smmu学习笔记之smmu v3 初始化

smmu的初始化如下:
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();

}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值