介绍
软件可以不需要关注该中断在硬件上是哪个中断来源。简单的 SOC内部对中断的管理也比较简单,通常会有一个全局的中断状态寄存器来记录外设中断,这样直接将硬件中断号线性映射到软件中断号即可。但是随着芯片技术的发展,SOC越来越复杂,通常内部会有多个中断控制器(比如GIC interrupt controller, GPIO interrupt controller), 每一个中断控制器对应多个中断号,而硬件中断号在不同的中断控制器上是会重复编码, 这时仅仅用硬中断号已经不能唯一标识一个外设中断。尤其在多个中断控制器级联的情况下,会变得更加复杂。这样对软件编程来讲极不友好,作为软件工程师,我们更愿意集中精力关注软件层面的内容
咱们沿着启动过程来分析它的映射:以4412板子来分析
中断控制器的初始化
start_kernel
=====>init_IRQ
=====>irqchip_init
=====>of_irq_init(__irqchip_of_table);
====> irq_init_cb = (of_irq_init_cb_t)match->data; //gic_of_init
====> ret = irq_init_cb(desc->dev, desc->interrupt_parent);//运行gic_of_init
gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base, hwirq_base, &gic_irq_domain_ops, gic);
====> gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
&gic_data);通过irq_domain_create_tree() 申请一个domain内存,赋值后加入到全局的 irq_domain_list中。同时,设置中断处理入口函数。
====> set_handle_irq(gic_handle_irq);
软件中断号的获取与映射
start_kernel
rest_init
kernel_init
kernel_init_freeable
do_one_initcall
customize_machine
of_platform_populate
of_platform_bus_create
of_platform_device_create_pdata
of_device_alloc
num_irq = of_irq_count(np); //Count the number of IRQs a node uses
of_irq_to_resource_table
of_irq_to_resource
irq_of_parse_and_map
of_irq_parse_one//从dts中收集该
中断的相关信息如触发方式,中断号
irq_create_of_mapping
irq_domain_translate//翻译硬件和软件irq
这里解释上面:
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
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)
static const struct of_device_id __of_table_##name\
__used __section(__##table##_of_table)\
= { .compatible = compat,\
.data = (fn == (fn_type)NULL) ? fn : fn }
static const struct of_device_id __of_table_cortex_a9_gic
__used __section(irqchip_of_table)
{
.compatible ="arm,cortex-a9-gic";
.data = gic_of_init;
}