mirror of
https://github.com/ipxe/ipxe
synced 2025-12-15 00:12:19 +03:00
[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:
@@ -32,8 +32,8 @@ extern void pcidirect_prepare ( struct pci_device *pci, int where );
|
|||||||
*/
|
*/
|
||||||
static inline __always_inline int
|
static inline __always_inline int
|
||||||
PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) {
|
PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) {
|
||||||
/* No way to work this out via Type 1 accesses */
|
/* Scan first bus and rely on bridge detection to find higher buses */
|
||||||
return 0x100;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -228,6 +228,9 @@ int pci_read_config ( struct pci_device *pci ) {
|
|||||||
*/
|
*/
|
||||||
int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
|
int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
|
||||||
static unsigned int end;
|
static unsigned int end;
|
||||||
|
unsigned int sub_end;
|
||||||
|
uint8_t hdrtype;
|
||||||
|
uint8_t sub;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Determine number of PCI buses */
|
/* Determine number of PCI buses */
|
||||||
@@ -236,9 +239,29 @@ int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
|
|||||||
|
|
||||||
/* Find next PCI device, if any */
|
/* Find next PCI device, if any */
|
||||||
for ( ; busdevfn < end ; busdevfn++ ) {
|
for ( ; busdevfn < end ; busdevfn++ ) {
|
||||||
|
|
||||||
|
/* Check for PCI device existence */
|
||||||
memset ( pci, 0, sizeof ( *pci ) );
|
memset ( pci, 0, sizeof ( *pci ) );
|
||||||
pci_init ( pci, busdevfn );
|
pci_init ( pci, busdevfn );
|
||||||
if ( ( rc = pci_read_config ( pci ) ) == 0 )
|
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 busdevfn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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_EHCI 0x20 /**< ECHI USB controller */
|
||||||
#define PCI_CLASS_SERIAL_USB_XHCI 0x30 /**< xHCI USB controller */
|
#define PCI_CLASS_SERIAL_USB_XHCI 0x30 /**< xHCI USB controller */
|
||||||
|
|
||||||
|
/** Subordinate bus number */
|
||||||
|
#define PCI_SUBORDINATE 0x1a
|
||||||
|
|
||||||
/** Construct PCI class
|
/** Construct PCI class
|
||||||
*
|
*
|
||||||
* @v base Base class (or PCI_ANY_ID)
|
* @v base Base class (or PCI_ANY_ID)
|
||||||
|
|||||||
Reference in New Issue
Block a user