1
| IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
|
声明irqchip与初始化函数的关联,兼容GIC-V2的GIC实现有很多,不过其初始化函数都是一个。在linux kernel编译的时候,你可以配置多个irq chip进入内核,编译系统会把所有的IRQCHIP_DECLARE宏定义的数据放入到一个特殊的section中(section name是__irqchip_of_table
),我们称这个特殊的section叫做irq chip table
。这个table也就保存了kernel支持的所有的中断控制器的ID信息(最重要的是驱动代码初始化函数和DT compatible string)
IRQCHIP_DECLARE宏定义
1 2
| #define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| #define _OF_DECLARE(table, name, compat, fn, fn_type) \ static const struct of_device_id __of_table_##name \ __used __section(__##table##_of_table) \ __aligned(__alignof__(struct of_device_id)) \ = { .compatible = compat, \ .data = (fn == (fn_type)NULL) ? fn : fn }
typedef int (*of_init_fn_2)(struct device_node *, struct device_node *);
#define OF_DECLARE_2(table, name, compat, fn) \ _OF_DECLARE(table, name, compat, fn, of_init_fn_2)
|
IRQCHIP_DECLARE
宏展开后
1 2 3 4 5 6 7
| static const struct of_device_id __of_table_gic_400 __used __section(__irqchip_of_table) //编译时将定义的of_device_id结构体添加到irqchip_of_table section中 __aligned(__alignof__(struct of_device_id)) = { .compatible = "arm,gic-400", .data = gic_of_init }
|
将初始化的of_device_id
结构体插入到irqchip_of_table
section中
irqchip_of_table段的定义
1 2 3 4 5 6 7 8 9
| /* arch/arm64/kernel/vmlinux.lds.S */ .init.data : { INIT_DATA //添加init section INIT_SETUP(16) INIT_CALLS CON_INITCALL INIT_RAM_FS *(.init.rodata.* .init.bss) /* from the EFI stub */ }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#define INIT_DATA \ ... IRQCHIP_OF_MATCH_TABLE() \ ...
#define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) #define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name) #define OF_TABLE(cfg, name) __OF_TABLE(IS_ENABLED(cfg), name) #define _OF_TABLE_0(name) #define _OF_TABLE_1(name) \ . = ALIGN(8); \ __##name##_of_table = .; \ KEEP(*(__##name##_of_table)) \ KEEP(*(__##name##_of_table_end))
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
|
IRQCHIP_OF_MATCH_TABLE
宏展开
1 2 3 4
| . = ALIGN(8); __irqchip_of_table = .; KEEP(*(irqchip_of_table)) KEEP(*(irqchip_of_table_end))
|
KEEP
: 链接器关键字,防止被优化ALIGN
: 表示字节对其
IRQCHIP_DECLARE
宏定义的的数据结构将直接插入到.init.data
段中的irqchip_of_table
解析irqchip_of_table段
定义并初始化完后,何时如何被解析使用。
1 2 3
| start_kernel \-> init_IRQ \-> irqchip_init
|
1 2 3 4 5 6
| void __init irqchip_init(void) { of_irq_init(__irqchip_of_table); acpi_probe_device_table(irqchip); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
void __init of_irq_init(const struct of_device_id *matches) {
for_each_matching_node_and_match(np, matches, &match) { ... desc->irq_init_cb = match->data; desc->dev = of_node_get(np); desc->interrupt_parent = of_irq_find_parent(np); if (desc->interrupt_parent == np) desc->interrupt_parent = NULL; list_add_tail(&desc->list, &intc_desc_list); }
while (!list_empty(&intc_desc_list)) { list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { ... ret = desc->irq_init_cb(desc->dev, desc->interrupt_parent); ... list_add_tail(&desc->list, &intc_parent_list); } } }
|