mirror of
https://github.com/ipxe/ipxe
synced 2026-02-14 02:31:26 +03:00
[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>
This commit is contained in:
@@ -45,7 +45,7 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) {
|
|||||||
PCIDIRECT_CONFIG_ADDRESS );
|
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_byte );
|
||||||
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
|
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
|
||||||
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
|
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
|
||||||
|
|||||||
@@ -26,14 +26,18 @@ struct pci_device;
|
|||||||
extern void pcidirect_prepare ( struct pci_device *pci, int where );
|
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
|
static inline __always_inline void
|
||||||
PCIAPI_INLINE ( direct, pci_num_bus ) ( 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 */
|
/* 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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,11 +34,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
int discard_a, discard_D;
|
||||||
uint8_t max_bus;
|
uint8_t max_bus;
|
||||||
|
|
||||||
@@ -57,7 +59,9 @@ static int pcibios_num_bus ( void ) {
|
|||||||
"D" ( 0 )
|
"D" ( 0 )
|
||||||
: "ebx", "edx" );
|
: "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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,7 +118,7 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){
|
|||||||
return ( status >> 8 );
|
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_byte );
|
||||||
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
|
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
|
||||||
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
|
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
|
||||||
|
|||||||
@@ -233,18 +233,23 @@ int pci_read_config ( struct pci_device *pci ) {
|
|||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn ) {
|
int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn ) {
|
||||||
static unsigned int end;
|
static struct pci_range range;
|
||||||
unsigned int sub_end;
|
|
||||||
uint8_t hdrtype;
|
uint8_t hdrtype;
|
||||||
uint8_t sub;
|
uint8_t sub;
|
||||||
|
uint32_t end;
|
||||||
|
unsigned int count;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Determine number of PCI buses */
|
|
||||||
if ( ! end )
|
|
||||||
end = PCI_BUSDEVFN ( 0, pci_num_bus(), 0, 0 );
|
|
||||||
|
|
||||||
/* Find next PCI device, if any */
|
/* 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 */
|
/* Check for PCI device existence */
|
||||||
memset ( pci, 0, sizeof ( *pci ) );
|
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 )
|
if ( ( rc = pci_read_config ( pci ) ) != 0 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* If device is a bridge, expand the number of PCI
|
/* If device is a bridge, expand the PCI bus:dev.fn
|
||||||
* buses as needed.
|
* address range as needed.
|
||||||
*/
|
*/
|
||||||
pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
|
pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
|
||||||
hdrtype &= PCI_HEADER_TYPE_MASK;
|
hdrtype &= PCI_HEADER_TYPE_MASK;
|
||||||
if ( hdrtype == PCI_HEADER_TYPE_BRIDGE ) {
|
if ( hdrtype == PCI_HEADER_TYPE_BRIDGE ) {
|
||||||
pci_read_config_byte ( pci, PCI_SUBORDINATE, &sub );
|
pci_read_config_byte ( pci, PCI_SUBORDINATE, &sub );
|
||||||
sub_end = PCI_BUSDEVFN ( 0, ( sub + 1 ), 0, 0 );
|
end = PCI_BUSDEVFN ( PCI_SEG ( *busdevfn ),
|
||||||
if ( end < sub_end ) {
|
( sub + 1 ), 0, 0 );
|
||||||
|
count = ( end - range.start );
|
||||||
|
if ( count > range.count ) {
|
||||||
DBGC ( pci, PCI_FMT " found subordinate bus "
|
DBGC ( pci, PCI_FMT " found subordinate bus "
|
||||||
"%#02x\n", PCI_ARGS ( pci ), sub );
|
"%#02x\n", PCI_ARGS ( pci ), sub );
|
||||||
end = sub_end;
|
range.count = count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return this device */
|
/* Return this device */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
} while ( ++(*busdevfn) );
|
||||||
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,17 @@ extern int efipci_write ( struct pci_device *pci, unsigned long location,
|
|||||||
unsigned long value );
|
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
|
static inline __always_inline void
|
||||||
PCIAPI_INLINE ( efi, pci_num_bus ) ( 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 */
|
/* EFI does not want us to scan the PCI bus ourselves */
|
||||||
return 0;
|
range->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,14 +23,18 @@ extern int linux_pci_write ( struct pci_device *pci, unsigned long where,
|
|||||||
unsigned long value, size_t len );
|
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
|
static inline __always_inline void
|
||||||
PCIAPI_INLINE ( linux, pci_num_bus ) ( void ) {
|
PCIAPI_INLINE ( linux, pci_discover ) ( uint32_t busdevfn __unused,
|
||||||
/* Assume all buses may exist */
|
struct pci_range *range ) {
|
||||||
return 0x100;
|
|
||||||
|
/* Assume all buses in segment 0 may exist */
|
||||||
|
range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
|
||||||
|
range->count = PCI_BUSDEVFN ( 1, 0, 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -262,9 +262,6 @@ struct pci_driver {
|
|||||||
#define PCI_BUS( busdevfn ) ( ( (busdevfn) >> 8 ) & 0xff )
|
#define PCI_BUS( busdevfn ) ( ( (busdevfn) >> 8 ) & 0xff )
|
||||||
#define PCI_SLOT( busdevfn ) ( ( (busdevfn) >> 3 ) & 0x1f )
|
#define PCI_SLOT( busdevfn ) ( ( (busdevfn) >> 3 ) & 0x1f )
|
||||||
#define PCI_FUNC( busdevfn ) ( ( (busdevfn) >> 0 ) & 0x07 )
|
#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_FIRST_FUNC( busdevfn ) ( (busdevfn) & ~0x07 )
|
||||||
#define PCI_LAST_FUNC( busdevfn ) ( (busdevfn) | 0x07 )
|
#define PCI_LAST_FUNC( busdevfn ) ( (busdevfn) | 0x07 )
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
#include <ipxe/iomap.h>
|
#include <ipxe/iomap.h>
|
||||||
#include <config/ioapi.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
|
* Calculate static inline PCI I/O API function name
|
||||||
*
|
*
|
||||||
@@ -51,11 +65,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
#include <bits/pci_io.h>
|
#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
|
* Read byte from PCI configuration space
|
||||||
|
|||||||
@@ -362,7 +362,7 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
|
|||||||
return ioremap ( bus_addr, len );
|
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_byte );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ int linux_pci_write ( struct pci_device *pci, unsigned long where,
|
|||||||
return rc;
|
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_byte );
|
||||||
PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_word );
|
PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_word );
|
||||||
PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_dword );
|
PROVIDE_PCIAPI_INLINE ( linux, pci_read_config_dword );
|
||||||
|
|||||||
Reference in New Issue
Block a user