mirror of https://github.com/ipxe/ipxe.git
[efi] Use address offset as reported by EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
Retrieve the address windows and translation offsets for the appropriate PCI root bridge and use them to adjust the PCI BAR address prior to calling ioremap(). Originally-implemented-by: Pankaj Bansal <pankaj.bansal@nxp.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/146/head
parent
eecb75ba48
commit
27e886c67b
|
@ -19,6 +19,138 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
#include <ipxe/api.h>
|
#include <ipxe/api.h>
|
||||||
#include <config/general.h>
|
#include <config/general.h>
|
||||||
|
|
||||||
|
/** An ACPI small resource descriptor header */
|
||||||
|
struct acpi_small_resource {
|
||||||
|
/** Tag byte */
|
||||||
|
uint8_t tag;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** ACPI small resource length mask */
|
||||||
|
#define ACPI_SMALL_LEN_MASK 0x03
|
||||||
|
|
||||||
|
/** An ACPI end resource descriptor */
|
||||||
|
#define ACPI_END_RESOURCE 0x78
|
||||||
|
|
||||||
|
/** An ACPI end resource descriptor */
|
||||||
|
struct acpi_end_resource {
|
||||||
|
/** Header */
|
||||||
|
struct acpi_small_resource hdr;
|
||||||
|
/** Checksum */
|
||||||
|
uint8_t checksum;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** An ACPI large resource descriptor header */
|
||||||
|
struct acpi_large_resource {
|
||||||
|
/** Tag byte */
|
||||||
|
uint8_t tag;
|
||||||
|
/** Length of data items */
|
||||||
|
uint16_t len;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** ACPI large resource flag */
|
||||||
|
#define ACPI_LARGE 0x80
|
||||||
|
|
||||||
|
/** An ACPI QWORD address space resource descriptor */
|
||||||
|
#define ACPI_QWORD_ADDRESS_SPACE_RESOURCE 0x8a
|
||||||
|
|
||||||
|
/** An ACPI QWORD address space resource descriptor */
|
||||||
|
struct acpi_qword_address_space_resource {
|
||||||
|
/** Header */
|
||||||
|
struct acpi_large_resource hdr;
|
||||||
|
/** Resource type */
|
||||||
|
uint8_t type;
|
||||||
|
/** General flags */
|
||||||
|
uint8_t general;
|
||||||
|
/** Type-specific flags */
|
||||||
|
uint8_t specific;
|
||||||
|
/** Granularity */
|
||||||
|
uint64_t granularity;
|
||||||
|
/** Minimum address */
|
||||||
|
uint64_t min;
|
||||||
|
/** Maximum address */
|
||||||
|
uint64_t max;
|
||||||
|
/** Translation offset */
|
||||||
|
uint64_t offset;
|
||||||
|
/** Length */
|
||||||
|
uint64_t len;
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
|
/** A memory address space type */
|
||||||
|
#define ACPI_ADDRESS_TYPE_MEM 0x00
|
||||||
|
|
||||||
|
/** An ACPI resource descriptor */
|
||||||
|
union acpi_resource {
|
||||||
|
/** Tag byte */
|
||||||
|
uint8_t tag;
|
||||||
|
/** Small resource descriptor */
|
||||||
|
struct acpi_small_resource small;
|
||||||
|
/** End resource descriptor */
|
||||||
|
struct acpi_end_resource end;
|
||||||
|
/** Large resource descriptor */
|
||||||
|
struct acpi_large_resource large;
|
||||||
|
/** QWORD address space resource descriptor */
|
||||||
|
struct acpi_qword_address_space_resource qword;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ACPI resource tag
|
||||||
|
*
|
||||||
|
* @v res ACPI resource descriptor
|
||||||
|
* @ret tag Resource tag
|
||||||
|
*/
|
||||||
|
static inline unsigned int acpi_resource_tag ( union acpi_resource *res ) {
|
||||||
|
|
||||||
|
return ( ( res->tag & ACPI_LARGE ) ?
|
||||||
|
res->tag : ( res->tag & ~ACPI_SMALL_LEN_MASK ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get length of ACPI small resource descriptor
|
||||||
|
*
|
||||||
|
* @v res Small resource descriptor
|
||||||
|
* @ret len Length of descriptor
|
||||||
|
*/
|
||||||
|
static inline size_t acpi_small_len ( struct acpi_small_resource *res ) {
|
||||||
|
|
||||||
|
return ( sizeof ( *res ) + ( res->tag & ACPI_SMALL_LEN_MASK ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get length of ACPI large resource descriptor
|
||||||
|
*
|
||||||
|
* @v res Large resource descriptor
|
||||||
|
* @ret len Length of descriptor
|
||||||
|
*/
|
||||||
|
static inline size_t acpi_large_len ( struct acpi_large_resource *res ) {
|
||||||
|
|
||||||
|
return ( sizeof ( *res ) + le16_to_cpu ( res->len ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get length of ACPI resource descriptor
|
||||||
|
*
|
||||||
|
* @v res ACPI resource descriptor
|
||||||
|
* @ret len Length of descriptor
|
||||||
|
*/
|
||||||
|
static inline size_t acpi_resource_len ( union acpi_resource *res ) {
|
||||||
|
|
||||||
|
return ( ( res->tag & ACPI_LARGE ) ?
|
||||||
|
acpi_large_len ( &res->large ) :
|
||||||
|
acpi_small_len ( &res->small ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get next ACPI resource descriptor
|
||||||
|
*
|
||||||
|
* @v res ACPI resource descriptor
|
||||||
|
* @ret next Next ACPI resource descriptor
|
||||||
|
*/
|
||||||
|
static inline union acpi_resource *
|
||||||
|
acpi_resource_next ( union acpi_resource *res ) {
|
||||||
|
|
||||||
|
return ( ( ( void * ) res ) + acpi_resource_len ( res ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ACPI description header
|
* An ACPI description header
|
||||||
*
|
*
|
||||||
|
|
|
@ -148,17 +148,4 @@ PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci,
|
||||||
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 ( efi, pci_ioremap ) ( struct pci_device *pci __unused,
|
|
||||||
unsigned long bus_addr, size_t len ) {
|
|
||||||
return ioremap ( bus_addr, len );
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _IPXE_EFI_PCI_API_H */
|
#endif /* _IPXE_EFI_PCI_API_H */
|
||||||
|
|
|
@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ipxe/pci.h>
|
#include <ipxe/pci.h>
|
||||||
|
#include <ipxe/acpi.h>
|
||||||
#include <ipxe/efi/efi.h>
|
#include <ipxe/efi/efi.h>
|
||||||
#include <ipxe/efi/efi_pci.h>
|
#include <ipxe/efi/efi_pci.h>
|
||||||
#include <ipxe/efi/efi_driver.h>
|
#include <ipxe/efi/efi_driver.h>
|
||||||
|
@ -224,6 +225,78 @@ int efipci_write ( struct pci_device *pci, unsigned long location,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
|
||||||
|
size_t len ) {
|
||||||
|
union {
|
||||||
|
union acpi_resource *res;
|
||||||
|
void *raw;
|
||||||
|
} u;
|
||||||
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
|
||||||
|
EFI_HANDLE handle;
|
||||||
|
unsigned int tag;
|
||||||
|
uint64_t offset;
|
||||||
|
uint64_t start;
|
||||||
|
uint64_t end;
|
||||||
|
void *io_addr = NULL;
|
||||||
|
EFI_STATUS efirc;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Open root bridge */
|
||||||
|
if ( ( rc = efipci_root_open ( pci, &handle, &root ) ) != 0 )
|
||||||
|
goto err_root;
|
||||||
|
|
||||||
|
/* Get ACPI resource descriptors */
|
||||||
|
if ( ( efirc = root->Configuration ( root, &u.raw ) ) != 0 ) {
|
||||||
|
rc = -EEFI ( efirc );
|
||||||
|
DBGC ( pci, "EFIPCI " PCI_FMT " cannot get configuration: "
|
||||||
|
"%s\n", PCI_ARGS ( pci ), strerror ( rc ) );
|
||||||
|
goto err_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse resource descriptors */
|
||||||
|
for ( ; ( ( tag = acpi_resource_tag ( u.res ) ) != ACPI_END_RESOURCE ) ;
|
||||||
|
u.res = acpi_resource_next ( u.res ) ) {
|
||||||
|
|
||||||
|
/* Ignore anything other than an address space descriptor */
|
||||||
|
if ( tag != ACPI_QWORD_ADDRESS_SPACE_RESOURCE )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Ignore descriptors that do not cover this memory range */
|
||||||
|
if ( u.res->qword.type != ACPI_ADDRESS_TYPE_MEM )
|
||||||
|
continue;
|
||||||
|
offset = le64_to_cpu ( u.res->qword.offset );
|
||||||
|
start = ( offset + le64_to_cpu ( u.res->qword.min ) );
|
||||||
|
end = ( start + le64_to_cpu ( u.res->qword.len ) );
|
||||||
|
if ( ( bus_addr < start ) || ( ( bus_addr + len ) > end ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Use this address space descriptor */
|
||||||
|
DBGC2 ( pci, "EFIPCI " PCI_FMT " %08lx+%zx -> ",
|
||||||
|
PCI_ARGS ( pci ), bus_addr, len );
|
||||||
|
bus_addr -= offset;
|
||||||
|
DBGC2 ( pci, "%08lx\n", bus_addr );
|
||||||
|
io_addr = ioremap ( bus_addr, len );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( ! io_addr ) {
|
||||||
|
DBGC ( pci, "EFIPCI " PCI_FMT " %08lx+%zx is not within "
|
||||||
|
"root bridge address space\n",
|
||||||
|
PCI_ARGS ( pci ), bus_addr, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
err_config:
|
||||||
|
efipci_root_close ( handle );
|
||||||
|
err_root:
|
||||||
|
return io_addr;
|
||||||
|
}
|
||||||
|
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
|
||||||
|
@ -231,7 +304,7 @@ PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
|
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
|
||||||
PROVIDE_PCIAPI_INLINE ( efi, pci_ioremap );
|
PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap );
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue