From b12884336e699d2a994cfdd146c05891a14f46fd Mon Sep 17 00:00:00 2001 From: Vasilis Liaskovitis Date: Fri, 20 Jul 2018 15:05:52 +0200 Subject: [PATCH libdrm] xf86drm: Correctly parse pci device information for virtio gpu Running glxinfo / glxgears when using virgl / virtio_gpu in a qemu VM results in the following message: libGL error: MESA-LOADER: failed to retrieve device information drmParseSubsystemType() expects /sys/dev/char/DRM_MAJOR\:0/device/subsystem to be one of: pci, usb, platform, hostix . But virtio-gpu has bus subsystem virtio, resulting in -EINVAL returned as a subsystem, and drmGetDevice2() returning -ENODEV. However the virtio-gpu device is actually a pci device e.g. : /sys/dev/char/226:0 -> ../../devices/pci0000:00/0000:00:02.0/virtio0/drm/card0 So for virtio devices: - introduce DRM_BUS_VIRTIO to parse the initial drm device subsystem. - use /sys/dev/char/226:0/../../../ to parse the final subsystem, pci bus and device information, instead of /sys/dev/char/226:0. The device will be registered as a normal PCI device. --- xf86drm.c | 64 +++++++++++++++++++++++++++++++++++++++++-------------- xf86drm.h | 1 + 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/xf86drm.c b/xf86drm.c index 87c216cf..de4f3896 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -2983,6 +2983,9 @@ static int drmParseSubsystemType(int maj, int min) if (strncmp(name, "/host1x", 7) == 0) return DRM_BUS_HOST1X; + if (strncmp(name, "/virtio", 7) == 0) + return DRM_BUS_VIRTIO; + return -EINVAL; #elif defined(__OpenBSD__) return DRM_BUS_PCI; @@ -2992,14 +2995,17 @@ static int drmParseSubsystemType(int maj, int min) #endif } -static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) +static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info, bool is_virtio) { #ifdef __linux__ unsigned int domain, bus, dev, func; char path[PATH_MAX + 1], *value; int num; - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + if (!is_virtio) + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + else + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/../../..", maj, min); value = sysfs_uevent_get(path, "PCI_SLOT_NAME"); if (!value) @@ -3057,6 +3063,7 @@ int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) switch (a->bustype) { case DRM_BUS_PCI: + case DRM_BUS_VIRTIO: return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; case DRM_BUS_USB: @@ -3104,7 +3111,8 @@ static int drmGetMaxNodeName(void) #ifdef __linux__ static int parse_separate_sysfs_files(int maj, int min, drmPciDeviceInfoPtr device, - bool ignore_revision) + bool ignore_revision, + bool is_virtio) { #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static const char *attrs[] = { @@ -3120,7 +3128,11 @@ static int parse_separate_sysfs_files(int maj, int min, int ret; for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { - snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min, + if (!is_virtio) + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min, + attrs[i]); + else + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/../../../%s", maj, min, attrs[i]); fp = fopen(path, "r"); if (!fp) @@ -3143,13 +3155,17 @@ static int parse_separate_sysfs_files(int maj, int min, } static int parse_config_sysfs_file(int maj, int min, - drmPciDeviceInfoPtr device) + drmPciDeviceInfoPtr device, + bool is_virtio) { char path[PATH_MAX + 1]; unsigned char config[64]; int fd, ret; - snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min); + if (!is_virtio) + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/config", maj, min); + else + snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/../../../config", maj, min); fd = open(path, O_RDONLY); if (fd < 0) return -errno; @@ -3171,14 +3187,15 @@ static int parse_config_sysfs_file(int maj, int min, static int drmParsePciDeviceInfo(int maj, int min, drmPciDeviceInfoPtr device, - uint32_t flags) + uint32_t flags, + bool is_virtio) { #ifdef __linux__ if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) - return parse_separate_sysfs_files(maj, min, device, true); + return parse_separate_sysfs_files(maj, min, device, true, is_virtio); - if (parse_separate_sysfs_files(maj, min, device, false)) - return parse_config_sysfs_file(maj, min, device); + if (parse_separate_sysfs_files(maj, min, device, false, is_virtio)) + return parse_config_sysfs_file(maj, min, device, is_virtio); return 0; #elif defined(__OpenBSD__) @@ -3317,7 +3334,7 @@ static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, static int drmProcessPciDevice(drmDevicePtr *device, const char *node, int node_type, int maj, int min, bool fetch_deviceinfo, - uint32_t flags) + uint32_t flags, bool is_virtio) { drmDevicePtr dev; char *addr; @@ -3332,7 +3349,7 @@ static int drmProcessPciDevice(drmDevicePtr *device, dev->businfo.pci = (drmPciBusInfoPtr)addr; - ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); + ret = drmParsePciBusInfo(maj, min, dev->businfo.pci, is_virtio); if (ret) goto free_device; @@ -3341,7 +3358,7 @@ static int drmProcessPciDevice(drmDevicePtr *device, addr += sizeof(drmPciBusInfo); dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; - ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); + ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags, is_virtio); if (ret) goto free_device; } @@ -3841,15 +3858,15 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) continue; + if (drmParseSubsystemType(maj, min) != subsystem_type) continue; switch (subsystem_type) { case DRM_BUS_PCI: - ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); + ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags, false); if (ret) continue; - break; case DRM_BUS_USB: @@ -3873,6 +3890,13 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) break; + case DRM_BUS_VIRTIO: + ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags, true); + if (ret) + continue; + + break; + default: continue; } @@ -3999,7 +4023,7 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices) switch (subsystem_type) { case DRM_BUS_PCI: ret = drmProcessPciDevice(&device, node, node_type, - maj, min, devices != NULL, flags); + maj, min, devices != NULL, flags, false); if (ret) continue; @@ -4029,6 +4053,14 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices) break; + case DRM_BUS_VIRTIO: + ret = drmProcessPciDevice(&device, node, node_type, + maj, min, devices != NULL, flags, true); + if (ret) + continue; + + break; + default: continue; } diff --git a/xf86drm.h b/xf86drm.h index 7773d71a..d1c5ef0b 100644 --- a/xf86drm.h +++ b/xf86drm.h @@ -787,6 +787,7 @@ extern char *drmGetRenderDeviceNameFromFd(int fd); #define DRM_BUS_USB 1 #define DRM_BUS_PLATFORM 2 #define DRM_BUS_HOST1X 3 +#define DRM_BUS_VIRTIO 4 typedef struct _drmPciBusInfo { uint16_t domain; -- 2.17.0