我们现在的项目使用的中断控制器是gicv3的,对应的型号有gic500/600。下面主要介绍gicv3控制器的kernel初始化流程。
gic: interrupt-controller@12000000 {
compatible = "arm,gic-v3"; 驱动名字匹配字符串
#interrupt-cells = <3>; /*interrupts用3个int描述 */
#address-cells = <2>;
#size-cells = <2>;
ranges;
redistributor-stride = <0x0 0x20000>; /* 128KB stride */
#redistributor-regions = <1>;
interrupt-controller; /*声明本设备是中断寄存器*/
reg = <0x0 0x12000000 0 0x20000>, /* GICD */
<0x0 0x12040000 0 0x100000>; /* GICR */
interrupts = <1 9 4>; /*中断类型(PPI) 硬件中断号 高电平触发*/
v2m_0: v2m@0 { /*基于消息的中断,暂时不介绍*/
compatible = "arm,gic-v2m-frame";
msi-controller;
reg = <0 0 0 0x1000>;
};
};
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
用宏静态定义的结构体,一般在编译的时候都由lds文件指定了节位置,将上述宏解开后是下面的样子。
static const struct of_device_id __of_table_gic_v3 \
__used __section(__irqchip _of_table) \
= { .compatible = "arm,gic-v3", \
.data = gic_of_init }
具体节位置编译后结果在obj\kernel\arch\arm64\kernel\vmlinux.lds
.init.data : {
... __irqchip_of_table = .; KEEP(*(__irqchip_of_table)) KEEP(*(__irqchip_of_table_end)) . = ALIGN(8);...
}
代码调用流程start_kernel-->init_IRQ-->irqchip_init-->of_irq_init-->gic_of_init
其中of_irq_init就是来match设备树中声明自己是中断控制器设备和gic_v3驱动程序的代码流程。最终找到gicv3的驱动程序,并调用它的初始化函数gic_of_init
void __init irqchip_init(void)
{
of_irq_init(__irqchip_of_table); //传入节的起始地址
acpi_probe_device_table(irqchip); acpi电源管理接口
}
void