[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>
This commit is contained in:
Michael Brown
2021-04-10 13:14:30 +01:00
parent c0346dbb49
commit 0be8491b71
3 changed files with 30 additions and 4 deletions

View File

@@ -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;