点击查看系列文章 =》 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博客
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!