aboutsummaryrefslogtreecommitdiffstats
path: root/src/drivers
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2022-09-15 16:47:04 +0100
committerMichael Brown <mcb30@ipxe.org>2022-09-15 16:49:47 +0100
commitff228f745c15594291fd3cbf3c02af27753a3885 (patch)
tree20fcd06b1407db029e1969095c9f4a449451ba64 /src/drivers
parent56b30364c5db6367279ffe88929f286f15680b40 (diff)
downloadipxe-ff228f745c15594291fd3cbf3c02af27753a3885.tar.gz
[pci] Generalise pci_num_bus() to pci_discover()
Allow pci_find_next() to discover devices beyond the first PCI segment, by generalising pci_num_bus() (which implicitly assumes that there is only a single PCI segment) with pci_discover() (which has the ability to return an arbitrary contiguous chunk of PCI bus:dev.fn address space). Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/bus/pci.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/src/drivers/bus/pci.c b/src/drivers/bus/pci.c
index c5deb08f6..7953aaedd 100644
--- a/src/drivers/bus/pci.c
+++ b/src/drivers/bus/pci.c
@@ -233,18 +233,23 @@ int pci_read_config ( struct pci_device *pci ) {
* @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 ) );
@@ -252,24 +257,27 @@ int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn ) {
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;
}