diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c index b1d196c..0cc6741 100644 --- a/src/linux_sysfs.c +++ b/src/linux_sysfs.c @@ -484,6 +484,40 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data, return err; } +static int +pci_device_linux_sysfs_map_range_wc(struct pci_device *dev, + struct pci_device_mapping *map) +{ + char name[256]; + int fd; + const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + ? (PROT_READ | PROT_WRITE) : PROT_READ; + const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) + ? O_RDWR : O_RDONLY; + const off_t offset = map->base - dev->regions[map->region].base_addr; + + snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u_wc", + SYS_BUS_PCI, + dev->domain, + dev->bus, + dev->dev, + dev->func, + map->region); + fd = open(name, open_flags); + if (fd == -1) + return errno; + + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); + if (map->memory == MAP_FAILED) { + map->memory = NULL; + close(fd); + return errno; + } + + close(fd); + + return 0; +} /** * Map a memory region for a device using the Linux sysfs interface. @@ -521,6 +555,11 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev, }; #endif + /* For WC mappings, try sysfs resourceN_wc file first */ + if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) && + !pci_device_linux_sysfs_map_range_wc(dev, map)) + return 0; + snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u", SYS_BUS_PCI, dev->domain,