原创文章,转载请注明出处.
Linux中断的初始化流程:
Linux kernel的启动入口是start_kernel(), 在init/main.c中,start_kernel()中有一系列初始化操作,比如:boot_cpu_init(),setup_arch(&command_line),mm_init()等, 本文主要分析init_IRQ()
__irqchip_of_table实际为静态定义好的一个section,其定义在驱动文件drivers/irqchip/irq-gic-v3.c中,定义方式为IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init)。
init_IRQ() arch/arm64/kernel/irq.c
->irqchip_init()
->of_irq_init(__irqchip_of_table);
{
struct device_node *np, *parent = NULL;
struct of_intc_desc *desc, *temp_desc;
初始化两个list, 分别为int-controller的list和int-controller-parent的list
INIT_LIST_HEAD(&intc_desc_list);
INIT_LIST_HEAD(&intc_parent_list);
定义一个struct device_node *np, 遍历dts中所有的node,如果和__irqchip_of_table匹配, 则说明
该node是一个int-controller。 以下是gic device node的例子:
arch/arm64/boot/dts/freescale/fsl-imx8qm.dtsi
gic: interrupt-controller@51a00000 {
compatible = "arm,gic-v3";
reg = <0x0 0x51a00000 0 0x10000>, /* GIC Dist */
<0x0 0x51b00000 0 0xC0000>; /* GICR (RD_base + SGI_base) */
#interrupt-cells = <3>;
interrupt-controller;
interrupts = <GIC_PPI 9
(GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
interrupt-parent = <&gic>;
};
for_each_matching_node_and_match(np, matches, &match)
{
如果当前节点不是interrupt-controller或者处于disabled状态,则继续遍历
if (!of_find_property(np, "interrupt-controller", NULL) || !of_device_is_available(np))
continue;
如果当前节点是interrupt-controller,分配一个struct of_intc_desc的结构体并初始化。
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
desc->irq_init_cb = match->data = gic_of_init;
desc->dev = of_node_get(np);
解析当前node的interrupt-parent, 如果是根中断控制器, 将interrupt_parent设为NULL
desc->interrupt_parent = of_irq_find_parent(np);
if (desc->interrupt_parent == np)
desc->interrupt_parent = NULL;
将该中断控制器加入intc_desc_list中
list_add_tail(&desc->list, &intc_desc_list);
}
while (!list_empty(&intc_desc_list))
{
找到root中断控制器
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list)
{