From: Daniel Vetter <daniel@ffwll.ch>
To: Jammy Zhou <Jammy.Zhou@amd.com>
Cc: Emil Velikov <emil.l.velikov@gmail.com>, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH 1/5] drm: add interface to get drm devices on the system v2
Date: Thu, 13 Aug 2015 17:07:55 +0200 [thread overview]
Message-ID: <20150813150755.GD17734@phenom.ffwll.local> (raw)
In-Reply-To: <1439436825-16908-2-git-send-email-Jammy.Zhou@amd.com>
On Thu, Aug 13, 2015 at 11:33:41AM +0800, Jammy Zhou wrote:
> From: Emil Velikov <emil.l.velikov@gmail.com>
>
> For mutiple GPU support, the devices on the system should be enumerated
> to get necessary information about each device, and the drmGetDevices
> interface is added for this. Currently only PCI devices are supported for
> the enumeration.
>
> Typical usage:
> int count;
> drmDevicePtr *foo;
> count = drmGetDevices(NULL, 0);
> foo = calloc(count, sizeof(drmDevicePtr));
> count = drmGetDevices(foo, count);
> /* find proper device, open correct device node, etc */
> drmFreeDevices(foo, count);
> free(foo);
>
> v2: change according to feedback from Emil
>
> Signed-off-by: Jammy Zhou <Jammy.Zhou@amd.com>
> ---
> xf86drm.c | 351 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> xf86drm.h | 34 ++++++
> 2 files changed, 385 insertions(+)
>
> diff --git a/xf86drm.c b/xf86drm.c
> index 5e02969..237663b 100644
> --- a/xf86drm.c
> +++ b/xf86drm.c
> @@ -55,6 +55,7 @@
> #ifdef HAVE_SYS_MKDEV_H
> # include <sys/mkdev.h> /* defines major(), minor(), and makedev() on Solaris */
> #endif
> +#include <math.h>
>
> /* Not all systems have MAP_FAILED defined */
> #ifndef MAP_FAILED
> @@ -2829,3 +2830,353 @@ char *drmGetRenderDeviceNameFromFd(int fd)
> {
> return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
> }
> +
> +#ifdef __linux__
> +static int drmParseSubsystemType(const char *str)
> +{
> + char link[PATH_MAX + 1] = "";
> + char *name;
> +
> + if (readlink(str, link, PATH_MAX) < 0)
> + return -EINVAL;
> +
> + name = strrchr(link, '/');
> + if (!name)
> + return -EINVAL;
> +
> + name++;
> +
> + if (strncmp(name, "pci", 3) == 0)
> + return DRM_BUS_PCI;
> +
> + return -EINVAL;
> +}
> +
> +static int drmParsePciBusInfo(const char *str, drmPciBusInfoPtr info)
> +{
> + int domain, bus, dev, func;
> + char *value;
> +
> + if (str == NULL)
> + return -EINVAL;
> +
> + value = strstr(str, "PCI_SLOT_NAME=");
> + if (value == NULL)
> + return -EINVAL;
> +
> + value += strlen("PCI_SLOT_NAME=");
> +
> + if (sscanf(value, "%04x:%02x:%02x.%1u",
> + &domain, &bus, &dev, &func) != 4)
> + return -EINVAL;
> +
> + info->domain = domain;
> + info->bus = bus;
> + info->dev = dev;
> + info->func = func;
> +
> + return 0;
> +}
> +
> +static int drmSameDevice(drmDevicePtr a, drmDevicePtr b)
> +{
> + if (a->bustype != b->bustype)
> + return 0;
> +
> + switch (a->bustype) {
> + case DRM_BUS_PCI:
> + if (memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0)
> + return 1;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int drmGetNodeType(const char *name)
> +{
> + if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
> + sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
> + return DRM_NODE_PRIMARY;
> +
> + if (strncmp(name, DRM_CONTROL_MINOR_NAME,
> + sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0)
> + return DRM_NODE_CONTROL;
> +
> + if (strncmp(name, DRM_RENDER_MINOR_NAME,
> + sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
> + return DRM_NODE_RENDER;
> +
> + return -EINVAL;
> +}
> +
> +static int drmParsePciDeviceInfo(const char *config,
> + drmPciDeviceInfoPtr device)
> +{
> + if (config == NULL)
> + return -EINVAL;
> +
> + device->vendor_id = config[0] | (config[1] << 8);
> + device->device_id = config[2] | (config[3] << 8);
> + device->revision_id = config[8];
> + device->subvendor_id = config[44] | (config[45] << 8);
> + device->subdevice_id = config[46] | (config[47] << 8);
Why not reuse libpciaccess?
-Daniel
> +
> + return 0;
> +}
> +
> +static void drmFreeDevice(drmDevicePtr device)
> +{
> + int i;
> +
> + if (device == NULL)
> + return;
> +
> + if (device->nodes != NULL)
> + for (i = 0; i < DRM_NODE_MAX; i++)
> + free(device->nodes[i]);
> +
> + free(device->nodes);
> + free(device->businfo.pci);
> + free(device->deviceinfo.pci);
> +}
> +
> +void drmFreeDevices(drmDevicePtr devices[], int count)
> +{
> + int i;
> +
> + if (devices == NULL)
> + return;
> +
> + for (i = 0; i < count; i++) {
> + drmFreeDevice(devices[i]);
> + free(devices[i]);
> + devices[i] = NULL;
> + }
> +}
> +
> +/**
> + * Get drm devices on the system
> + *
> + * \param devices the array of devices with drmDevicePtr elements
> + * can be NULL to get the device number first
> + * \param max_devices the maximum number of devices for the array
> + *
> + * \return on error - negative error code,
> + * if devices is NULL - total number of devices available on the system,
> + * alternatively the number of devices stored in devices[], which is
> + * capped by the max_devices.
> + */
> +int drmGetDevices(drmDevicePtr devices[], int max_devices)
> +{
> + drmDevicePtr devs = NULL;
> + drmPciBusInfoPtr pcibus = NULL;
> + drmPciDeviceInfoPtr pcidevice = NULL;
> + DIR *sysdir = NULL;
> + struct dirent *dent = NULL;
> + struct stat sbuf = {0};
> + char node[PATH_MAX + 1] = "";
> + char path[PATH_MAX + 1] = "";
> + char data[128] = "";
> + char config[64] = "";
> + int node_type, subsystem_type;
> + int maj, min;
> + int fd;
> + int ret, i = 0, j, node_count, device_count = 0;
> + int max_count = 16;
> + int *duplicated = NULL;
> +
> + devs = calloc(max_count, sizeof(*devs));
> + if (devs == NULL)
> + return -ENOMEM;
> +
> + sysdir = opendir(DRM_DIR_NAME);
> + if (!sysdir) {
> + ret = -errno;
> + goto free_locals;
> + }
> +
> + while ((dent = readdir(sysdir))) {
> + node_type = drmGetNodeType(dent->d_name);
> + if (node_type < 0)
> + continue;
> +
> + snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, dent->d_name);
> + if (stat(node, &sbuf))
> + continue;
> +
> + maj = major(sbuf.st_rdev);
> + min = minor(sbuf.st_rdev);
> +
> + if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode))
> + continue;
> +
> + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/subsystem",
> + maj, min);
> + subsystem_type = drmParseSubsystemType(path);
> +
> + if (subsystem_type < 0)
> + continue;
> +
> + switch (subsystem_type) {
> + case DRM_BUS_PCI:
> + pcibus = calloc(1, sizeof(*pcibus));
> + if (pcibus == NULL) {
> + ret = -ENOMEM;
> + goto free_locals;
> + }
> +
> + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent",
> + maj, min);
> + fd = open(path, O_RDONLY);
> + if (fd < 0) {
> + ret = -errno;
> + goto free_locals;
> + }
> + ret = read(fd, data, sizeof(data));
> + if (ret < 0) {
> + ret = -errno;
> + close(fd);
> + goto free_locals;
> + }
> +
> + ret = drmParsePciBusInfo(data, pcibus);
> + close(fd);
> + if (ret)
> + goto free_locals;
> +
> + if (i >= max_count) {
> + max_count += 16;
> + devs = realloc(devs, max_count * sizeof(*devs));
> + }
> +
> + devs[i].businfo.pci = pcibus;
> + devs[i].bustype = subsystem_type;
> + devs[i].nodes = calloc(DRM_NODE_MAX, sizeof(char *));
> + if (devs[i].nodes == NULL) {
> + ret = -ENOMEM;
> + goto free_locals;
> + }
> + devs[i].nodes[node_type] = strdup(node);
> + if (devs[i].nodes[node_type] == NULL) {
> + ret = -ENOMEM;
> + goto free_locals;
> + }
> + devs[i].available_nodes = 1 << node_type;
> +
> + if (devices != NULL) {
> + snprintf(path, PATH_MAX, "/sys/class/drm/%s/device/config",
> + dent->d_name);
> + fd = open(path, O_RDONLY);
> + if (fd < 0) {
> + ret = -errno;
> + goto free_locals;
> + }
> + ret = read(fd, config, 64);
> + if (ret < 0) {
> + ret = -errno;
> + close(fd);
> + goto free_locals;
> + }
> +
> + pcidevice = calloc(1, sizeof(*pcidevice));
> + if (pcidevice == NULL) {
> + ret = -ENOMEM;
> + goto free_locals;
> + }
> +
> + ret = drmParsePciDeviceInfo(config, pcidevice);
> + if (ret)
> + goto free_locals;
> +
> + devs[i].deviceinfo.pci = pcidevice;
> + close(fd);
> + }
> + break;
> + default:
> + fprintf(stderr, "The subsystem type is not supported yet\n");
> + break;
> + }
> + i++;
> + }
> +
> + node_count = i;
> +
> + /* merge duplicated devices with same domain/bus/device/func IDs */
> + duplicated = calloc(node_count, sizeof(*duplicated));
> + if (duplicated == NULL) {
> + ret = -ENOMEM;
> + goto free_locals;
> + }
> +
> + for (i = 0; i < node_count; i++) {
> + for (j = i+1; j < node_count; j++) {
> + if (duplicated[i] || duplicated[j])
> + continue;
> + if (drmSameDevice(&devs[i], &devs[j])) {
> + duplicated[j] = 1;
> + devs[i].available_nodes |= devs[j].available_nodes;
> + node_type = log2(devs[j].available_nodes);
> + devs[i].nodes[node_type] = devs[j].nodes[node_type];
> + free(devs[j].nodes);
> + free(devs[j].businfo.pci);
> + free(devs[j].deviceinfo.pci);
> + }
> + }
> + }
> +
> + for (i = 0; i < node_count; i++) {
> + if(duplicated[i] == 0) {
> + if ((devices != NULL) && (device_count < max_devices)) {
> + devices[device_count] = calloc(1, sizeof(drmDevice));
> + if (devices[device_count] == NULL) {
> + ret = -ENOMEM;
> + break;
> + }
> + memcpy(devices[device_count], &devs[i], sizeof(drmDevice));
> + } else
> + drmFreeDevice(&devs[i]);
> + device_count++;
> + }
> + }
> +
> + if (i < node_count) {
> + drmFreeDevices(devices, device_count);
> + for ( ; i < node_count; i++)
> + if(duplicated[i] == 0)
> + drmFreeDevice(&devs[i]);
> + } else
> + ret = device_count;
> +
> + free(duplicated);
> + free(devs);
> + closedir(sysdir);
> + return ret;
> +
> +free_locals:
> + for (j = 0; j < i; j++)
> + drmFreeDevice(&devs[j]);
> + free(pcidevice);
> + free(pcibus);
> + free(devs);
> + closedir(sysdir);
> + return ret;
> +}
> +#else
> +void drmFreeDevices(drmDevicePtr devices[], int count)
> +{
> + (void)devices;
> + (void)count;
> +}
> +
> +int drmGetDevices(drmDevicePtr devices[], int max_devices)
> +{
> + (void)devices;
> + (void)max_devices;
> + return -EINVAL;
> +}
> +
> +#warning "Missing implementation of drmGetDevices/drmFreeDevices"
> +
> +#endif
> diff --git a/xf86drm.h b/xf86drm.h
> index 360e04a..e82ca84 100644
> --- a/xf86drm.h
> +++ b/xf86drm.h
> @@ -563,6 +563,8 @@ extern int drmOpen(const char *name, const char *busid);
> #define DRM_NODE_PRIMARY 0
> #define DRM_NODE_CONTROL 1
> #define DRM_NODE_RENDER 2
> +#define DRM_NODE_MAX 3
> +
> extern int drmOpenWithType(const char *name, const char *busid,
> int type);
>
> @@ -759,6 +761,38 @@ 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
> +
> +typedef struct _drmPciBusInfo {
> + uint16_t domain;
> + uint8_t bus;
> + uint8_t dev;
> + uint8_t func;
> +} drmPciBusInfo, *drmPciBusInfoPtr;
> +
> +typedef struct _drmPciDeviceInfo {
> + uint16_t vendor_id;
> + uint16_t device_id;
> + uint16_t subvendor_id;
> + uint16_t subdevice_id;
> + uint8_t revision_id;
> +} drmPciDeviceInfo, *drmPciDeviceInfoPtr;
> +
> +typedef struct _drmDevice {
> + char **nodes; /* DRM_NODE_MAX sized array */
> + int available_nodes; /* DRM_NODE_* bitmask */
> + int bustype;
> + union {
> + drmPciBusInfoPtr pci;
> + } businfo;
> + union {
> + drmPciDeviceInfoPtr pci;
> + } deviceinfo;
> +} drmDevice, *drmDevicePtr;
> +
> +extern int drmGetDevices(drmDevicePtr devices[], int max_devices);
> +extern void drmFreeDevices(drmDevicePtr devices[], int count);
> +
> #if defined(__cplusplus)
> }
> #endif
> --
> 1.9.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
next prev parent reply other threads:[~2015-08-13 15:07 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-13 3:33 [PATCH 0/5] some drm and amdgpu patches Jammy Zhou
2015-08-13 3:33 ` [PATCH 1/5] drm: add interface to get drm devices on the system v2 Jammy Zhou
2015-08-13 13:58 ` Emil Velikov
2015-08-14 5:53 ` Zhou, Jammy
2015-08-14 8:35 ` Emil Velikov
2015-08-14 9:41 ` Zhou, Jammy
2015-08-14 10:05 ` Emil Velikov
2015-08-14 12:15 ` Zhou, Jammy
2015-08-14 12:28 ` Emil Velikov
2015-08-14 12:45 ` Zhou, Jammy
2015-08-14 13:19 ` Emil Velikov
2015-08-14 13:43 ` Zhou, Jammy
2015-08-13 15:07 ` Daniel Vetter [this message]
2015-08-13 15:26 ` Emil Velikov
2015-08-14 5:59 ` Zhou, Jammy
2015-08-14 7:59 ` Kai Wasserbäch
2015-08-14 8:17 ` Emil Velikov
2015-08-14 8:26 ` Kai Wasserbäch
2015-08-14 9:07 ` Emil Velikov
2015-08-14 9:48 ` Zhou, Jammy
2015-08-13 3:33 ` [PATCH 2/5] amdgpu: improve amdgpu_vamgr_init Jammy Zhou
2015-08-13 3:33 ` [PATCH 3/5] amdgpu: add flag to support 32bit VA address v3 Jammy Zhou
2015-08-13 3:33 ` [PATCH 4/5] amdgpu: fix one warning from previous commit Jammy Zhou
2015-08-13 3:33 ` [PATCH 5/5] amdgpu: make vamgr per device v2 Jammy Zhou
2015-08-13 6:19 ` [PATCH 0/5] some drm and amdgpu patches Michel Dänzer
2015-08-14 5:47 ` Zhou, Jammy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150813150755.GD17734@phenom.ffwll.local \
--to=daniel@ffwll.ch \
--cc=Jammy.Zhou@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=emil.l.velikov@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.