diff options
author | Michael Brown <mcb30@ipxe.org> | 2022-09-15 16:47:04 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2022-09-15 16:49:47 +0100 |
commit | ff228f745c15594291fd3cbf3c02af27753a3885 (patch) | |
tree | 20fcd06b1407db029e1969095c9f4a449451ba64 /src/drivers | |
parent | 56b30364c5db6367279ffe88929f286f15680b40 (diff) | |
download | ipxe-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.c | 34 |
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; } |