[pci] Use linker tables for runtime selectable PCI APIs

Use the linker table mechanism to enumerate the underlying PCI I/O
APIs, to allow PCIAPI_CLOUD to become architecture-independent code.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-11-24 20:18:52 +00:00
parent 0cf2f8028c
commit ff1a17dc7e
12 changed files with 59 additions and 43 deletions

View File

@@ -54,5 +54,4 @@ PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword ); PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( direct, pci_ioremap ); PROVIDE_PCIAPI_INLINE ( direct, pci_ioremap );
PROVIDE_PCIAPI_RUNTIME ( direct, PCIAPI_PRIORITY_DIRECT );
struct pci_api pcidirect_api = PCIAPI_RUNTIME ( direct );

View File

@@ -11,6 +11,5 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/pcibios.h> #include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h> #include <ipxe/pcidirect.h>
#include <ipxe/pcicloud.h>
#endif /* _BITS_PCI_IO_H */ #endif /* _BITS_PCI_IO_H */

View File

@@ -155,6 +155,4 @@ PCIAPI_INLINE ( pcbios, pci_ioremap ) ( struct pci_device *pci __unused,
return ioremap ( bus_addr, len ); return ioremap ( bus_addr, len );
} }
extern struct pci_api pcibios_api;
#endif /* _IPXE_PCIBIOS_H */ #endif /* _IPXE_PCIBIOS_H */

View File

@@ -165,6 +165,4 @@ PCIAPI_INLINE ( direct, pci_ioremap ) ( struct pci_device *pci __unused,
return ioremap ( bus_addr, len ); return ioremap ( bus_addr, len );
} }
extern struct pci_api pcidirect_api;
#endif /* _PCIDIRECT_H */ #endif /* _PCIDIRECT_H */

View File

@@ -129,5 +129,4 @@ PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_ioremap ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_ioremap );
PROVIDE_PCIAPI_RUNTIME ( pcbios, PCIAPI_PRIORITY_PCBIOS );
struct pci_api pcibios_api = PCIAPI_RUNTIME ( pcbios );

View File

@@ -4,4 +4,7 @@
#ifdef PLATFORM_pcbios #ifdef PLATFORM_pcbios
#undef PCIAPI_PCBIOS #undef PCIAPI_PCBIOS
#define PCIAPI_CLOUD #define PCIAPI_CLOUD
#define PCIAPI_RUNTIME_ECAM
#define PCIAPI_RUNTIME_PCBIOS
#define PCIAPI_RUNTIME_DIRECT
#endif #endif

View File

