IORT_ACPI_DECLARE(arm_smmu_v3, ACPI_SIG_IORT, acpi_smmu_v3_init);
其定义如下:
#define IORT_ACPI_DECLARE(name, table_id, fn) \
ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn)
#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \
static const struct acpi_probe_entry __acpi_probe_##name \
__used __section(__##table##_acpi_probe_table) \
= { \
.id = table_id, \
.type = subtable, \
.subtable_valid = valid, \
.probe_table = (acpi_tbl_table_handler)fn, \
.driver_data = data, \
}
这里需要关注的是id=ACPI_SIG_IORT。而probe_table=acpi_smmu_v3_init,去这个函数会放在__table_acpi_probe_table 这个段中.
因此在调用
void __init acpi_iort_init(void)
{
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;
}
iort_init_platform_devices();
acpi_probe_device_table(iort);
}
中调用acpi_probe_device_table的时候
#define acpi_probe_device_table(t) \
({ \
extern struct acpi_probe_entry ACPI_PROBE_TABLE(t), \
ACPI_PROBE_TABLE_END(t); \
__acpi_probe_device_table(&ACPI_PROBE_TABLE(t), \
(&ACPI_PROBE_TABLE_END(t) - \
&ACPI_PROBE_TABLE(t))); \
})
就等于调用__acpi_probe_device_table,而这里的#define ACPI_PROBE_TABLE(name) \
. = ALIGN(8); \
VMLINUX_SYMBOL(__##name##_acpi_probe_table) = .; \
*(__##name##_acpi_probe_table) \
VMLINUX_SYMBOL(__##name##_acpi_probe_table_end) = .;
就是表示在__table_acpi_probe_table 段中查找和ACPI表中id一样的,就调用probe_table 函数
int __init __acpi_probe_device_table(struct acpi_probe_entry *ap_head, int nr)
{
int count = 0;
if (acpi_disabled)
return 0;
mutex_lock(&acpi_probe_mutex);
for (ape = ap_head; nr; ape++, nr--) {
if (ACPI_COMPARE_NAME(ACPI_SIG_MADT, ape->id)) {
acpi_probe_count = 0;
acpi_table_parse_madt(ape->type, acpi_match_madt, 0);
count += acpi_probe_count;
} else {
int res;
res = acpi_table_parse(ape->id, ape->probe_table);
if (!res)
count++;
}
}
mutex_unlock(&acpi_probe_mutex);
return count;
}
__acpi_probe_device_table 中我们没有ACPI_SIG_MADT ,所以一般调用acpi_table_parse。这个函数之前以及给你分析过了,也就是说只要bios中传递iort 表后就会调用probe_table=acpi_smmu_v3_init 从而开始smmu v3的初始化.
而从acpi_init 的调用顺序看acpi_iort_init();在acpi_scan_init();的前面,因此在smmu v3 初始化函数中调用的dma_alloc_coherent其实走的是swiotlb的方式,也就是说在smmu 没有使能之前所有的dma都走的是swiotlb,包括smmu自身初始化过程中调用的dma接口函数.
static int __init acpi_init(void)
{
int result;
if (acpi_disabled) {
printk(KERN_INFO PREFIX "Interpreter disabled.\n");
return -ENODEV;
}
acpi_kobj = kobject_create_and_add("acpi", firmware_kobj);
if (!acpi_kobj) {
printk(KERN_WARNING "%s: kset create error\n", __func__);
acpi_kobj = NULL;
}
init_acpi_device_notify();
result = acpi_bus_init();
if (result) {
disable_acpi();
return result;
}
pci_mmcfg_late_init();
acpi_iort_init();
acpi_scan_init();
}