中断控制器声明宏`IRQCHIP_DECLARE`分析

中断控制器声明宏IRQCHIP_DECLARE分析

定义一个中断控制器的时候,一般使用这个宏,下面是分析这个宏是怎么将你定义的irqchip结构参与设备树匹配并最终被调用的。

#define IRQCHIP_DECLARE(name,compat,fn)
  • name 表示控制器名字
  • compat 匹配设备树中的compatible
  • fn 匹配后调用,类似于probe

实例展开

文件[/drivers/irqchip/irq-gic.c]中,以IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);为例,展开:

static const struct of_device_id __of_table_gic_400 __used __section(__irqchip_of_table) = {
	.compatible = "arm,gic-400", 
	.data = (gic_of_init == (of_init_fn_2)((void *)0)) ? gic_of_init : gic_of_init 
}
  • __used 就是__attribute__((used)),用来控制编译时不被优化掉未使用的结构体变量
  • __section(__irqchip_of_table) 展开就是__attribute__((__section__(__irqchip_of_table))), 用来控制链接时将结构体变量放入__irqchip_of_table

目前可以看到,这个宏的功能就是定义一个struct of_device_id结构体,根据宏参数初始化此结构体,并指定链接时放入__irqchip_of_table段中。

问题来了,这怎么就能参与设备树中中断控制器节点的匹配了呢?

irqchip初始化

先从文件[drivers/irqchip/irqchip.c]中的初始化代码分析,
在这里插入图片描述

  • 外部引用了__irqchip_of_table数组符号,这个符号并不是在C代码中定义的,打开内核链接脚本vmlinux.lds,可以找到:

    .init.data :  ...略... 
    __irqchip_of_table = .;
    KEEP(*(__irqchip_of_table)) KEEP(*(__irqchip_of_table_end)) . = ALIGN(8);
    

    __irqchip_of_table数组符号是在此处被定义的,而#define IRQCHIP_DECLARE(name,compat,fn)宏定义的irqchip控制器数据结构都是放在__irqchip_of_table数组符号的后面,并且最末尾放置上述C文件中定义的__irqchip_of_table_end,这是此段最后一个struct of_device_id数据。

  • 回来接着分析,irqchip_init初始化函数中,将所有IRQCHIP_DECLARE定义的irq控制器组成的数组指针传入of_irq_init函数

    void __init of_irq_init(const struct of_device_id *matches)
    {
    	// ...略...
    	// 遍历设备树中与matches元素compatible匹配的节点
    	for_each_matching_node_and_match(np, matches, &match) {
    		// 要求设备树节点中定义属性"interrupt-controller"
    		if (!of_property_read_bool(np, "interrupt-controller") ||
    				!of_device_is_available(np))
    			continue;
    		// ...略...
    		// 组装设备树中断描述结构(struct of_intc_desc *desc)链表
    		// 每一项包含设备树对应device_node、父device_node、init_cb
    		desc->irq_init_cb = match->data; // 从of_device_id中取init_cb
    		desc->dev = of_node_get(np);
    		desc->interrupt_parent = of_irq_find_parent(np); // 通过此节点中是否指定"interrupt-parent",并且指定节点中是否定义"#interrupt-cells"来判断
    		// ...略...
    		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) {
    			int ret;
    			// 这里保证处理最终的父节点
    			if (desc->interrupt_parent != parent)
    				continue;
    			list_del(&desc->list);
    			// ...略...
    			// 这里调用init_cb
    			ret = desc->irq_init_cb(desc->dev,
    						desc->interrupt_parent);
    			// ...略...
    		}
    		// ...略...
    	}
    	// ...略...
    }
    
  • 可以看到,基本就是将IRQCHIP_DECLARE注册的数组,和设备树进行匹配,匹配成功的元素,被调用其注册init_cb的回调

总结

  • IRQCHIP_DECLARE此宏是定义了一个struct of_device_id结构体
  • 此结构体通过控制链接属性被放到内核链接脚本中定义的符号__irqchip_of_table下面
  • 内核启动时,此符号被irqchip_init代码以extern的方式作为数组访问,传入of_irq_init初始化流程
  • 而后将此数组与设备树进行匹配(通过compatibleinterrupt-controllerinterrupt-parent#interrupt-cells等限制信息)
  • 匹配后的项目中被调用init_cb回调
  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值