aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2021-04-10 13:14:30 +0100
committerMichael Brown <mcb30@ipxe.org>2021-04-10 15:05:05 +0100
commit0be8491b717fec6697dbf6ef8ac07604e062ecb1 (patch)
tree1f5d84a13dbd6113e7e884a2795e6e01cdda3a31
parentc0346dbb49de0bb6c7637c511a175ce478aca9b9 (diff)
downloadipxe-0be8491b717fec6697dbf6ef8ac07604e062ecb1.zip
ipxe-0be8491b717fec6697dbf6ef8ac07604e062ecb1.tar.gz
ipxe-0be8491b717fec6697dbf6ef8ac07604e062ecb1.tar.bz2
[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>
-rw-r--r--src/arch/x86/include/ipxe/pcidirect.h4
-rw-r--r--src/drivers/bus/pci.c27
-rw-r--r--src/include/ipxe/pci.h3
3 files changed, 30 insertions, 4 deletions
diff --git a/src/arch/x86/include/ipxe/pcidirect.h b/src/arch/x86/include/ipxe/pcidirect.h
index 9570fd7..decdc81 100644
--- a/src/arch/x86/include/ipxe/pcidirect.h
+++ b/src/arch/x86/include/ipxe/pcidirect.h
@@ -32,8 +32,8 @@ extern void pcidirect_prepare ( struct pci_device *pci, int where );
*/
static inline __always_inline int
PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) {
- /* No way to work this out via Type 1 accesses */
- return 0x100;
+ /* Scan first bus and rely on bridge detection to find higher buses */
+ return 1;
}
/**
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c
index 06b36a7..1b7350c 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;
diff --git a/src/include/ipxe/pci.h b/src/include/ipxe/pci.h
index 6632c57..933f485 100644
--- a/src/include/ipxe/pci.h
+++ b/src/include/ipxe/pci.h
@@ -135,6 +135,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define PCI_CLASS_SERIAL_USB_EHCI 0x20 /**< ECHI USB controller */
#define PCI_CLASS_SERIAL_USB_XHCI 0x30 /**< xHCI USB controller */
+/** Subordinate bus number */
+#define PCI_SUBORDINATE 0x1a
+
/** Construct PCI class
*
* @v base Base class (or PCI_ANY_ID)