[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_dword );
PROVIDE_PCIAPI_INLINE ( direct, pci_ioremap );
struct pci_api pcidirect_api = PCIAPI_RUNTIME ( direct );
PROVIDE_PCIAPI_RUNTIME ( direct, PCIAPI_PRIORITY_DIRECT );

View File

@@ -11,6 +11,5 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h>
#include <ipxe/pcicloud.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 );
}
extern struct pci_api pcibios_api;
#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 );
}
extern struct pci_api pcidirect_api;
#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_dword );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_ioremap );
struct pci_api pcibios_api = PCIAPI_RUNTIME ( pcbios );
PROVIDE_PCIAPI_RUNTIME ( pcbios, PCIAPI_PRIORITY_PCBIOS );

View File

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

View File

@@ -22,6 +22,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/settings.h>
#include <config/ioapi.h>
/** @file
*
@@ -34,3 +35,13 @@ PROVIDE_REQUIRING_SYMBOL();
#ifdef PCI_SETTINGS
REQUIRE_OBJECT ( pci_settings );
#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_dword );
PROVIDE_PCIAPI_INLINE ( ecam, pci_ioremap );
struct pci_api ecam_api = PCIAPI_RUNTIME ( ecam );
PROVIDE_PCIAPI_RUNTIME ( ecam, PCIAPI_PRIORITY_ECAM );

View File

@@ -26,9 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <string.h>
#include <ipxe/pci.h>
#include <ipxe/ecam.h>
#include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h>
#include <ipxe/pcicloud.h>
/** @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 */
static struct {
/** PCI bus:dev.fn address range */
@@ -65,17 +57,14 @@ static struct pci_api * pcicloud_find ( uint32_t busdevfn,
uint32_t index;
uint32_t first;
uint32_t last;
unsigned int i;
/* Return empty range on error */
range->count = 0;
/* Try discovery via all known APIs */
for ( i = 0 ; i < ( sizeof ( pcicloud_apis ) /
sizeof ( pcicloud_apis[0] ) ) ; i++ ) {
for_each_table_entry ( api, PCI_APIS ) {
/* Discover via this API */
api = pcicloud_apis[i];
api->pci_discover ( busdevfn, &candidate );
/* 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 */
if ( ! api ) {
api = pcicloud_apis[ ( sizeof ( pcicloud_apis ) /
sizeof ( pcicloud_apis[0] ) ) - 1 ];
api = ( table_end ( PCI_APIS ) - 1 );
range->count = ( range->start - pci->busdevfn );
range->start = pci->busdevfn;
first = range->start;

View File

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

View File

@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/api.h>
#include <ipxe/tables.h>
#include <ipxe/iomap.h>
#include <config/ioapi.h>
@@ -61,6 +62,7 @@ struct pci_range {
/* Include all architecture-independent I/O API headers */
#include <ipxe/null_pci.h>
#include <ipxe/ecam_io.h>
#include <ipxe/pcicloud.h>
#include <ipxe/efi/efi_pci_api.h>
#include <ipxe/linux/linux_pci.h>
@@ -171,23 +173,45 @@ struct pci_api {
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 */
#define PCIAPI_RUNTIME( _subsys ) { \
.name = #_subsys, \
.pci_discover = PCIAPI_INLINE ( _subsys, pci_discover ), \
#define PROVIDE_PCIAPI_RUNTIME( subsys, priority ) \
struct pci_api pciapi_ ## subsys __pci_api ( priority ) = { \
.name = #subsys, \
.pci_discover = PCIAPI_INLINE ( subsys, pci_discover ), \
.pci_read_config_byte = \
PCIAPI_INLINE ( _subsys, pci_read_config_byte ), \
PCIAPI_INLINE ( subsys, pci_read_config_byte ), \
.pci_read_config_word = \
PCIAPI_INLINE ( _subsys, pci_read_config_word ), \
PCIAPI_INLINE ( subsys, pci_read_config_word ), \
.pci_read_config_dword = \
PCIAPI_INLINE ( _subsys, pci_read_config_dword ), \
PCIAPI_INLINE ( subsys, pci_read_config_dword ), \
.pci_write_config_byte = \
PCIAPI_INLINE ( _subsys, pci_write_config_byte ), \
PCIAPI_INLINE ( subsys, pci_write_config_byte ), \
.pci_write_config_word = \
PCIAPI_INLINE ( _subsys, pci_write_config_word ), \
PCIAPI_INLINE ( subsys, pci_write_config_word ), \
.pci_write_config_dword = \
PCIAPI_INLINE ( _subsys, 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 */