diff --git a/src/common_map.c b/src/common_map.c index 8757151..68044cd 100644 --- a/src/common_map.c +++ b/src/common_map.c @@ -51,5 +51,11 @@ _pci_hidden int pci_device_generic_unmap_range(struct pci_device *dev, struct pci_device_mapping *map) { +#ifdef __alpha__ + if (map->pre_bwx && map->memory_sparse) { + munmap(map->memory_sparse, map->size**(1<<5)); + } +#endif + return (munmap(map->memory, map->size) == -1) ? errno : 0; } diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c index 1832ee7..e24de74 100644 --- a/src/linux_sysfs.c +++ b/src/linux_sysfs.c @@ -548,10 +548,28 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev, map->region); fd = open(name, open_flags); + +#ifdef __alpha__ + map->pre_bwx = 0; if (fd == -1) { - return errno; + /* Attempt to map resourceX_dense which exists on non-BWX Alphas. */ + snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u_dense", + SYS_BUS_PCI, + dev->domain, + dev->bus, + dev->dev, + dev->func, + map->region); + fd = open(name, open_flags); + if (fd != -1) { + map->pre_bwx = 1; + } } +#endif + if (fd == -1) { + return errno; + } map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); if (map->memory == MAP_FAILED) { @@ -597,6 +615,45 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev, } #endif +#ifdef __alpha__ + if (map->pre_bwx && dev->regions[map->region].is_IO) { + /* Also map sparse mapping for IO. + * This map is only needed for byte or word read/writes, but we + * don't know what the calling routine intends to do so we always + * map sparse. + */ + close(fd); + + snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u_sparse", + SYS_BUS_PCI, + dev->domain, + dev->bus, + dev->dev, + dev->func, + map->region); + fd = open(name, open_flags); + if (fd == -1) { + /* We fail -- any attempt at a byte or word access to the dense + * mapping by the caller will result in a bus error. + */ + int saved_errno = errno; + map->memory_sparse = NULL; + pci_device_generic_unmap_range(dev, map); + return saved_errno; + } + + map->memory_sparse = mmap(NULL, map->size*(1<<5), prot, + MAP_SHARED, fd, offset*(1<<5)); + if (map->memory_sparse == MAP_FAILED) { + int saved_errno = errno; + map->memory_sparse = NULL; + pci_device_generic_unmap_range(dev, map); + close(fd); + return saved_errno; + } + } +#endif + close(fd); return 0; diff --git a/src/pciaccess_private.h b/src/pciaccess_private.h index 77eb57b..e0828f6 100644 --- a/src/pciaccess_private.h +++ b/src/pciaccess_private.h @@ -85,6 +85,10 @@ struct pci_device_mapping { unsigned region; unsigned flags; void *memory; +#ifdef __alpha__ + void *memory_sparse; + int pre_bwx; +#endif }; struct pci_io_handle {