diff options
author | Michael Brown <mcb30@ipxe.org> | 2021-04-10 13:14:30 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2021-04-10 15:05:05 +0100 |
commit | 0be8491b717fec6697dbf6ef8ac07604e062ecb1 (patch) | |
tree | 1f5d84a13dbd6113e7e884a2795e6e01cdda3a31 /src/drivers | |
parent | c0346dbb49de0bb6c7637c511a175ce478aca9b9 (diff) | |
download | ipxe-0be8491b717fec6697dbf6ef8ac07604e062ecb1.tar.gz |
[pci] Avoid scanning nonexistent buses when using PCIAPI_DIRECT
There is no method for obtaining the number of PCI buses when using
PCIAPI_DIRECT, and we therefore currently scan all possible bus
numbers. This can cause a several-second startup delay in some
virtualised environments, since PCI configuration space access will
necessarily require the involvement of the hypervisor.
Ameliorate this situation by defaulting to scanning only a single bus,
and expanding the number of PCI buses to accommodate any subordinate
buses that are detected during enumeration.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers')
-rw-r--r-- | src/drivers/bus/pci.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c index 06b36a770..1b7350c8b 100644 --- a/src/drivers/bus/pci.c +++ b/src/drivers/bus/pci.c @@ -228,6 +228,9 @@ int pci_read_config ( struct pci_device *pci ) { */ int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) { static unsigned int end; + unsigned int sub_end; + uint8_t hdrtype; + uint8_t sub; int rc; /* Determine number of PCI buses */ @@ -236,10 +239,30 @@ int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) { /* Find next PCI device, if any */ for ( ; busdevfn < end ; busdevfn++ ) { + + /* Check for PCI device existence */ memset ( pci, 0, sizeof ( *pci ) ); pci_init ( pci, busdevfn ); - if ( ( rc = pci_read_config ( pci ) ) == 0 ) - return busdevfn; + if ( ( rc = pci_read_config ( pci ) ) != 0 ) + continue; + + /* If device is a bridge, expand the number of PCI + * buses as needed. + */ + pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype ); + hdrtype &= PCI_HEADER_TYPE_MASK; + if ( hdrtype == PCI_HEADER_TYPE_BRIDGE ) { + pci_read_config_byte ( pci, PCI_SUBORDINATE, &sub ); + sub_end = PCI_BUSDEVFN ( 0, ( sub + 1 ), 0, 0 ); + if ( end < sub_end ) { + DBGC ( pci, PCI_FMT " found subordinate bus " + "%#02x\n", PCI_ARGS ( pci ), sub ); + end = sub_end; + } + } + + /* Return this device */ + return busdevfn; } return -ENODEV; |