summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmil Velikov <emil.velikov@collabora.com>2016-12-01 18:17:35 +0000
committerAdam Jackson <ajax@redhat.com>2017-01-11 10:48:26 -0500
commit73db249c4b1eb91e0df27a1045bea344371dd2ca (patch)
tree2d482ba21c40b8c5670d4eaf17a47faeecda4a5e
parent099489b7917da44de57f3214425ea9b4a8f36482 (diff)
linux sysfs: retrieve vendor, device... info via separate sysfs files
Currently the kernel does not expose the revision file. With that about to change (due in 4.10) we can read all the information required from separate files and avoid opening the config one. The latter has the [negative] side effect of waking up the device, which in some cases can be quite costly. Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
-rw-r--r--src/linux_sysfs.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c
index cd2713d..8055e8d 100644
--- a/src/linux_sysfs.c
+++ b/src/linux_sysfs.c
@@ -146,6 +146,56 @@ scan_sys_pci_filter( const struct dirent * d )
}
+static int
+parse_separate_sysfs_files(struct pci_device * dev)
+{
+ static const char *attrs[] = {
+ "vendor",
+ "device",
+ "class",
+ "revision",
+ "subsystem_vendor",
+ "subsystem_device",
+ };
+ char name[256];
+ char resource[512];
+ uint64_t data[6];
+ int fd;
+ int i;
+
+ for (i = 0; i < 6; i++) {
+ snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/%s",
+ SYS_BUS_PCI,
+ dev->domain,
+ dev->bus,
+ dev->dev,
+ dev->func,
+ attrs[i]);
+
+ fd = open(name, O_RDONLY | O_CLOEXEC);
+ if (fd == -1) {
+ return errno;
+ }
+
+ read(fd, resource, 512);
+ resource[511] = '\0';
+
+ close(fd);
+
+ data[i] = strtoull(resource, NULL, 16);
+ }
+
+ dev->vendor_id = data[0] & 0xffff;
+ dev->device_id = data[1] & 0xffff;
+ dev->device_class = data[2] & 0xffffff;
+ dev->revision = data[3] & 0xff;
+ dev->subvendor_id = data[4] & 0xffff;
+ dev->subdevice_id = data[5] & 0xffff;
+
+ return 0;
+}
+
+
int
populate_entries( struct pci_system * p )
{
@@ -178,6 +228,10 @@ populate_entries( struct pci_system * p )
device->base.func = func;
+ err = parse_separate_sysfs_files(& device->base);
+ if (!err)
+ continue;
+
err = pci_device_linux_sysfs_read(& device->base, config, 0,
48, & bytes);
if ((bytes == 48) && !err) {