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:
Najumon B.A 2023-07-02 14:04:55 +05:30 committed by Carles Cufí
commit e5ec893c00
6 changed files with 264 additions and 35 deletions

View file

@ -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

View file

@ -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

View file

@ -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];
}

View file

@ -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");

View file

@ -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)

View file

@ -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