Commit e5ec893c authored by Najumon B.A's avatar Najumon B.A Committed by Carles Cufi
Browse files

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: default avatarNajumon B.A <najumon.ba@intel.com>
parent 58299535
Loading
Loading
Loading
Loading
+63 −4
Original line number Diff line number Diff line
@@ -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_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_table_get(char *signature, int inst, void **acpi_table);
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
+3 −3
Original line number Diff line number Diff line
@@ -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

+169 −7
Original line number Diff line number Diff line
@@ -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,9 +251,11 @@ static int acpi_get_irq_table(struct acpi *bus, char *bus_name,
		if (!bus->pci_prt_table[i].SourceIndex) {
			break;
		}
		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];
}
+6 −6
Original line number Diff line number Diff line
@@ -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>
@@ -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");
+17 −15
Original line number Diff line number Diff line
@@ -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)
Loading