在kernel中一般通过acpi_get_table的方式找到某个子table的head
例如可以同下面这段code找到iort的head,然后将其赋值给iort_table,下面这段code可以当模板适用于acpi的个个子表
acpi_status status;
status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
const char *msg = acpi_format_exception(status);
pr_err("Failed to get table, %s\n", msg);
}
return;
}
而
acpi_status
acpi_get_table(char *signature,
u32 instance, struct acpi_table_header **out_table)
{
acpi_size tbl_size;
return acpi_get_table_with_size(signature,
instance, out_table, &tbl_size);
}
而
acpi_status
acpi_get_table_with_size(char *signature,
u32 instance, struct acpi_table_header **out_table,
acpi_size *tbl_size)
{
u32 i;
u32 j;
acpi_status status;
/* Parameter validation */
if (!signature || !out_table) {
return (AE_BAD_PARAMETER);
}
/* Walk the root table list */
for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
i++) {
if (!ACPI_COMPARE_NAME
(&(acpi_gbl_root_table_list.tables[i].signature),
signature)) {
continue;
}
if (++j < instance) {
continue;
}
status =
acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
if (ACPI_SUCCESS(status)) {
*out_table = acpi_gbl_root_table_list.tables[i].pointer;
*tbl_size = acpi_gbl_root_table_list.tables[i].length;
}
if (!acpi_gbl_permanent_mmap) {
acpi_gbl_root_table_list.tables[i].pointer = NULL;
}
return (status);
}
return (AE_NOT_FOUND);
}
可见bios传递给kernel的ACPI表在kernel中是用acpi_gbl_root_table_list.table 这个数组表示的。
回到最开始的问题,我们通过acpi_get_table 找到iort 子表后,就可以通过iort_node_match 来找这个iort子表中是否包含ACPI_IORT_NODE_SMMU_V3
static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
{
if (iort_node_match(ACPI_IORT_NODE_SMMU_V3))
return arm_smmu_init();
return 0;
}
而iort_node_match 实现如下:
static acpi_status
iort_match_type_callback(struct acpi_iort_node *node, void *context)
{
return AE_OK;
}
bool iort_node_match(u8 type)
{
struct acpi_iort_node *node;
node = iort_scan_node(type, iort_match_type_callback, NULL);
return node != NULL;
}
可见iort_match_type_callback 只是返回AE_OK 而已,最重要的是通过iort_scan_node 返回acpi_iort_node *node。
static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
iort_find_node_callback callback,
void *context)
{
struct acpi_iort_node *iort_node, *iort_end;
struct acpi_table_iort *iort;
int i;
if (!iort_table)
return NULL;
/* Get the first IORT node */
iort = (struct acpi_table_iort *)iort_table;
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
iort->node_offset);
iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
iort_table->length);
for (i = 0; i < iort->node_count; i++) {
if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
"IORT node pointer overflows, bad table!\n"))
return NULL;
if (iort_node->type == type &&
ACPI_SUCCESS(callback(iort_node, context)))
return iort_node;
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
iort_node->length);
}
return NULL;
}
在iort_scan_node 中会遍历之前找到iort在内存中的代表iort_table,然后遍历看是否有ACPI_IORT_NODE_SMMU_V3
if (iort_node->type == type && ACPI_SUCCESS(callback(iort_node, context)))
return iort_node;
如果找到的话,就返回iort_node。这样就可以开始smmu v3的初始化.
例如可以同下面这段code找到iort的head,然后将其赋值给iort_table,下面这段code可以当模板适用于acpi的个个子表
acpi_status status;
status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
const char *msg = acpi_format_exception(status);
pr_err("Failed to get table, %s\n", msg);
}
return;
}
而
acpi_status
acpi_get_table(char *signature,
u32 instance, struct acpi_table_header **out_table)
{
acpi_size tbl_size;
return acpi_get_table_with_size(signature,
instance, out_table, &tbl_size);
}
而
acpi_status
acpi_get_table_with_size(char *signature,
u32 instance, struct acpi_table_header **out_table,
acpi_size *tbl_size)
{
u32 i;
u32 j;
acpi_status status;
/* Parameter validation */
if (!signature || !out_table) {
return (AE_BAD_PARAMETER);
}
/* Walk the root table list */
for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count;
i++) {
if (!ACPI_COMPARE_NAME
(&(acpi_gbl_root_table_list.tables[i].signature),
signature)) {
continue;
}
if (++j < instance) {
continue;
}
status =
acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
if (ACPI_SUCCESS(status)) {
*out_table = acpi_gbl_root_table_list.tables[i].pointer;
*tbl_size = acpi_gbl_root_table_list.tables[i].length;
}
if (!acpi_gbl_permanent_mmap) {
acpi_gbl_root_table_list.tables[i].pointer = NULL;
}
return (status);
}
return (AE_NOT_FOUND);
}
可见bios传递给kernel的ACPI表在kernel中是用acpi_gbl_root_table_list.table 这个数组表示的。
回到最开始的问题,我们通过acpi_get_table 找到iort 子表后,就可以通过iort_node_match 来找这个iort子表中是否包含ACPI_IORT_NODE_SMMU_V3
static int __init acpi_smmu_v3_init(struct acpi_table_header *table)
{
if (iort_node_match(ACPI_IORT_NODE_SMMU_V3))
return arm_smmu_init();
return 0;
}
而iort_node_match 实现如下:
static acpi_status
iort_match_type_callback(struct acpi_iort_node *node, void *context)
{
return AE_OK;
}
bool iort_node_match(u8 type)
{
struct acpi_iort_node *node;
node = iort_scan_node(type, iort_match_type_callback, NULL);
return node != NULL;
}
可见iort_match_type_callback 只是返回AE_OK 而已,最重要的是通过iort_scan_node 返回acpi_iort_node *node。
static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
iort_find_node_callback callback,
void *context)
{
struct acpi_iort_node *iort_node, *iort_end;
struct acpi_table_iort *iort;
int i;
if (!iort_table)
return NULL;
/* Get the first IORT node */
iort = (struct acpi_table_iort *)iort_table;
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
iort->node_offset);
iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
iort_table->length);
for (i = 0; i < iort->node_count; i++) {
if (WARN_TAINT(iort_node >= iort_end, TAINT_FIRMWARE_WORKAROUND,
"IORT node pointer overflows, bad table!\n"))
return NULL;
if (iort_node->type == type &&
ACPI_SUCCESS(callback(iort_node, context)))
return iort_node;
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
iort_node->length);
}
return NULL;
}
在iort_scan_node 中会遍历之前找到iort在内存中的代表iort_table,然后遍历看是否有ACPI_IORT_NODE_SMMU_V3
if (iort_node->type == type && ACPI_SUCCESS(callback(iort_node, context)))
return iort_node;
如果找到的话,就返回iort_node。这样就可以开始smmu v3的初始化.