@@ -22,6 +22,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/settings.h> #include <config/settings.h>
#include <config/ioapi.h>
/** @file /** @file
* *
@@ -34,3 +35,13 @@ PROVIDE_REQUIRING_SYMBOL();
#ifdef PCI_SETTINGS #ifdef PCI_SETTINGS
REQUIRE_OBJECT ( pci_settings ); REQUIRE_OBJECT ( pci_settings );
#endif #endif
#ifdef PCIAPI_RUNTIME_ECAM
REQUIRE_OBJECT ( ecam );
#endif
#ifdef PCIAPI_RUNTIME_PCBIOS
REQUIRE_OBJECT ( pcibios );
#endif
#ifdef PCIAPI_RUNTIME_DIRECT
REQUIRE_OBJECT ( pcidirect );
#endif

View File

@@ -279,5 +279,4 @@ PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_dword ); PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( ecam, pci_ioremap ); PROVIDE_PCIAPI_INLINE ( ecam, pci_ioremap );
PROVIDE_PCIAPI_RUNTIME ( ecam, PCIAPI_PRIORITY_ECAM );
struct pci_api ecam_api = PCIAPI_RUNTIME ( ecam );

View File

@@ -26,9 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <ipxe/pci.h> #include <ipxe/pci.h>
#include <ipxe/ecam.h>
#include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h>
#include <ipxe/pcicloud.h> #include <ipxe/pcicloud.h>
/** @file /** @file
@@ -37,11 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* *
*/ */
/** Underlying PCI configuration space access APIs */
static struct pci_api *pcicloud_apis[] = {
&ecam_api, &pcibios_api, &pcidirect_api
};
/** Cached PCI configuration space access API */ /** Cached PCI configuration space access API */
static struct { static struct {
/** PCI bus:dev.fn address range */ /** PCI bus:dev.fn address range */
@@ -65,17 +57,14 @@ static struct pci_api * pcicloud_find ( uint32_t busdevfn,
uint32_t index; uint32_t index;
uint32_t first; uint32_t first;
uint32_t last; uint32_t last;
unsigned int i;
/* Return empty range on error */ /* Return empty range on error */
range->count = 0; range->count = 0;
/* Try discovery via all known APIs */ /* Try discovery via all known APIs */
for ( i = 0 ; i < ( sizeof ( pcicloud_apis ) / for_each_table_entry ( api, PCI_APIS ) {
sizeof ( pcicloud_apis[0] ) ) ; i++ ) {
/* Discover via this API */ /* Discover via this API */
api = pcicloud_apis[i];
api->pci_discover ( busdevfn, &candidate ); api->pci_discover ( busdevfn, &candidate );
/* Check for a matching or new closest allocation */ /* Check for a matching or new closest allocation */
@@ -135,8 +124,7 @@ static struct pci_api * pcicloud_api ( struct pci_device *pci ) {
/* Fall back to lowest priority API for any unclaimed gaps in ranges */ /* Fall back to lowest priority API for any unclaimed gaps in ranges */
if ( ! api ) { if ( ! api ) {
api = pcicloud_apis[ ( sizeof ( pcicloud_apis ) / api = ( table_end ( PCI_APIS ) - 1 );
sizeof ( pcicloud_apis[0] ) ) - 1 ];
range->count = ( range->start - pci->busdevfn ); range->count = ( range->start - pci->busdevfn );
range->start = pci->busdevfn; range->start = pci->busdevfn;
first = range->start; first = range->start;

View File

@@ -54,6 +54,4 @@ struct ecam_mapping {
int rc; int rc;
}; };
extern struct pci_api ecam_api;
#endif /* _IPXE_ECAM_H */ #endif /* _IPXE_ECAM_H */

View File

@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h> #include <stdint.h>
#include <ipxe/api.h> #include <ipxe/api.h>
#include <ipxe/tables.h>
#include <ipxe/iomap.h> #include <ipxe/iomap.h>
#include <config/ioapi.h> #include <config/ioapi.h>
@@ -61,6 +62,7 @@ struct pci_range {
/* Include all architecture-independent I/O API headers */ /* Include all architecture-independent I/O API headers */
#include <ipxe/null_pci.h> #include <ipxe/null_pci.h>
#include <ipxe/ecam_io.h> #include <ipxe/ecam_io.h>
#include <ipxe/pcicloud.h>
#include <ipxe/efi/efi_pci_api.h> #include <ipxe/efi/efi_pci_api.h>
#include <ipxe/linux/linux_pci.h> #include <ipxe/linux/linux_pci.h>
@@ -171,23 +173,45 @@ struct pci_api {
typeof ( pci_ioremap ) ( * pci_ioremap ); typeof ( pci_ioremap ) ( * pci_ioremap );
}; };
/** Runtime selectable PCI API table */
#define PCI_APIS __table ( struct pci_api, "pci_apis" )
/**
* Declare a runtime selectable PCI API
*
* In the common case of a non-runtime-selectable PCI I/O API, allow
* the runtime API code to be garbage-collected at link time to save
* space.
*/
#ifdef PCIAPI_CLOUD
#define __pci_api( priority ) __table_entry ( PCI_APIS, priority )
#else
#define __pci_api( priority )
#endif
/* PCI runtime selectable API priorities */
#define PCIAPI_PRIORITY_ECAM 01 /**< ACPI ECAM */
#define PCIAPI_PRIORITY_PCBIOS 02 /**< PCI BIOS calls */
#define PCIAPI_PRIORITY_DIRECT 03 /**< Direct Type 1 accesses */
/** Provide a runtime selectable PCI I/O API */ /** Provide a runtime selectable PCI I/O API */
#define PCIAPI_RUNTIME( _subsys ) { \ #define PROVIDE_PCIAPI_RUNTIME( subsys, priority ) \
.name = #_subsys, \ struct pci_api pciapi_ ## subsys __pci_api ( priority ) = { \
.pci_discover = PCIAPI_INLINE ( _subsys, pci_discover ), \ .name = #subsys, \
.pci_read_config_byte = \ .pci_discover = PCIAPI_INLINE ( subsys, pci_discover ), \
PCIAPI_INLINE ( _subsys, pci_read_config_byte ), \ .pci_read_config_byte = \
.pci_read_config_word = \ PCIAPI_INLINE ( subsys, pci_read_config_byte ), \
PCIAPI_INLINE ( _subsys, pci_read_config_word ), \ .pci_read_config_word = \
.pci_read_config_dword = \ PCIAPI_INLINE ( subsys, pci_read_config_word ), \
PCIAPI_INLINE ( _subsys, pci_read_config_dword ), \ .pci_read_config_dword = \
.pci_write_config_byte = \ PCIAPI_INLINE ( subsys, pci_read_config_dword ), \
PCIAPI_INLINE ( _subsys, pci_write_config_byte ), \ .pci_write_config_byte = \
.pci_write_config_word = \ PCIAPI_INLINE ( subsys, pci_write_config_byte ), \
PCIAPI_INLINE ( _subsys, pci_write_config_word ), \ .pci_write_config_word = \
.pci_write_config_dword = \ PCIAPI_INLINE ( subsys, pci_write_config_word ), \
PCIAPI_INLINE ( _subsys, pci_write_config_dword ), \ .pci_write_config_dword = \
.pci_ioremap = PCIAPI_INLINE ( _subsys, pci_ioremap ), \ PCIAPI_INLINE ( subsys, pci_write_config_dword ), \
.pci_ioremap = PCIAPI_INLINE ( subsys, pci_ioremap ), \
} }
#endif /* _IPXE_PCI_IO_H */ #endif /* _IPXE_PCI_IO_H */