PCIDIRECT_CONFIG_ADDRESS );
}
-PROVIDE_PCIAPI_INLINE ( direct, pci_num_bus );
+PROVIDE_PCIAPI_INLINE ( direct, pci_discover );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
extern void pcidirect_prepare ( struct pci_device *pci, int where );
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static inline __always_inline int
-PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) {
+static inline __always_inline void
+PCIAPI_INLINE ( direct, pci_discover ) ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
+
/* Scan first bus and rely on bridge detection to find higher buses */
- return 1;
+ range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
+ range->count = PCI_BUSDEVFN ( 0, 1, 0, 0 );
}
/**
*/
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static int pcibios_num_bus ( void ) {
+static void pcibios_discover ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
int discard_a, discard_D;
uint8_t max_bus;
"D" ( 0 )
: "ebx", "edx" );
- return ( max_bus + 1 );
+ /* Populate range */
+ range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
+ range->count = PCI_BUSDEVFN ( 0, ( max_bus + 1 ), 0, 0 );
}
/**
return ( status >> 8 );
}
-PROVIDE_PCIAPI ( pcbios, pci_num_bus, pcibios_num_bus );
+PROVIDE_PCIAPI ( pcbios, pci_discover, pcibios_discover );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
* @ret rc Return status code
*/
int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn ) {
- static unsigned int end;
- unsigned int sub_end;
+ static struct pci_range range;
uint8_t hdrtype;
uint8_t sub;
+ uint32_t end;
+ unsigned int count;
int rc;
- /* Determine number of PCI buses */
- if ( ! end )
- end = PCI_BUSDEVFN ( 0, pci_num_bus(), 0, 0 );
-
/* Find next PCI device, if any */
- for ( ; *busdevfn < end ; (*busdevfn)++ ) {
+ do {
+ /* Find next PCI bus:dev.fn address range, if necessary */
+ if ( ( *busdevfn - range.start ) >= range.count ) {
+ pci_discover ( *busdevfn, &range );
+ if ( *busdevfn < range.start )
+ *busdevfn = range.start;
+ if ( ( *busdevfn - range.start ) >= range.count )
+ break;
+ }
/* Check for PCI device existence */
memset ( pci, 0, sizeof ( *pci ) );
if ( ( rc = pci_read_config ( pci ) ) != 0 )
continue;
- /* If device is a bridge, expand the number of PCI
- * buses as needed.
+ /* If device is a bridge, expand the PCI bus:dev.fn
+ * address range 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 ) {
+ end = PCI_BUSDEVFN ( PCI_SEG ( *busdevfn ),
+ ( sub + 1 ), 0, 0 );
+ count = ( end - range.start );
+ if ( count > range.count ) {
DBGC ( pci, PCI_FMT " found subordinate bus "
"%#02x\n", PCI_ARGS ( pci ), sub );
- end = sub_end;
+ range.count = count;
}
}
/* Return this device */
return 0;
- }
+
+ } while ( ++(*busdevfn) );
return -ENODEV;
}
unsigned long value );
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static inline __always_inline int
-PCIAPI_INLINE ( efi, pci_num_bus ) ( void ) {
+static inline __always_inline void
+PCIAPI_INLINE ( efi, pci_discover ) ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
+
/* EFI does not want us to scan the PCI bus ourselves */
- return 0;
+ range->count = 0;
}
/**
unsigned long value, size_t len );
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static inline __always_inline int
-PCIAPI_INLINE ( linux, pci_num_bus ) ( void ) {
- /* Assume all buses may exist */
- return 0x100;
+static inline __always_inline void
+PCIAPI_INLINE ( linux, pci_discover ) ( uint32_t busdevfn __unused,
+ struct pci_range *range ) {
+
+ /* Assume all buses in segment 0 may exist */
+ range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
+ range->count = PCI_BUSDEVFN ( 1, 0, 0, 0 );
}
/**
#define PCI_BUS( busdevfn ) ( ( (busdevfn) >> 8 ) & 0xff )
#define PCI_SLOT( busdevfn ) ( ( (busdevfn) >> 3 ) & 0x1f )
#define PCI_FUNC( busdevfn ) ( ( (busdevfn) >> 0 ) & 0x07 )
-#define PCI_BUSDEVFN( segment, bus, slot, func ) \
- ( ( (segment) << 16 ) | ( (bus) << 8 ) | \
- ( (slot) << 3 ) | ( (func) << 0 ) )
#define PCI_FIRST_FUNC( busdevfn ) ( (busdevfn) & ~0x07 )
#define PCI_LAST_FUNC( busdevfn ) ( (busdevfn) | 0x07 )
#include <ipxe/iomap.h>
#include <config/ioapi.h>
+struct pci_device;
+
+/** A PCI bus:dev.fn address range */
+struct pci_range {
+ /** Starting bus:dev.fn address */
+ uint32_t start;
+ /** Number of bus:dev.fn addresses within this range */
+ unsigned int count;
+};
+
+#define PCI_BUSDEVFN( segment, bus, slot, func ) \
+ ( ( (segment) << 16 ) | ( (bus) << 8 ) | \
+ ( (slot) << 3 ) | ( (func) << 0 ) )
+
/**
* Calculate static inline PCI I/O API function name
*
#include <bits/pci_io.h>
/**
- * Determine number of PCI buses within system
+ * Find next PCI bus:dev.fn address range in system
*
- * @ret num_bus Number of buses
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-int pci_num_bus ( void );
+void pci_discover ( uint32_t busdevfn, struct pci_range *range );
/**
* Read byte from PCI configuration space
return ioremap ( bus_addr, len );
}
-PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
+PROVIDE_PCIAPI_INLINE ( efi, pci_discover );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
return rc;
}
-PROVIDE_PCIAPI_INLINE ( linux, pci_num_bus );
+PROVIDE_PCIAPI_INLINE ( linux, pci_discover );
PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_dword );