[PATCH libdrm v3 3/5] xf86drm: Add platform and host1x bus support
walter harms
wharms at bfs.de
Wed Jan 18 15:00:20 UTC 2017
Am 18.01.2017 10:02, schrieb Thierry Reding:
> From: Thierry Reding <treding at nvidia.com>
>
> ARM SoCs usually have their DRM/KMS devices on the platform bus, so add
> support for that to enable these devices to be used with the drmDevice
> infrastructure.
>
> NVIDIA Tegra SoCs have an additional level in the hierarchy and DRM/KMS
> devices can also be on the host1x bus. This is mostly equivalent to the
> platform bus.
>
> v3:
> - guard Linux-specific sysfs parsing code with #ifdef __linux__
>
> v2:
> - be careful not to overflow the full name
> - read compatible strings into device info
>
> Signed-off-by: Thierry Reding <treding at nvidia.com>
> ---
> xf86drm.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> xf86drm.h | 30 ++++++-
> 2 files changed, 328 insertions(+), 2 deletions(-)
>
> diff --git a/xf86drm.c b/xf86drm.c
> index d83674e638c4..3c6ec1cc9e00 100644
> --- a/xf86drm.c
> +++ b/xf86drm.c
> @@ -2953,6 +2953,12 @@ static int drmParseSubsystemType(int maj, int min)
> if (strncmp(name, "/usb", 4) == 0)
> return DRM_BUS_USB;
>
> + if (strncmp(name, "/platform", 9) == 0)
> + return DRM_BUS_PLATFORM;
> +
> + if (strncmp(name, "/host1x", 7) == 0)
> + return DRM_BUS_HOST1X;
> +
> return -EINVAL;
> #elif defined(__OpenBSD__)
> return DRM_BUS_PCI;
> @@ -3043,6 +3049,12 @@ static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b)
> case DRM_BUS_USB:
> return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo));
>
> + case DRM_BUS_PLATFORM:
> + return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo));
> +
> + case DRM_BUS_HOST1X:
> + return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo));
> +
> default:
> break;
> }
> @@ -3187,11 +3199,55 @@ static int drmParsePciDeviceInfo(int maj, int min,
> #endif
> }
>
> +static void drmFreePlatformDevice(drmDevicePtr device)
> +{
> + if (device->deviceinfo.platform) {
to save 2 indent level and improve readability :
if (! device->deviceinfo.platform ||
! device->deviceinfo.platform->compatible)
return;
> + if (device->deviceinfo.platform->compatible) {
> + char **compatible = device->deviceinfo.platform->compatible;
> +
> + while (*compatible) {
> + free(*compatible);
> + compatible++;
> + }
> +
> + free(device->deviceinfo.platform->compatible);
> + }
> + }
> +}
> +
> +static void drmFreeHost1xDevice(drmDevicePtr device)
> +{
> + if (device->deviceinfo.host1x) {
> + if (device->deviceinfo.host1x->compatible) {
> + char **compatible = device->deviceinfo.host1x->compatible;
> +
> + while (*compatible) {
> + free(*compatible);
> + compatible++;
> + }
> +
> + free(device->deviceinfo.host1x->compatible);
> + }
> + }
> +}
> +
> void drmFreeDevice(drmDevicePtr *device)
> {
> if (device == NULL)
> return;
>
> + if (*device) {
> + switch ((*device)->bustype) {
> + case DRM_BUS_PLATFORM:
> + drmFreePlatformDevice(*device);
> + break;
> +
> + case DRM_BUS_HOST1X:
> + drmFreeHost1xDevice(*device);
> + break;
> + }
> + }
> +
> free(*device);
> *device = NULL;
> }
> @@ -3393,6 +3449,220 @@ free_device:
> return ret;
> }
>
> +static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info)
> +{
> +#ifdef __linux__
> + char path[PATH_MAX + 1], *name;
> +
> + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
> +
> + name = sysfs_uevent_get(path, "OF_FULLNAME");
> + if (!name)
> + return -ENOENT;
> +
> + strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN);
> + info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
> + free(name);
> +
> + return 0;
> +#else
> +#warning "Missing implementation of drmParsePlatformBusInfo"
> + return -EINVAL;
> +#endif
> +}
> +
> +static int drmParsePlatformDeviceInfo(int maj, int min,
> + drmPlatformDeviceInfoPtr info)
> +{
> +#ifdef __linux__
> + char path[PATH_MAX + 1], *value;
> + unsigned int count, i;
> + int err;
> +
> + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
> +
> + value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
> + if (!value)
> + return -ENOENT;
> +
> + sscanf(value, "%u", &count);
> + free(value);
> +
> + info->compatible = calloc(count + 1, sizeof(*info->compatible));
> + if (!info->compatible)
> + return -ENOMEM;
> +
> + for (i = 0; i < count; i++) {
> + value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
> + if (!value) {
> + err = -ENOENT;
> + goto free;
> + }
> +
> + info->compatible[i] = value;
> + }
> +
> + return 0;
> +
> +free:
> + while (i--)
> + free(info->compatible[i]);
> +
> + free(info->compatible);
> + return err;
> +#else
> +#warning "Missing implementation of drmParsePlatformDeviceInfo"
> + return -EINVAL;
> +#endif
> +}
> +
> +static int drmProcessPlatformDevice(drmDevicePtr *device,
> + const char *node, int node_type,
> + int maj, int min, bool fetch_deviceinfo,
> + uint32_t flags)
> +{
> + drmDevicePtr dev;
> + char *ptr;
> + int ret;
> +
> + dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
> + sizeof(drmPlatformDeviceInfo), &ptr);
> + if (!dev)
> + return -ENOMEM;
> +
> + dev->bustype = DRM_BUS_PLATFORM;
> +
> + dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
> +
> + ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform);
> + if (ret < 0)
> + goto free_device;
> +
> + if (fetch_deviceinfo) {
> + ptr += sizeof(drmPlatformBusInfo);
> + dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
> +
> + ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform);
> + if (ret < 0)
> + goto free_device;
> + }
> +
> + *device = dev;
> +
> + return 0;
> +
> +free_device:
> + free(dev);
> + return ret;
> +}
> +
> +static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info)
> +{
> +#ifdef __linux__
> + char path[PATH_MAX + 1], *name;
> +
> + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
> +
> + name = sysfs_uevent_get(path, "OF_FULLNAME");
> + if (!name)
> + return -ENOENT;
> +
> + strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN);
> + info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0';
> + free(name);
> +
> + return 0;
> +#else
> +#warning "Missing implementation of drmParseHost1xBusInfo"
> + return -EINVAL;
> +#endif
> +}
> +
> +static int drmParseHost1xDeviceInfo(int maj, int min,
> + drmHost1xDeviceInfoPtr info)
> +{
> +#ifdef __linux__
> + char path[PATH_MAX + 1], *value;
> + unsigned int count, i;
> + int err;
> +
> + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
> +
> + value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
> + if (!value)
> + return -ENOENT;
> +
> + sscanf(value, "%u", &count);
> + free(value);
> +
> + info->compatible = calloc(count + 1, sizeof(*info->compatible));
> + if (!info->compatible)
> + return -ENOMEM;
> +
> + for (i = 0; i < count; i++) {
> + value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
> + if (!value) {
> + err = -ENOENT;
> + goto free;
> + }
> +
> + info->compatible[i] = value;
> + }
> +
> + return 0;
> +
> +free:
> + while (i--)
> + free(info->compatible[i]);
> +
> + free(info->compatible);
> + return err;
> +#else
> +#warning "Missing implementation of drmParseHost1xDeviceInfo"
> + return -EINVAL;
> +#endif
> +}
> +
> +static int drmProcessHost1xDevice(drmDevicePtr *device,
> + const char *node, int node_type,
> + int maj, int min, bool fetch_deviceinfo,
> + uint32_t flags)
> +{
> + drmDevicePtr dev;
> + char *ptr;
> + int ret;
> +
> + dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
> + sizeof(drmHost1xDeviceInfo), &ptr);
> + if (!dev)
> + return -ENOMEM;
> +
> + dev->bustype = DRM_BUS_HOST1X;
> +
> + dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
> +
> + ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x);
> + if (ret < 0)
> + goto free_device;
> +
> + if (fetch_deviceinfo) {
> + ptr += sizeof(drmHost1xBusInfo);
> + dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
> +
> + ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x);
> + if (ret < 0)
> + goto free_device;
> + }
> +
> + *device = dev;
> +
do you assume that fetch_deviceinfo may change dev ?
re,
wh
> + return 0;
> +
> +free_device:
> + free(dev);
> + return ret;
> +}
> +
> /* Consider devices located on the same bus as duplicate and fold the respective
> * entries into a single one.
> *
> @@ -3576,6 +3846,20 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
>
> break;
>
> + case DRM_BUS_PLATFORM:
> + ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags);
> + if (ret)
> + goto free_devices;
> +
> + break;
> +
> + case DRM_BUS_HOST1X:
> + ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags);
> + if (ret)
> + goto free_devices;
> +
> + break;
> +
> default:
> continue;
> }
> @@ -3716,6 +4000,22 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices)
>
> break;
>
> + case DRM_BUS_PLATFORM:
> + ret = drmProcessPlatformDevice(&device, node, node_type, maj, min,
> + devices != NULL, flags);
> + if (ret)
> + goto free_devices;
> +
> + break;
> +
> + case DRM_BUS_HOST1X:
> + ret = drmProcessHost1xDevice(&device, node, node_type, maj, min,
> + devices != NULL, flags);
> + if (ret)
> + goto free_devices;
> +
> + break;
> +
> default:
> continue;
> }
> diff --git a/xf86drm.h b/xf86drm.h
> index 65d5321950fc..0d927018f1f7 100644
> --- a/xf86drm.h
> +++ b/xf86drm.h
> @@ -766,8 +766,10 @@ extern int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle);
> extern char *drmGetPrimaryDeviceNameFromFd(int fd);
> extern char *drmGetRenderDeviceNameFromFd(int fd);
>
> -#define DRM_BUS_PCI 0
> -#define DRM_BUS_USB 1
> +#define DRM_BUS_PCI 0
> +#define DRM_BUS_USB 1
> +#define DRM_BUS_PLATFORM 2
> +#define DRM_BUS_HOST1X 3
>
> typedef struct _drmPciBusInfo {
> uint16_t domain;
> @@ -794,6 +796,26 @@ typedef struct _drmUsbDeviceInfo {
> uint16_t product;
> } drmUsbDeviceInfo, *drmUsbDeviceInfoPtr;
>
> +#define DRM_PLATFORM_DEVICE_NAME_LEN 512
> +
> +typedef struct _drmPlatformBusInfo {
> + char fullname[DRM_PLATFORM_DEVICE_NAME_LEN];
> +} drmPlatformBusInfo, *drmPlatformBusInfoPtr;
> +
> +typedef struct _drmPlatformDeviceInfo {
> + char **compatible; /* NULL terminated list of compatible strings */
> +} drmPlatformDeviceInfo, *drmPlatformDeviceInfoPtr;
> +
> +#define DRM_HOST1X_DEVICE_NAME_LEN 512
> +
> +typedef struct _drmHost1xBusInfo {
> + char fullname[DRM_HOST1X_DEVICE_NAME_LEN];
> +} drmHost1xBusInfo, *drmHost1xBusInfoPtr;
> +
> +typedef struct _drmHost1xDeviceInfo {
> + char **compatible; /* NULL terminated list of compatible strings */
> +} drmHost1xDeviceInfo, *drmHost1xDeviceInfoPtr;
> +
> typedef struct _drmDevice {
> char **nodes; /* DRM_NODE_MAX sized array */
> int available_nodes; /* DRM_NODE_* bitmask */
> @@ -801,10 +823,14 @@ typedef struct _drmDevice {
> union {
> drmPciBusInfoPtr pci;
> drmUsbBusInfoPtr usb;
> + drmPlatformBusInfoPtr platform;
> + drmHost1xBusInfoPtr host1x;
> } businfo;
> union {
> drmPciDeviceInfoPtr pci;
> drmUsbDeviceInfoPtr usb;
> + drmPlatformDeviceInfoPtr platform;
> + drmHost1xDeviceInfoPtr host1x;
> } deviceinfo;
> } drmDevice, *drmDevicePtr;
>
More information about the xorg-devel
mailing list