lib: acpi: add support for MAD table and DMAR table
add support for retrieve MAD and DMAR table information. Provided two new interface namely acpi_dmar_entry_get() and acpi_drhd_get() for retrieve DMA Remapping Reporting and DMA-remapping hardware unit definition (DRDH). Signed-off-by: Najumon B.A <najumon.ba@intel.com>
This commit is contained in:
parent
582995359a
commit
e5ec893c00
6 changed files with 264 additions and 35 deletions
|
@ -10,6 +10,11 @@
|
|||
|
||||
#define ACPI_RES_INVALID ACPI_RESOURCE_TYPE_MAX
|
||||
|
||||
#define ACPI_DRHD_FLAG_INCLUDE_PCI_ALL BIT(0)
|
||||
#define ACPI_DMAR_FLAG_INTR_REMAP BIT(0)
|
||||
#define ACPI_DMAR_FLAG_X2APIC_OPT_OUT BIT(1)
|
||||
#define ACPI_DMAR_FLAG_DMA_CTRL_PLATFORM_OPT_IN BIT(2)
|
||||
|
||||
struct acpi_dev {
|
||||
ACPI_HANDLE handle;
|
||||
char *path;
|
||||
|
@ -19,6 +24,22 @@ struct acpi_dev {
|
|||
ACPI_DEVICE_INFO *dev_info;
|
||||
};
|
||||
|
||||
union acpi_dmar_id {
|
||||
struct {
|
||||
uint16_t function: 3;
|
||||
uint16_t device: 5;
|
||||
uint16_t bus: 8;
|
||||
} bits;
|
||||
|
||||
uint16_t raw;
|
||||
};
|
||||
|
||||
struct acpi_mcfg {
|
||||
struct acpi_table_header header;
|
||||
uint64_t _reserved;
|
||||
struct acpi_mcfg_allocation pci_segs[];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* @brief Retrieve a legacy interrupt number for a PCI device.
|
||||
*
|
||||
|
@ -62,8 +83,7 @@ int acpi_current_resource_free(ACPI_RESOURCE *res);
|
|||
* @param rt_size the the size of IRQ routing table
|
||||
* @return return 0 on success or error code
|
||||
*/
|
||||
int acpi_get_irq_routing_table(char *bus_name,
|
||||
ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size);
|
||||
int acpi_get_irq_routing_table(char *bus_name, ACPI_PCI_ROUTING_TABLE *rt_table, size_t rt_size);
|
||||
|
||||
/**
|
||||
* @brief Parse resource table for a given resource type.
|
||||
|
@ -117,9 +137,48 @@ int acpi_device_type_get(ACPI_RESOURCE *res);
|
|||
*
|
||||
* @param signature pointer to the 4-character ACPI signature for the requested table
|
||||
* @param inst instance number for the requested table
|
||||
* @param acpi_table pointer to the acpi table
|
||||
* @return acpi_table pointer to the acpi table on success else return NULL
|
||||
*/
|
||||
void *acpi_table_get(char *signature, int inst);
|
||||
|
||||
/**
|
||||
* @brief retrieve acpi MAD table for the given type.
|
||||
*
|
||||
* @param type type of requested MAD table
|
||||
* @param tables pointer to the MAD table
|
||||
* @param num_inst number of instance for the requested table
|
||||
* @return return 0 on success or error code
|
||||
*/
|
||||
int acpi_table_get(char *signature, int inst, void **acpi_table);
|
||||
int acpi_madt_entry_get(int type, struct acpi_subtable_header **tables, int *num_inst);
|
||||
|
||||
/**
|
||||
* @brief retrieve DMA remapping structure for the given type.
|
||||
*
|
||||
* @param type type of remapping structure
|
||||
* @param tables pointer to the dmar id structure
|
||||
* @return return 0 on success or error code
|
||||
*/
|
||||
int acpi_dmar_entry_get(enum AcpiDmarType type,
|
||||
struct acpi_subtable_header **tables);
|
||||
|
||||
/**
|
||||
* @brief retrieve acpi DRHD info for the given scope.
|
||||
*
|
||||
* @param scope scope of requested DHRD table
|
||||
* @param dev_scope pointer to the sub table (optional)
|
||||
* @param dmar_id pointer to the DHRD info
|
||||
* @param num_inst number of instance for the requested table
|
||||
* @param max_inst maximum number of entry for the given dmar_id buffer
|
||||
* @return return 0 on success or error code
|
||||
*/
|
||||
int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *dev_scope,
|
||||
union acpi_dmar_id *dmar_id, int *num_inst, int max_inst);
|
||||
|
||||
/**
|
||||
* @brief Retrieve lapic info for a specific cpu.
|
||||
*
|
||||
* @param cpu_num the cpu number
|
||||
* @return lapic info on success or NULL
|
||||
*/
|
||||
struct acpi_madt_local_apic *acpi_local_apic_get(uint32_t cpu_num);
|
||||
#endif
|
||||
|
|
|
@ -40,10 +40,10 @@ config ACPI_INIT_PRIORITY
|
|||
boot time init level for acpi driver.
|
||||
|
||||
config ACPI_MAX_INIT_TABLES
|
||||
int "acpi table size"
|
||||
default 16
|
||||
int "maximum table entries"
|
||||
default 128
|
||||
help
|
||||
acpi table size.
|
||||
maximum number of table entries.
|
||||
|
||||
endif # ACPI
|
||||
|
||||
|
|
176
lib/acpi/acpi.c
176
lib/acpi/acpi.c
|
@ -39,7 +39,6 @@ static int check_init_status(void)
|
|||
}
|
||||
|
||||
if (bus_ctx.status == AE_NOT_CONFIGURED) {
|
||||
LOG_DBG("ACPI init\n");
|
||||
ret = acpi_init();
|
||||
} else {
|
||||
LOG_ERR("ACPI init was not success\n");
|
||||
|
@ -252,8 +251,10 @@ static int acpi_get_irq_table(struct acpi *bus, char *bus_name,
|
|||
if (!bus->pci_prt_table[i].SourceIndex) {
|
||||
break;
|
||||
}
|
||||
/* mark the PRT irq numbers as reserved. */
|
||||
arch_irq_set_used(bus->pci_prt_table[i].SourceIndex);
|
||||
if (IS_ENABLED(CONFIG_X86_64)) {
|
||||
/* mark the PRT irq numbers as reserved. */
|
||||
arch_irq_set_used(bus->pci_prt_table[i].SourceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -624,7 +625,7 @@ struct acpi_dev *acpi_device_by_index_get(int index)
|
|||
return index < bus_ctx.num_dev ? &bus_ctx.child_dev[index] : NULL;
|
||||
}
|
||||
|
||||
int acpi_table_get(char *signature, int inst, void **acpi_table)
|
||||
void *acpi_table_get(char *signature, int inst)
|
||||
{
|
||||
int status;
|
||||
ACPI_TABLE_HEADER *table;
|
||||
|
@ -632,18 +633,179 @@ int acpi_table_get(char *signature, int inst, void **acpi_table)
|
|||
if (!bus_ctx.early_init) {
|
||||
status = acpi_early_init();
|
||||
if (status) {
|
||||
LOG_ERR("ACPI early int failed");
|
||||
return status;
|
||||
LOG_ERR("ACPI early init failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
status = AcpiGetTable(signature, inst, &table);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
LOG_ERR("ACPI get table failed: %d", status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *)table;
|
||||
}
|
||||
|
||||
static uint32_t acpi_get_subtable_entry_num(int type, struct acpi_subtable_header *subtable,
|
||||
uintptr_t offset, uintptr_t base, uint32_t madt_len)
|
||||
{
|
||||
uint32_t subtable_cnt = 0;
|
||||
|
||||
while (offset < madt_len) {
|
||||
if (type == subtable->Type) {
|
||||
subtable_cnt++;
|
||||
}
|
||||
offset += subtable->Length;
|
||||
subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
|
||||
|
||||
if (!subtable->Length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return subtable_cnt;
|
||||
}
|
||||
|
||||
int acpi_madt_entry_get(int type, struct acpi_subtable_header **tables, int *num_inst)
|
||||
{
|
||||
struct acpi_table_header *madt = acpi_table_get("APIC", 0);
|
||||
uintptr_t base = POINTER_TO_UINT(madt);
|
||||
uintptr_t offset = sizeof(ACPI_TABLE_MADT);
|
||||
struct acpi_subtable_header *subtable;
|
||||
|
||||
if (!madt) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*acpi_table = table;
|
||||
subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
|
||||
while (offset < madt->Length) {
|
||||
|
||||
if (type == subtable->Type) {
|
||||
*tables = subtable;
|
||||
*num_inst = acpi_get_subtable_entry_num(type, subtable, offset, base,
|
||||
madt->Length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset += subtable->Length;
|
||||
subtable = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, base, offset);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int acpi_dmar_entry_get(enum AcpiDmarType type, struct acpi_subtable_header **tables)
|
||||
{
|
||||
struct acpi_table_dmar *dmar = acpi_table_get("DMAR", 0);
|
||||
uintptr_t base = POINTER_TO_UINT(dmar);
|
||||
uintptr_t offset = sizeof(ACPI_TABLE_DMAR);
|
||||
struct acpi_dmar_header *subtable;
|
||||
|
||||
if (!dmar) {
|
||||
LOG_ERR("error on get DMAR table\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, base, offset);
|
||||
while (offset < dmar->Header.Length) {
|
||||
if (type == subtable->Type) {
|
||||
*tables = (struct acpi_subtable_header *)subtable;
|
||||
return 0;
|
||||
}
|
||||
offset += subtable->Length;
|
||||
subtable = ACPI_ADD_PTR(ACPI_DMAR_HEADER, base, offset);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int acpi_drhd_get(enum AcpiDmarScopeType scope, struct acpi_dmar_device_scope *dev_scope,
|
||||
union acpi_dmar_id *dmar_id, int *num_inst, int max_inst)
|
||||
{
|
||||
uintptr_t offset = sizeof(ACPI_DMAR_HARDWARE_UNIT);
|
||||
uint32_t i = 0;
|
||||
struct acpi_dmar_header *drdh;
|
||||
struct acpi_dmar_device_scope *subtable;
|
||||
struct acpi_dmar_pci_path *dev_path;
|
||||
int ret;
|
||||
uintptr_t base;
|
||||
int scope_size;
|
||||
|
||||
ret = acpi_dmar_entry_get(ACPI_DMAR_TYPE_HARDWARE_UNIT,
|
||||
(struct acpi_subtable_header **)&drdh);
|
||||
if (ret) {
|
||||
LOG_ERR("Error on retrieve DMAR table\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
scope_size = drdh->Length - sizeof(ACPI_DMAR_HARDWARE_UNIT);
|
||||
base = (uintptr_t)((uintptr_t)drdh + offset);
|
||||
|
||||
offset = 0;
|
||||
|
||||
while (scope_size) {
|
||||
int num_path;
|
||||
|
||||
subtable = ACPI_ADD_PTR(ACPI_DMAR_DEVICE_SCOPE, base, offset);
|
||||
if (!subtable->Length) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (scope == subtable->EntryType) {
|
||||
num_path = (subtable->Length - 6u) / 2u;
|
||||
dev_path = ACPI_ADD_PTR(ACPI_DMAR_PCI_PATH, subtable,
|
||||
sizeof(ACPI_DMAR_DEVICE_SCOPE));
|
||||
|
||||
while (num_path--) {
|
||||
if (i >= max_inst) {
|
||||
LOG_ERR("DHRD not enough buffer size\n");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
dmar_id[i].bits.bus = subtable->Bus;
|
||||
dmar_id[i].bits.device = dev_path[i].Device;
|
||||
dmar_id[i].bits.function = dev_path[i].Function;
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
offset += subtable->Length;
|
||||
|
||||
if (scope_size < subtable->Length) {
|
||||
break;
|
||||
}
|
||||
scope_size -= subtable->Length;
|
||||
}
|
||||
|
||||
*num_inst = i;
|
||||
if (!i) {
|
||||
LOG_ERR("Error on retrieve DRHD Info\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (dev_scope && subtable) {
|
||||
memcpy(dev_scope, subtable, sizeof(struct acpi_dmar_device_scope));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct acpi_madt_local_apic *acpi_local_apic_get(uint32_t cpu_num)
|
||||
{
|
||||
struct acpi_madt_local_apic *lapic;
|
||||
int cpu_cnt;
|
||||
|
||||
if (acpi_madt_entry_get(ACPI_MADT_TYPE_LOCAL_APIC, (ACPI_SUBTABLE_HEADER **)&lapic,
|
||||
&cpu_cnt)) {
|
||||
/* Error on MAD table. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((cpu_num >= cpu_cnt) || !(lapic[cpu_num].LapicFlags & 1u)) {
|
||||
/* Proccessor not enabled. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &lapic[cpu_num];
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/arch/cpu.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/drivers/pcie/pcie.h>
|
||||
|
@ -91,7 +92,7 @@ static void dump_dev_res(const struct shell *sh, ACPI_RESOURCE *res_lst)
|
|||
|
||||
shell_print(sh, "\nACPI_RESOURCE_TYPE_ADDRESS32\n\n");
|
||||
shell_print(sh, "Minimum:%x, Maximum:%x\n", add_res->Address.Minimum,
|
||||
add_res->Address.Maximum);
|
||||
add_res->Address.Maximum);
|
||||
break;
|
||||
case ACPI_RESOURCE_TYPE_ADDRESS64:
|
||||
ACPI_RESOURCE_ADDRESS64 * add_res64 = &res->Data.Address64;
|
||||
|
@ -237,7 +238,6 @@ static int enum_dev(const struct shell *sh, size_t argc, char **argv)
|
|||
|
||||
static int read_table(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
int status;
|
||||
ACPI_TABLE_HEADER *table;
|
||||
|
||||
if (argc < 2) {
|
||||
|
@ -246,10 +246,10 @@ static int read_table(const struct shell *sh, size_t argc, char **argv)
|
|||
|
||||
shell_print(sh, "ACPI Table Name: %s\n", argv[1]);
|
||||
|
||||
status = acpi_table_get(argv[1], 0, (void **)&table);
|
||||
if (status) {
|
||||
shell_error(sh, "ACPI get table failed: %d\n", status);
|
||||
return status;
|
||||
table = acpi_table_get(argv[1], 0);
|
||||
if (!table) {
|
||||
shell_error(sh, "ACPI get table failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
shell_print(sh, "ACPI Table Info:\n");
|
||||
|
|
|
@ -29,6 +29,7 @@ if (CONFIG_ACPI)
|
|||
|
||||
get_filename_component(libname "${SRC_DIR}/common/" NAME)
|
||||
|
||||
if (CONFIG_ACPI_DSDT_SUPPORT)
|
||||
zephyr_library_sources(
|
||||
${COMP_DIR}/dispatcher/dsargs.c
|
||||
${COMP_DIR}/dispatcher/dscontrol.c
|
||||
|
@ -46,7 +47,6 @@ if (CONFIG_ACPI)
|
|||
${COMP_DIR}/dispatcher/dswload2.c
|
||||
${COMP_DIR}/dispatcher/dswscope.c
|
||||
${COMP_DIR}/dispatcher/dswstate.c
|
||||
|
||||
${COMP_DIR}/events/evhandler.c
|
||||
${COMP_DIR}/events/evmisc.c
|
||||
${COMP_DIR}/events/evregion.c
|
||||
|
@ -113,6 +113,22 @@ if (CONFIG_ACPI)
|
|||
${COMP_DIR}/parser/psutils.c
|
||||
${COMP_DIR}/parser/pswalk.c
|
||||
${COMP_DIR}/parser/psxface.c
|
||||
${COMP_DIR}/resources/rsxface.c
|
||||
${COMP_DIR}/resources/rsutils.c
|
||||
${COMP_DIR}/resources/rsaddr.c
|
||||
${COMP_DIR}/resources/rscalc.c
|
||||
${COMP_DIR}/resources/rscreate.c
|
||||
${COMP_DIR}/resources/rsdumpinfo.c
|
||||
${COMP_DIR}/resources/rsinfo.c
|
||||
${COMP_DIR}/resources/rsio.c
|
||||
${COMP_DIR}/resources/rsirq.c
|
||||
${COMP_DIR}/resources/rslist.c
|
||||
${COMP_DIR}/resources/rsmemory.c
|
||||
${COMP_DIR}/resources/rsmisc.c
|
||||
${COMP_DIR}/resources/rsserial.c
|
||||
)
|
||||
endif (CONFIG_ACPI_DSDT_SUPPORT)
|
||||
zephyr_library_sources(
|
||||
${COMP_DIR}/tables/tbdata.c
|
||||
${COMP_DIR}/tables/tbfadt.c
|
||||
${COMP_DIR}/tables/tbfind.c
|
||||
|
@ -158,20 +174,6 @@ if (CONFIG_ACPI)
|
|||
${COMP_DIR}/utilities/utxfinit.c
|
||||
${COMP_DIR}/utilities/utresdecode.c
|
||||
${COMP_DIR}/hardware/hwvalid.c
|
||||
${COMP_DIR}/resources/rsxface.c
|
||||
${COMP_DIR}/resources/rsutils.c
|
||||
${COMP_DIR}/resources/rsaddr.c
|
||||
${COMP_DIR}/resources/rscalc.c
|
||||
${COMP_DIR}/resources/rscreate.c
|
||||
${COMP_DIR}/resources/rsdumpinfo.c
|
||||
${COMP_DIR}/resources/rsinfo.c
|
||||
${COMP_DIR}/resources/rsio.c
|
||||
${COMP_DIR}/resources/rsirq.c
|
||||
${COMP_DIR}/resources/rslist.c
|
||||
${COMP_DIR}/resources/rsmemory.c
|
||||
${COMP_DIR}/resources/rsmisc.c
|
||||
${COMP_DIR}/resources/rsserial.c
|
||||
|
||||
${SRC_DIR}/os_specific/service_layers/oszephyr.c
|
||||
)
|
||||
endif (CONFIG_ACPI)
|
||||
|
|
|
@ -6,4 +6,10 @@ config ACPI
|
|||
|
||||
menu "ACPI driver support"
|
||||
|
||||
config ACPI_DSDT_SUPPORT
|
||||
bool "Build source code for DSDT ACPICA support"
|
||||
default y if PCIE
|
||||
help
|
||||
Build source code for DSDT support
|
||||
|
||||
endmenu
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue