aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Velikov2016-11-01 13:04:06 -0500
committerEmil Velikov2016-12-05 11:21:23 -0600
commitaae3f318d5aca81b87a14360116bb766a51e82ef (patch)
tree4f656c0f082c7589a3cdea96815b4030db1c24c3 /xf86drm.c
parent138d23117c6b96f57aaa0072992e0480153cfebd (diff)
downloadexternal-libgbm-aae3f318d5aca81b87a14360116bb766a51e82ef.tar.gz
external-libgbm-aae3f318d5aca81b87a14360116bb766a51e82ef.tar.xz
external-libgbm-aae3f318d5aca81b87a14360116bb766a51e82ef.zip
xf86drm: parse the separate sysfs files for vendor... info
Up-to recently (patch should land in 4.10) the kernel did not expose the PCI device revision field as a separate sysfs file. Thus one needed too parse the config file to retrieve it. This in itself wakes up the device, which in some cases can be quite slow. To avoid that, just check for the separate files and fall-back to the original if kernel is not new enough. v3: rework alongside drmGetDevice[s]2 Cc: Michel Dänzer <michel@daenzer.net> Cc: Nicolai Hähnle <nhaehnle@gmail.com> Cc: Mauro Santos <registo.mailling@gmail.com> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98502 Signed-off-by: Emil Velikov <emil.velikov@collabora.com> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com>
Diffstat (limited to 'xf86drm.c')
-rw-r--r--xf86drm.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/xf86drm.c b/xf86drm.c
index ddb8f9f7..701cf291 100644
--- a/xf86drm.c
+++ b/xf86drm.c
@@ -2946,11 +2946,49 @@ static int drmGetMaxNodeName(void)
2946 3 /* length of the node number */; 2946 3 /* length of the node number */;
2947} 2947}
2948 2948
2949static int drmParsePciDeviceInfo(int maj, int min,
2950 drmPciDeviceInfoPtr device,
2951 uint32_t flags)
2952{
2953#ifdef __linux__ 2949#ifdef __linux__
2950static int parse_separate_sysfs_files(int maj, int min,
2951 drmPciDeviceInfoPtr device)
2952{
2953#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
2954 static const char *attrs[] = {
2955 "revision", /* Older kernels are missing the file, so check for it first */
2956 "vendor",
2957 "device",
2958 "subsystem_vendor",
2959 "subsystem_device",
2960 };
2961 char path[PATH_MAX + 1];
2962 unsigned int data[ARRAY_SIZE(attrs)];
2963 FILE *fp;
2964 int ret;
2965
2966 for (unsigned i = 0; i < ARRAY_SIZE(attrs); i++) {
2967 snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/%s", maj, min,
2968 attrs[i]);
2969 fp = fopen(path, "r");
2970 if (!fp)
2971 return -errno;
2972
2973 ret = fscanf(fp, "%x", &data[i]);
2974 fclose(fp);
2975 if (ret != 1)
2976 return -errno;
2977
2978 }
2979
2980 device->revision_id = data[0] & 0xff;
2981 device->vendor_id = data[1] & 0xffff;
2982 device->device_id = data[2] & 0xffff;
2983 device->subvendor_id = data[3] & 0xffff;
2984 device->subdevice_id = data[4] & 0xffff;
2985
2986 return 0;
2987}
2988
2989static int parse_config_sysfs_file(int maj, int min,
2990 drmPciDeviceInfoPtr device)
2991{
2954 char path[PATH_MAX + 1]; 2992 char path[PATH_MAX + 1];
2955 unsigned char config[64]; 2993 unsigned char config[64];
2956 int fd, ret; 2994 int fd, ret;
@@ -2972,6 +3010,18 @@ static int drmParsePciDeviceInfo(int maj, int min,
2972 device->subdevice_id = config[46] | (config[47] << 8); 3010 device->subdevice_id = config[46] | (config[47] << 8);
2973 3011
2974 return 0; 3012 return 0;
3013}
3014#endif
3015
3016static int drmParsePciDeviceInfo(int maj, int min,
3017 drmPciDeviceInfoPtr device,
3018 uint32_t flags)
3019{
3020#ifdef __linux__
3021 if (parse_separate_sysfs_files(maj, min, device))
3022 return parse_config_sysfs_file(maj, min, device);
3023
3024 return 0;
2975#else 3025#else
2976#warning "Missing implementation of drmParsePciDeviceInfo" 3026#warning "Missing implementation of drmParsePciDeviceInfo"
2977 return -EINVAL; 3027 return -EINVAL;