[PATCH libpciaccess] linux: support 32 bit PCI domains (v2)
Adam Jackson
ajax at redhat.com
Thu Sep 7 18:50:13 UTC 2017
From: Stephen Hemminger <stephen at networkplumber.org>
The PCI domain may be larger than 16 bits on Microsoft Azure and other
virtual environments. PCI busses reported by ACPI are limited to 16
bits, but in Azure the domain value for pass through devices is
intentionally larger than 16 bits to avoid clashing with local devices.
This is needed to support pass through of GPU devices.
v2: (ajax)
Rename fields as domain_{16,32} to force consumers to adapt when built
against the new library. Update FreeBSD and Solaris backends to preserve
the full 32-bit domain number, since on those OSes it stands a chance of
working already. Update NetBSD and OpenBSD backends to initialize
domain_16 compatibly with older libpciaccess; neither backend appears to
support more than a handful of domains to begin with though. Trivially
update the generic x86 backend for source compatibility, though it still
only supports one domain and will never be better.
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=101744
Signed-off-by: Stephen Hemminger <sthemmin at microsoft.com>
---
include/pciaccess.h | 15 ++++++++++++++-
scanpci/scanpci.c | 4 ++--
src/common_bridge.c | 2 +-
src/common_iterator.c | 2 +-
src/common_vgaarb.c | 2 +-
src/freebsd_pci.c | 8 ++++----
src/linux_sysfs.c | 53 +++++++++++++++++++++++++--------------------------
src/netbsd_pci.c | 30 ++++++++++++++++-------------
src/openbsd_pci.c | 10 +++++++---
src/solx_devfs.c | 15 ++++++++++-----
src/x86_pci.c | 2 +-
11 files changed, 84 insertions(+), 59 deletions(-)
diff --git a/include/pciaccess.h b/include/pciaccess.h
index 1d7aa4b..497c58b 100644
--- a/include/pciaccess.h
+++ b/include/pciaccess.h
@@ -311,6 +311,10 @@ struct pci_mem_region {
* PCI device.
*
* Contains all of the information about a particular PCI device.
+ *
+ * This structure - like everything else in libpciaccess - is allocated
+ * by the library itself. Do not embed this structure in other structs,
+ * or otherwise allocate them yourself.
*/
struct pci_device {
/**
@@ -319,9 +323,12 @@ struct pci_device {
* Complete bus identification, including domain, of the device. On
* platforms that do not support PCI domains (e.g., 32-bit x86 hardware),
* the domain will always be zero.
+ *
+ * The domain_16 field is provided for binary compatibility with older
+ * libpciaccess. New code should use domain_32 instead.
*/
/*@{*/
- uint16_t domain;
+ uint16_t domain_16;
uint8_t bus;
uint8_t dev;
uint8_t func;
@@ -385,6 +392,12 @@ struct pci_device {
* Used by the VGA arbiter. Type of resource decoded by the device and
* the file descriptor (/dev/vga_arbiter). */
int vgaarb_rsrc;
+
+
+ /**
+ * PCI domain value (full 32 bits)
+ */
+ uint32_t domain_32;
};
diff --git a/scanpci/scanpci.c b/scanpci/scanpci.c
index 2f86833..f61e9f5 100644
--- a/scanpci/scanpci.c
+++ b/scanpci/scanpci.c
@@ -83,8 +83,8 @@ print_pci_device( struct pci_device * dev, int verbose )
}
printf("\npci ");
- if (dev->domain != 0)
- printf("domain 0x%04x ", dev->domain);
+ if (dev->domain_32 != 0)
+ printf("domain 0x%04x ", dev->domain_32);
printf("bus 0x%04x cardnum 0x%02x function 0x%02x:"
" vendor 0x%04x device 0x%04x\n",
dev->bus,
diff --git a/src/common_bridge.c b/src/common_bridge.c
index b4b5d7e..c187daa 100644
--- a/src/common_bridge.c
+++ b/src/common_bridge.c
@@ -347,7 +347,7 @@ pci_device_get_parent_bridge(struct pci_device *dev)
return NULL;
while ((bridge = pci_device_next(iter)) != NULL) {
- if (bridge->domain == dev->domain) {
+ if (bridge->domain_32 == dev->domain_32) {
const struct pci_bridge_info *info =
pci_device_get_bridge_info(bridge);
diff --git a/src/common_iterator.c b/src/common_iterator.c
index 2beb180..6346dd5 100644
--- a/src/common_iterator.c
+++ b/src/common_iterator.c
@@ -179,7 +179,7 @@ pci_device_next( struct pci_device_iterator * iter )
& pci_sys->devices[ iter->next_index ];
iter->next_index++;
- if ( PCI_ID_COMPARE( iter->match.slot.domain, temp->base.domain )
+ if ( PCI_ID_COMPARE( iter->match.slot.domain, temp->base.domain_32 )
&& PCI_ID_COMPARE( iter->match.slot.bus, temp->base.bus )
&& PCI_ID_COMPARE( iter->match.slot.dev, temp->base.dev )
&& PCI_ID_COMPARE( iter->match.slot.func, temp->base.func ) ) {
diff --git a/src/common_vgaarb.c b/src/common_vgaarb.c
index 515275f..fefaac2 100644
--- a/src/common_vgaarb.c
+++ b/src/common_vgaarb.c
@@ -237,7 +237,7 @@ pci_device_vgaarb_set_target(struct pci_device *dev)
return -1;
len = snprintf(buf, BUFSIZE, "target PCI:%04x:%02x:%02x.%x",
- dev->domain, dev->bus, dev->dev, dev->func);
+ dev->domain_32, dev->bus, dev->dev, dev->func);
ret = vgaarb_write(pci_sys->vgaarb_fd, buf, len);
if (ret)
diff --git a/src/freebsd_pci.c b/src/freebsd_pci.c
index f9c1476..8dfa67a 100644
--- a/src/freebsd_pci.c
+++ b/src/freebsd_pci.c
@@ -188,7 +188,7 @@ pci_device_freebsd_read( struct pci_device * dev, void * data,
struct pci_io io;
#if HAVE_PCI_IO_PC_DOMAIN
- io.pi_sel.pc_domain = dev->domain;
+ io.pi_sel.pc_domain = dev->domain_32;
#endif
io.pi_sel.pc_bus = dev->bus;
io.pi_sel.pc_dev = dev->dev;
@@ -228,7 +228,7 @@ pci_device_freebsd_write( struct pci_device * dev, const void * data,
struct pci_io io;
#if HAVE_PCI_IO_PC_DOMAIN
- io.pi_sel.pc_domain = dev->domain;
+ io.pi_sel.pc_domain = dev->domain_32;
#endif
io.pi_sel.pc_bus = dev->bus;
io.pi_sel.pc_dev = dev->dev;
@@ -352,7 +352,7 @@ pci_device_freebsd_probe( struct pci_device * dev )
int err, i;
#if HAVE_PCI_IO_PC_DOMAIN
- bar.pbi_sel.pc_domain = dev->domain;
+ bar.pbi_sel.pc_domain = dev->domain_32;
#endif
bar.pbi_sel.pc_bus = dev->bus;
bar.pbi_sel.pc_dev = dev->dev;
@@ -776,7 +776,7 @@ pci_system_freebsd_create( void )
struct pci_conf *p = &pciconf[ i ];
#if HAVE_PCI_IO_PC_DOMAIN
- pci_sys->devices[ i ].base.domain = p->pc_sel.pc_domain;
+ pci_sys->devices[ i ].base.domain = p->pc_sel.pc_domain_32;
#else
pci_sys->devices[ i ].base.domain = 0;
#endif
diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c
index dd8ef3e..2f51d76 100644
--- a/src/linux_sysfs.c
+++ b/src/linux_sysfs.c
@@ -118,28 +118,18 @@ pci_system_linux_sysfs_create( void )
/**
- * Filter out the names "." and ".." from the scanned sysfs entries, and
- * domains requiring 32-bits.
+ * Filter out the names "." and ".." from the scanned sysfs entries.
*
* \param d Directory entry being processed by \c scandir.
*
* \return
- * Zero if the entry name matches either "." or "..", or the domain requires
- * 32 bits, non-zero otherwise.
+ * Zero if the entry name matches either "." or ".."
*
* \sa scandir, populate_entries
*/
static int
scan_sys_pci_filter( const struct dirent * d )
{
- if (d->d_name[0] != '.') {
- unsigned dom = 0;
-
- sscanf(d->d_name, "%x:", &dom);
- if (dom > USHRT_MAX)
- return 0;
- }
-
return !((strcmp( d->d_name, "." ) == 0)
|| (strcmp( d->d_name, ".." ) == 0));
}
@@ -165,7 +155,7 @@ parse_separate_sysfs_files(struct pci_device * dev)
for (i = 0; i < 6; i++) {
snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/%s",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func,
@@ -218,10 +208,19 @@ populate_entries( struct pci_system * p )
(struct pci_device_private *) &p->devices[i];
- sscanf(devices[i]->d_name, "%04x:%02x:%02x.%1u",
+ sscanf(devices[i]->d_name, "%x:%02x:%02x.%1u",
& dom, & bus, & dev, & func);
- device->base.domain = dom;
+ device->base.domain_32 = dom;
+ /*
+ * Applications compiled with older versions do not expect
+ * 32-bit domain numbers. To keep them working, we keep a 16-bit
+ * version of the domain number at the previous location.
+ */
+ if (dom > 0xffff)
+ device->base.domain_16 = 0xffff;
+ else
+ device->base.domain_16 = dom;
device->base.bus = bus;
device->base.dev = dev;
device->base.func = func;
@@ -308,7 +307,7 @@ pci_device_linux_sysfs_probe( struct pci_device * dev )
*/
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/resource",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func );
@@ -369,7 +368,7 @@ pci_device_linux_sysfs_read_rom( struct pci_device * dev, void * buffer )
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/rom",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func );
@@ -450,7 +449,7 @@ pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
*/
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func );
@@ -510,7 +509,7 @@ pci_device_linux_sysfs_write( struct pci_device * dev, const void * data,
*/
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func );
@@ -561,7 +560,7 @@ pci_device_linux_sysfs_map_range_wc(struct pci_device *dev,
snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u_wc",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func,
@@ -625,7 +624,7 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev,
snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func,
@@ -749,7 +748,7 @@ static void pci_device_linux_sysfs_enable(struct pci_device *dev)
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/enable",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func );
@@ -771,7 +770,7 @@ static int pci_device_linux_sysfs_boot_vga(struct pci_device *dev)
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/boot_vga",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func );
@@ -798,7 +797,7 @@ static int pci_device_linux_sysfs_has_kernel_driver(struct pci_device *dev)
snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/driver",
SYS_BUS_PCI,
- dev->domain,
+ dev->domain_32,
dev->bus,
dev->dev,
dev->func );
@@ -817,7 +816,7 @@ pci_device_linux_sysfs_open_device_io(struct pci_io_handle *ret,
char name[PATH_MAX];
snprintf(name, PATH_MAX, "%s/%04x:%02x:%02x.%1u/resource%d",
- SYS_BUS_PCI, dev->domain, dev->bus, dev->dev, dev->func, bar);
+ SYS_BUS_PCI, dev->domain_32, dev->bus, dev->dev, dev->func, bar);
ret->fd = open(name, O_RDWR | O_CLOEXEC);
@@ -841,7 +840,7 @@ pci_device_linux_sysfs_open_legacy_io(struct pci_io_handle *ret,
/* First check if there's a legacy io method for the device */
while (dev) {
snprintf(name, PATH_MAX, "/sys/class/pci_bus/%04x:%02x/legacy_io",
- dev->domain, dev->bus);
+ dev->domain_32, dev->bus);
ret->fd = open(name, O_RDWR | O_CLOEXEC);
if (ret->fd >= 0)
@@ -988,7 +987,7 @@ pci_device_linux_sysfs_map_legacy(struct pci_device *dev, pciaddr_t base,
/* First check if there's a legacy memory method for the device */
while (dev) {
snprintf(name, PATH_MAX, "/sys/class/pci_bus/%04x:%02x/legacy_mem",
- dev->domain, dev->bus);
+ dev->domain_32, dev->bus);
fd = open(name, flags | O_CLOEXEC);
if (fd >= 0)
diff --git a/src/netbsd_pci.c b/src/netbsd_pci.c
index f972f94..c4d992c 100644
--- a/src/netbsd_pci.c
+++ b/src/netbsd_pci.c
@@ -152,7 +152,7 @@ pci_device_netbsd_map_range(struct pci_device *dev,
if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
prot |= PROT_WRITE;
map->memory = mmap(NULL, (size_t)map->size, prot, MAP_SHARED,
- buses[dev->domain].fd, (off_t)map->base);
+ buses[dev->domain_32].fd, (off_t)map->base);
if (map->memory == MAP_FAILED)
return errno;
@@ -216,7 +216,7 @@ pci_device_netbsd_read(struct pci_device *dev, void *data,
reg = (u_int)(offset & ~0x3);
- if ((pcibus_conf_read(buses[dev->domain].fd,
+ if ((pcibus_conf_read(buses[dev->domain_32].fd,
(unsigned int)dev->bus, (unsigned int)dev->dev,
(unsigned int)dev->func, reg, &rval)) == -1)
return errno;
@@ -249,7 +249,7 @@ pci_device_netbsd_write(struct pci_device *dev, const void *data,
reg = (u_int)offset;
memcpy(&val, data, 4);
- if ((pcibus_conf_write(buses[dev->domain].fd,
+ if ((pcibus_conf_write(buses[dev->domain_32].fd,
(unsigned int)dev->bus, (unsigned int)dev->dev,
(unsigned int)dev->func, reg, val)) == -1)
return errno;
@@ -289,7 +289,7 @@ pci_device_netbsd_boot_vga(struct pci_device *dev)
if (busid.bus_type != WSDISPLAYIO_BUS_PCI)
return 0;
- if (busid.ubus.pci.domain != dev->domain)
+ if (busid.ubus.pci.domain != dev->domain_32)
return 0;
if (busid.ubus.pci.bus != dev->bus)
return 0;
@@ -324,7 +324,7 @@ pci_device_netbsd_probe(struct pci_device *device)
uint32_t bar, reg, size;
int bus, dev, func, err, domain;
- domain = device->domain;
+ domain = device->domain_32;
bus = device->bus;
dev = device->dev;
func = device->func;
@@ -467,23 +467,23 @@ pci_device_netbsd_read_rom(struct pci_device *dev, void *buffer)
rom_base = priv->rom_base;
rom_size = dev->rom_size;
pci_rom = 1;
- if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
+ if ((pcibus_conf_read(buses[dev->domain_32].fd, (unsigned int)dev->bus,
(unsigned int)dev->dev, (unsigned int)dev->func,
PCI_COMMAND_STATUS_REG, &command_val)) == -1)
return errno;
if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
- if ((pcibus_conf_write(buses[dev->domain].fd,
+ if ((pcibus_conf_write(buses[dev->domain_32].fd,
(unsigned int)dev->bus, (unsigned int)dev->dev,
(unsigned int)dev->func, PCI_COMMAND_STATUS_REG,
command_val | PCI_COMMAND_MEM_ENABLE)) == -1)
return errno;
}
- if ((pcibus_conf_read(buses[dev->domain].fd, (unsigned int)dev->bus,
+ if ((pcibus_conf_read(buses[dev->domain_32].fd, (unsigned int)dev->bus,
(unsigned int)dev->dev, (unsigned int)dev->func,
PCI_MAPREG_ROM, &bios_val)) == -1)
return errno;
if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
- if ((pcibus_conf_write(buses[dev->domain].fd,
+ if ((pcibus_conf_write(buses[dev->domain_32].fd,
(unsigned int)dev->bus,
(unsigned int)dev->dev, (unsigned int)dev->func,
PCI_MAPREG_ROM, bios_val | PCI_MAPREG_ROM_ENABLE)) == -1)
@@ -494,7 +494,7 @@ pci_device_netbsd_read_rom(struct pci_device *dev, void *buffer)
fprintf(stderr, "Using rom_base = 0x%lx 0x%lx (pci_rom=%d)\n",
(long)rom_base, (long)rom_size, pci_rom);
- bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED, buses[dev->domain].fd,
+ bios = mmap(NULL, rom_size, PROT_READ, MAP_SHARED, buses[dev->domain_32].fd,
(off_t)rom_base);
if (bios == MAP_FAILED) {
int serrno = errno;
@@ -507,14 +507,14 @@ pci_device_netbsd_read_rom(struct pci_device *dev, void *buffer)
if (pci_rom) {
if ((command_val & PCI_COMMAND_MEM_ENABLE) == 0) {
- if ((pcibus_conf_write(buses[dev->domain].fd,
+ if ((pcibus_conf_write(buses[dev->domain_32].fd,
(unsigned int)dev->bus,
(unsigned int)dev->dev, (unsigned int)dev->func,
PCI_COMMAND_STATUS_REG, command_val)) == -1)
return errno;
}
if ((bios_val & PCI_MAPREG_ROM_ENABLE) == 0) {
- if ((pcibus_conf_write(buses[dev->domain].fd,
+ if ((pcibus_conf_write(buses[dev->domain_32].fd,
(unsigned int)dev->bus,
(unsigned int)dev->dev, (unsigned int)dev->func,
PCI_MAPREG_ROM, bios_val)) == -1)
@@ -958,7 +958,11 @@ pci_system_netbsd_create(void)
PCI_VENDOR(reg) == 0)
continue;
- device->base.domain = domain;
+ device->base.domain_32 = domain;
+ if (domain > 0xffff)
+ device->base.domain_16 = 0xffff;
+ else
+ device->base.domain_16 = domain & 0xffff;
device->base.bus = bus;
device->base.dev = dev;
device->base.func = func;
diff --git a/src/openbsd_pci.c b/src/openbsd_pci.c
index b8ce318..723874a 100644
--- a/src/openbsd_pci.c
+++ b/src/openbsd_pci.c
@@ -121,7 +121,7 @@ pci_device_openbsd_read_rom(struct pci_device *device, void *buffer)
u_int32_t csr, rom;
int pci_rom, domain, bus, dev, func;
- domain = device->domain;
+ domain = device->domain_32;
if (domain < 0 || domain >= ndomains)
return ENXIO;
@@ -655,7 +655,11 @@ pci_system_openbsd_create(void)
PCI_VENDOR(reg) == 0)
continue;
- device->base.domain = domain;
+ device->base.domain_32 = domain;
+ if (domain > 0xffff)
+ device->base.domain_16 = 0xffff;
+ else
+ device->base.domain_16 = domain & 0xffff;
device->base.bus = bus;
device->base.dev = dev;
device->base.func = func;
@@ -727,7 +731,7 @@ pci_device_vgaarb_init(void)
return -1;
pci_sys->vga_count = 0;
while ((dev = pci_device_next(iter)) != NULL) {
- if (dev->domain == 0)
+ if (dev->domain_32 == 0)
pci_sys->vga_count++;
}
pci_iterator_destroy(iter);
diff --git a/src/solx_devfs.c b/src/solx_devfs.c
index 46fc301..3e0976e 100644
--- a/src/solx_devfs.c
+++ b/src/solx_devfs.c
@@ -208,11 +208,16 @@ probe_device_node(di_node_t node, void *arg)
pci_base = &pinfo->devices[pinfo->num_devices].base;
- pci_base->domain = nexus->domain;
+ pci_base->domain_32 = nexus->domain;
pci_base->bus = PCI_REG_BUS_G(retbuf[0]);
pci_base->dev = PCI_REG_DEV_G(retbuf[0]);
pci_base->func = PCI_REG_FUNC_G(retbuf[0]);
+ if (nexus->domain > 0xffff)
+ pci_base->domain_16 = 0xffff;
+ else
+ pci_base->domain_16 = nexus->domain;
+
/* Get property values */
for (i = 0; i < NUM_PROPERTIES; i++) {
len = di_prop_lookup_ints(DDI_DEV_T_ANY, node,
@@ -233,7 +238,7 @@ probe_device_node(di_node_t node, void *arg)
fprintf(stderr, "cannot get property \"%s\" for nexus = %s :\n",
property_list[i].name, nexus->path);
fprintf(stderr, " domain = %x, busno = %x, devno = %x, funcno = %x\n",
- pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func);
+ pci_base->domain_32, pci_base->bus, pci_base->dev, pci_base->func);
#endif
}
}
@@ -527,7 +532,7 @@ pci_device_solx_devfs_probe( struct pci_device * dev )
(struct pci_device_private *) dev;
nexus_t *nexus;
- if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL )
+ if ( (nexus = find_nexus_for_bus(dev->domain_32, dev->bus)) == NULL )
return ENODEV;
pci_device_cfg_read_u8(dev, &priv->header_type, PCI_CONF_HEADER);
@@ -775,7 +780,7 @@ pci_device_solx_devfs_read( struct pci_device * dev, void * data,
nexus_t *nexus;
int fd;
- nexus = find_nexus_for_bus(dev->domain, dev->bus);
+ nexus = find_nexus_for_bus(dev->domain_32, dev->bus);
*bytes_read = 0;
@@ -835,7 +840,7 @@ pci_device_solx_devfs_write( struct pci_device * dev, const void * data,
nexus_t *nexus;
int fd;
- nexus = find_nexus_for_bus(dev->domain, dev->bus);
+ nexus = find_nexus_for_bus(dev->domain_32, dev->bus);
if ( bytes_written != NULL ) {
*bytes_written = 0;
diff --git a/src/x86_pci.c b/src/x86_pci.c
index 32daa04..a863f26 100644
--- a/src/x86_pci.c
+++ b/src/x86_pci.c
@@ -915,7 +915,7 @@ pci_system_x86_create(void)
if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
PCI_VENDOR(reg) == 0)
continue;
- device->base.domain = 0;
+ device->base.domain_32 = device->base.domain_16 = 0;
device->base.bus = bus;
device->base.dev = dev;
device->base.func = func;
--
2.13.5
More information about the xorg-devel
mailing list