diff options
| author | Michael Brown | 2022-09-14 15:29:52 +0200 |
|---|---|---|
| committer | Michael Brown | 2022-09-16 02:05:47 +0200 |
| commit | be667ba94822877036f6c80992554ed32314a1f2 (patch) | |
| tree | e4c5dcd30a4de0d9b58c58357aa184cb397e7dd7 /src/include | |
| parent | [pci] Generalise pci_num_bus() to pci_discover() (diff) | |
| download | ipxe-be667ba94822877036f6c80992554ed32314a1f2.tar.gz ipxe-be667ba94822877036f6c80992554ed32314a1f2.tar.xz ipxe-be667ba94822877036f6c80992554ed32314a1f2.zip | |
[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>
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/ipxe/ecam.h | 55 | ||||
| -rw-r--r-- | src/include/ipxe/ecam_io.h | 139 | ||||
| -rw-r--r-- | src/include/ipxe/errfile.h | 1 | ||||
| -rw-r--r-- | src/include/ipxe/pci_io.h | 1 |
4 files changed, 196 insertions, 0 deletions
diff --git a/src/include/ipxe/ecam.h b/src/include/ipxe/ecam.h new file mode 100644 index 000000000..0f0fbf4bf --- /dev/null +++ b/src/include/ipxe/ecam.h @@ -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 */ diff --git a/src/include/ipxe/ecam_io.h b/src/include/ipxe/ecam_io.h new file mode 100644 index 000000000..4fb24db33 --- /dev/null +++ b/src/include/ipxe/ecam_io.h @@ -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 */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 9b955e574..2b8adbfd6 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -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 ) diff --git a/src/include/ipxe/pci_io.h b/src/include/ipxe/pci_io.h index 91359cec8..35d16f95e 100644 --- a/src/include/ipxe/pci_io.h +++ b/src/include/ipxe/pci_io.h @@ -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> |
