[pci] Add support for the Enhanced Configuration Access Mechanism (ECAM)

The ACPI MCFG table describes a direct mapping of PCI configuration
space into MMIO space.  This mapping allows access to extended
configuration space (up to 4096 bytes) and also provides for the
existence of multiple host bridges.

Add support for the ECAM mechanism described by the ACPI MCFG table,
as a selectable PCI I/O API alongside the existing PCI BIOS and Type 1
mechanisms.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2022-09-14 14:29:52 +01:00
parent ff228f745c
commit be667ba948
5 changed files with 461 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
#ifndef _IPXE_ECAM_H
#define _IPXE_ECAM_H
/** @file
*
* PCI I/O API for Enhanced Configuration Access Mechanism (ECAM)
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/acpi.h>
#include <ipxe/pci.h>
/** Enhanced Configuration Access Mechanism per-device size */
#define ECAM_SIZE 4096
/** Enhanced Configuration Access Mechanism table signature */
#define ECAM_SIGNATURE ACPI_SIGNATURE ( 'M', 'C', 'F', 'G' )
/** An Enhanced Configuration Access Mechanism allocation */
struct ecam_allocation {
/** Base address */
uint64_t base;
/** PCI segment number */
uint16_t segment;
/** Start PCI bus number */
uint8_t start;
/** End PCI bus number */
uint8_t end;
/** Reserved */
uint8_t reserved[4];
} __attribute__ (( packed ));
/** An Enhanced Configuration Access Mechanism table */
struct ecam_table {
/** ACPI header */
struct acpi_header acpi;
/** Reserved */
uint8_t reserved[8];
/** Allocation structures */
struct ecam_allocation alloc[0];
} __attribute__ (( packed ));
/** A mapped Enhanced Configuration Access Mechanism allocation */
struct ecam_mapping {
/** Allocation */
struct ecam_allocation alloc;
/** PCI bus:dev.fn address range */
struct pci_range range;
/** MMIO base address */
void *regs;
};
#endif /* _IPXE_ECAM_H */
+139
View File
@@ -0,0 +1,139 @@
#ifndef _IPXE_ECAM_IO_H
#define _IPXE_ECAM_IO_H
/** @file
*
* PCI I/O API for Enhanced Configuration Access Mechanism (ECAM)
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#ifdef PCIAPI_ECAM
#define PCIAPI_PREFIX_ecam
#else
#define PCIAPI_PREFIX_ecam __ecam_
#endif
struct pci_device;
/** Construct ECAM location */
#define ECAM_LOC( where, len ) ( ( (len) << 16 ) | where )
/** Extract offset from ECAM location */
#define ECAM_WHERE( location ) ( (location) & 0xffff )
/** Extract length from ECAM location */
#define ECAM_LEN( location ) ( (location) >> 16 )
extern int ecam_read ( struct pci_device *pci, unsigned int location,
void *value );
extern int ecam_write ( struct pci_device *pci, unsigned int location,
unsigned long value );
/**
* Read byte from PCI configuration space via ECAM
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value read
* @ret rc Return status code
*/
static inline __always_inline int
PCIAPI_INLINE ( ecam, pci_read_config_byte ) ( struct pci_device *pci,
unsigned int where,
uint8_t *value ) {
return ecam_read ( pci, ECAM_LOC ( where, sizeof ( *value ) ), value );
}
/**
* Read word from PCI configuration space via ECAM
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value read
* @ret rc Return status code
*/
static inline __always_inline int
PCIAPI_INLINE ( ecam, pci_read_config_word ) ( struct pci_device *pci,
unsigned int where,
uint16_t *value ) {
return ecam_read ( pci, ECAM_LOC ( where, sizeof ( *value ) ), value );
}
/**
* Read dword from PCI configuration space via ECAM
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value read
* @ret rc Return status code
*/
static inline __always_inline int
PCIAPI_INLINE ( ecam, pci_read_config_dword ) ( struct pci_device *pci,
unsigned int where,
uint32_t *value ) {
return ecam_read ( pci, ECAM_LOC ( where, sizeof ( *value ) ), value );
}
/**
* Write byte to PCI configuration space via ECAM
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value to be written
* @ret rc Return status code
*/
static inline __always_inline int
PCIAPI_INLINE ( ecam, pci_write_config_byte ) ( struct pci_device *pci,
unsigned int where,
uint8_t value ) {
return ecam_write ( pci, ECAM_LOC ( where, sizeof ( value ) ), value );
}
/**
* Write word to PCI configuration space via ECAM
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value to be written
* @ret rc Return status code
*/
static inline __always_inline int
PCIAPI_INLINE ( ecam, pci_write_config_word ) ( struct pci_device *pci,
unsigned int where,
uint16_t value ) {
return ecam_write ( pci, ECAM_LOC ( where, sizeof ( value ) ), value );
}
/**
* Write dword to PCI configuration space via ECAM
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value to be written
* @ret rc Return status code
*/
static inline __always_inline int
PCIAPI_INLINE ( ecam, pci_write_config_dword ) ( struct pci_device *pci,
unsigned int where,
uint32_t value ) {
return ecam_write ( pci, ECAM_LOC ( where, sizeof ( value ) ), value );
}
/**
* Map PCI bus address as an I/O address
*
* @v bus_addr PCI bus address
* @v len Length of region
* @ret io_addr I/O address, or NULL on error
*/
static inline __always_inline void *
PCIAPI_INLINE ( ecam, pci_ioremap ) ( struct pci_device *pci __unused,
unsigned long bus_addr, size_t len ) {
return ioremap ( bus_addr, len );
}
#endif /* _IPXE_ECAM_IO_H */
+1
View File
@@ -216,6 +216,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 )
#define ERRFILE_rdc ( ERRFILE_DRIVER | 0x00d10000 )
#define ERRFILE_ice ( ERRFILE_DRIVER | 0x00d20000 )
#define ERRFILE_ecam ( ERRFILE_DRIVER | 0x00d30000 )
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
+1
View File
@@ -58,6 +58,7 @@ struct pci_range {
PROVIDE_SINGLE_API_INLINE ( PCIAPI_PREFIX_ ## _subsys, _api_func )
/* Include all architecture-independent I/O API headers */
#include <ipxe/ecam_io.h>
#include <ipxe/efi/efi_pci_api.h>
#include <ipxe/linux/linux_pci.h>