完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
这里主要分析 linux kernel 中 GIC v3 中断控制器的代码(drivers/irqchip/irq-gic-v3.c)。 设备树 先来看下一个中断控制器的设备树信息: gic: interrupt-controller@51a00000 { compatible = "arm,gic-v3"; reg = <0x0 0x51a00000 0 0x10000>, /* GIC Dist */ <0x0 0x51b00000 0 0xC0000>, /* GICR */ <0x0 0x52000000 0 0x2000>, /* GICC */ <0x0 0x52010000 0 0x1000>, /* GICH */ <0x0 0x52020000 0 0x20000>; /* GICV */ #interrupt-cells = <3>; interrupt-controller; interrupts =
初始化 1. irq chip driver 的声明: IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);定义 IRQCHIP_DECLARE 之后,相应的内容会保存到 __irqchip_of_table 里边: #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 __p(__##table##_of_table) = { .compatible = compat, .data = (fn == (fn_type)NULL) ? fn : fn }__irqchip_of_table 在链接脚本 vmlinux.lds 里,被放到了 __irqchip_begin 和 __irqchip_of_end 之间,该段用于存放中断控制器信息: #ifdef CONFIG_IRQCHIP #define IRQCHIP_OF_MATCH_TABLE() . = ALIGN(8); VMLINUX_SYMBOL(__irqchip_begin) = .; *(__irqchip_of_table) *(__irqchip_of_end)#endif在内核启动初始化中断的函数中,of_irq_init 函数会去查找设备节点信息,该函数的传入参数就是 __irqchip_of_table 段,由于 IRQCHIP_DECLARE 已经将信息填充好了,of_irq_init 函数会根据 “arm,gic-v3” 去查找对应的设备节点,并获取设备的信息。or_irq_init 函数中,最终会回调 IRQCHIP_DECLARE 声明的回调函数,也就是 gic_of_init,而这个函数就是 GIC 驱动的初始化入口。 2. gic_of_init 流程: static int __init gic_of_init(struct device_node *node, struct device_node *parent){ ...... dist_base = of_iomap(node, 0); ------(1) if (!dist_base) { pr_err("%pOF: unable to map gic dist registersn", node); return -ENXIO; } err = gic_validate_dist_version(dist_base); ------(2) if (err) { pr_err("%pOF: no distributor detected, giving upn", node); goto out_unmap_dist; } if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions)) ------(3) nr_redist_regions = 1; rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL); if (!rdist_regs) { err = -ENOMEM; goto out_unmap_dist; } for (i = 0; i < nr_redist_regions; i++) { ------(4) struct resource res; int ret; ret = of_address_to_resource(node, 1 + i, &res); rdist_regs.redist_base = of_iomap(node, 1 + i); if (ret || !rdist_regs.redist_base) { pr_err("%pOF: couldn't map region %dn", node, i); err = -ENODEV; goto out_unmap_rdist; } rdist_regs.phys_base = res.start; } if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) ------(5) redist_stride = 0; err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, ------(6) redist_stride, &node->fwnode); if (err) goto out_unmap_rdist; gic_populate_ppi_partitions(node); ------(7) gic_of_setup_kvm_info(node); return 0; ...... return err;}
当早期的系统只存在一个中断控制器,而且中断数目也不多的时候,一个很简单的做法就是一个中断号对应到中断控制器的一个号,可以说是简单的线性映射: 但当一个系统中有多个中断控制器,而且中断号也逐渐增加的时候。linux 内核为了应对此问题,引入了 irq_domain 的概念。 irq_domain 的引入相当于一个中断控制器就是一个 irq_domain。这样一来所有的中断控制器就会出现级联的布局。利用树状的结构可以充分的利用 irq 数目,而且每一个 irq_domain 区域可以自己去管理自己 interrupt 的特性。 每一个中断控制器对应多个中断号, 而硬件中断号在不同的中断控制器上是会重复编码的, 这时仅仅用硬中断号已经不能唯一标识一个外设中断,因此 linux kernel 提供了一个虚拟中断号的概念。 |
|
|
|
只有小组成员才能发言,加入小组>>
3274 浏览 9 评论
2950 浏览 16 评论
3453 浏览 1 评论
8980 浏览 16 评论
4042 浏览 18 评论
1092浏览 3评论
564浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
560浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2297浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1854浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-17 16:23 , Processed in 1.270293 second(s), Total 78, Slave 58 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号