内核版本:linux-4.19.8
本文以s3c2440处理器为例,分析内核中断子系统具体函数调用过程。
一、中断控制子系统的初始化
1、irq_desc初始化,是对struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp这个数组的初始化,
start_kernel
early_irq_init();
int __init early_irq_init(void)
{
int count, i, node = first_online_node;
struct irq_desc *desc;
init_irq_default_affinity();
printk(KERN_INFO "NR_IRQS: %d\n", NR_IRQS);
desc = irq_desc;//irq_desc数组指针
count = ARRAY_SIZE(irq_desc);
for (i = 0; i < count; i++) {
desc[i].kstat_irqs = alloc_percpu(unsigned int);//每个cpu的irq统计数据
alloc_masks(&desc[i], node);
raw_spin_lock_init(&desc[i].lock);
lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
desc_set_defaults(i, &desc[i], node, NULL, NULL);//初始化每一项irq_desc
}
return arch_early_irq_init();
}
2、irq domain注册
在drivers/irqchip/irq-s3c24xx.c中存在这样一个函数,采用宏定义在段属性中,如下所示:
int __init s3c2410_init_intc_of(struct device_node *np,
struct device_node *interrupt_parent){
return s3c_init_intc_of(np, interrupt_parent,
s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
}
IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);
#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 }
展开为:
static const struct of_device_id __of_table_s3c2410_irq \
__used __section("__irqchip_of_table") \
= { .compatible = "samsung,s3c2410-irq", \
.data = s3c2410_init_intc_of }
它定义了一个of_device_id结构体, 段属性为"__irqchip_of_table", 在编译内核时这些段被放在__irqchip_of_table地址处。即__irqchip_of_table起始地址处,放置了一个或多个 of_device_id, 它含有compatible成员;设备树中的设备节点含有compatible属性,如果双方的compatible相同, 并且设备节点含有"interrupt-controller"属性,则调用of_device_id中的函数来处理该设备节点。所以: IRQCHIP_DECLARE 是用来声明设备树中的中断控制器的处理函数。
我们分析内核启动:
start_kernel
init_IRQ();
if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
irqchip_init();
of_irq_init(__irqchip_of_table);
of_irq_init
for_each_matching_node_and_match(np, matches, &match) //查找device node是否匹配__irqchip_of_table
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
list_add_tail(&desc->list, &intc_desc_list);
while (!list_empty(&intc_desc_list)) {
ret = desc->irq_init_cb(desc->dev,desc->interrupt_parent);//调用初始化函数,初始化处理器的父中断控制器
}
如上面分析所示,当内核启动在初始化IRQ时,发现设备树和__irqchip_of_table这个段属性中,双方的compatible相同, 并且设备节点含有"interrupt-controller"属性,则调用of_device_id中的函数来处理。即调用s3c2410_in