mirror of
https://github.com/ipxe/ipxe
synced 2026-04-16 03:00:10 +03:00
[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:
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 )
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user