4.2.3 根据DTS完成中断控制器初始化

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

4.2.3 根据DTS完成中断控制器初始化

GIC V3中断控制器驱动irq-gic-v3.c中,IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init)其实就是初始化了一个静态常量:struct of_device_id __of_table_gic_v3。

//定义了 struct of_device_id __of_table_gic_v3
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);

#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
 
 
#define OF_DECLARE_2(table, name, compat, fn) \ 
        _OF_DECLARE(table, name, compat, fn, of_init_fn_2)
 
 
#define _OF_DECLARE(table, name, compat, fn, fn_type)            \ 
    static const struct of_device_id __of_table_##name        \ 
        __used __section(__##table##_of_table)            \ 
         = { .compatible = compat,                \ 
             .data = (fn == (fn_type)NULL) ? fn : fn  }

 根据_OF_DECLARE,struct of_device_id __of_table_gic_v3被指定放在了__irqchip_of_table段(section)中。这个段定义arch/arm64/kernel/vmlinux.lds中,在编译Linux的过程中,变量__of_table_gic_v3会被放在__irqchip_of_table段(section)中。

IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init)最终展开为:

struct of_device_id __of_table_gic_v3 __used __section(__irqchip_of_table) = {
.compatible = "arm,gic-v3",
.data = gic_of_init
};

of_irq_init(__irqchip_of_table)从__irqchip_of_table中找出变量__of_table_gic_v3,根据.compatible = "arm,gic-v3"成员,遍历struct device_node设备树,找到匹配的struct device_node节点。如果这个struct device_node节点带有"interrupt-controller"属性,调用gic_of_init(.data = gic_of_init)进行GIC V3中断控制器的初始化。

以QEMU virt为例,上图中的DTS中的intc@8000000节点,完全符合上述分析。下图是实际的调用堆栈,gic_of_init传入的参数struct device_node *node就指向intc@8000000节点。

gic_of_init函数的内部细节就不一一分析了,这里只关注重点irq_domain。如下图所示的调用堆栈,分配了一个 irq_domain 数据结构实例来表示GIC v3,最后把这个irq_domain加入到了全局链表irq_domain_list。

struct irq_domain 是 Linux 内核中用于硬件中断号转换的数据结构,将硬件中断号(hwirq)映射到内核中的虚拟中断号(virq)。关注struct irq_domain如下几个成员,在后面分析中断号映射时会用到。

  • 映射操作:struct irq_domain_ops

irq_domain_ops 是 Linux 内核中用于定义中断域操作方法的结构体。这个结构体包含了一系列函数指针,这些函数指针指向了处理特定中断域操作的函数。通过这些操作,内核可以与中断控制器进行交互,并实现硬件中断号(hwirq)到虚拟中断号(virq)的映射。

static const struct irq_domain_ops gic_irq_domain_ops = {
    //从设备树中的中断规范(irq_fwspec)翻译出硬件中断号(hwirq)和中断类型(type)
	.translate = gic_irq_domain_translate,
    //完成虚拟中断号到硬件中断号的映射
	.alloc = gic_irq_domain_alloc,
    //释放之前通过 alloc 函数分配的资源
	.free = gic_irq_domain_free,
    //选择合适的中断控制器
	.select = gic_irq_domain_select,
};
  •  反向映射相关数据结构

反向映射是指从hwirq找到对应的virq;而映射(正向映射)是指从virq找到对应的hwirq。irq_domain支持两种反向映射的方法:数组linear_revmap和基数树revmap_tree。

数组linear_revmap,其中每个数组下标对应一个硬件中断号,数值为相应的虚拟中断号。优点是访问速度快,适用于连续且范围较小的硬件中断号。缺点是如果硬件中断号范围很大,会占用大量内存。

基数树revmap_tree,用于存储非线性的、稀疏的反向映射关系,基数树中的每个节点存储了一个硬件中断号和相应的虚拟中断号。基数树是一种高效的数据结构,特别适合处理不连续或范围较大的硬件中断号。优点是内存使用效率高,适用于稀疏的中断号映射。缺点是访问速度比线性数组稍慢,但仍然非常高效。

hwirq_max: 最大的硬件中断号。

revmap_direct_max_irq: 支持直接映射的最大硬件中断号。

revmap_size: 线性映射表 linear_revmap 的大小。

revmap_tree: 基数树,用于存储硬件中断号到虚拟中断号的反向映射。

revmap_tree_mutex: 保护基数树的互斥锁。

linear_revmap: 线性表,用于存储硬件中断号到虚拟中断号的反向映射。

小结一下,根据DTS树找到中断控制器后,创建irq_domain。irq_domain提供struct irq_domain_ops来完成virq到hwirq的映射,提供数组linear_revmap或基数树revmap_tree用于从hwirq反向查找virq。

具体的映射过程和反向查找,下一章节举例说明。

点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客

原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值