一 init_IRQ
本文以arm,gic-v3兼容的中断控制器为例,介绍中断控制器的初始化过程。
1.0 init_IRQ
定义在arch/arm64/kernel/irq.c中
void __init init_IRQ(void)
{
irqchip_init();
if (!handle_arch_irq)
panic("No interrupt controller found.");
}
void __init irqchip_init(void)
{
of_irq_init(__irqchip_begin);
}
// 在drivers/irqchip/irq-gic-v3.c中
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
// 在drivers/irqchip/irqchip.h中
#define IRQCHIP_DECLARE(name,compstr,fn) \
static const struct of_device_id irqchip_of_match_##name \
__used __section(__irqchip_of_table) \
= { .compatible = compstr, .data = fn }
// 在include\asm-generic\vmlinux.lds.h中
VMLINUX_SYMBOL(__irqchip_begin) = .; \
*(__irqchip_of_table) \
*(__irqchip_of_end)
以上三个宏实际上定义了一个
static const struct of_device_id irqchip_of_match_gic_v3 __used __section(__irqchip_of_table) = { .compatible = "arm,gic-v3", .data = gic_of_init }
而irqchip_of_match_gic_v3保存在__irqchip_of_table
device tree中包含中断控制器node为
intc: interrupt-controller@09bc0000 {
compatible = "arm,gic-v3";
reg = <0x9bc0000 0x10000>, /* GICD */ // GIC Distributor interface
<0x9c00000 0x100000>; /* GICR * 4 */ // GIC Redistributors
#interrupt-cells = <3>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
interrupt-controller;
#redistributor-regions = <1>;
redistributor-stride = <0x0 0x40000>;
interrupts = <1 9 4>;
gic-its@09BE0000 {
compatible = "arm,gic-v3-its";
msi-contoller;
reg = <0x9be0000 0x20000>;
};
};
1.1 of_irq_init
void __init of_irq_init(const struct of_device_id *matches)
{
struct device_node *np, *parent = NULL;
struct intc_desc *desc, *temp_desc;
struct list_head intc_desc_list, intc_parent_list;
INIT_LIST_HEAD(&intc_desc_list);
INIT_LIST_HEAD(&intc_parent_list);
for_each_matching_node(np, matches) { // 遍历device tree找到与arm,gic-v3兼容的中断控制器node
if (!of_find_property(np, "interrupt-controller", NULL))
continue;
/*
* Here, we allocate and populate an intc_desc with the node
* pointer, interrupt-parent device_node etc.
*/
desc = kzalloc(sizeof(*desc), GFP_KERNEL); // 从内存中分配中断控制器描述符
if (WARN_ON(!desc))
goto err;
desc->dev = np; // 为中断控制器描述的device_node赋值