今天呢,我们就来具体的讲一下GIC的驱动源码啦,这个才是重点来着,我们来看看:
GIC中的重要函数和结构体:
沿着中断的处理流程,GIC涉及这4个重要部分:
-
CPU从异常向量表中调用handle_arch_irq,这个函数指针是有GIC驱动设置的
-
GIC才知道怎么判断发生的是哪个GIC中断
-
-
从GIC获得hwirq后,要转换为virq:需要有GIC Domain
-
调用irq_desc[virq].handle_irq函数:这也应该由GIC驱动提供
-
处理中断时,要屏蔽中断、清除中断等:这些函数保存在irq_chip里,由GIC驱动提供
从硬件上看,GIC的功能是什么?
-
可以使能、屏蔽中断
-
发生中断时,可以从GIC里判断是哪个中断
在内核里,使用gic_chip_data结构体表示GIC,gic_chip_data里有什么?
-
irq_chip:中断使能、屏蔽、清除,放在irq_chip中的各个函数里实现
-
irq_domain
-
申请中断时
-
在设备树里指定hwirq、flag,可以使用irq_domain的函数来解析设备树
-
根据hwirq可以分配virq,把(hwirq, virq)存入irq_domain中
-
-
发生中断时,从GIC读出hwirq,可以通过irq_domain找到virq,从而找到处理函数
-
所以,GIC用gic_chip_data来表示,gic_chip_data中重要的成员是:irq_chip、irq_domain。
GIC初始化过程:
内核支持多种GIC:
按照设备树的套路:
-
驱动程序注册platform_driver
-
它的of_match_table里有多个of_device_id,表示能支持多个设备
-
有多种版本的GIC,在内核为每一类GIC定义一个结构体of_device_id,并放在一个段里:
把宏IRQCHIP_DECLARE
展开:
在设备树里指定GIC:
在设备树中指定GIC,内核驱动程序根据设备树来选择、初始化GIC。
drivers\irqchip\irqchip.c
中并没有定义一个platform_driver,但是套路是一样的。
调用过程:
of_irq_init:
-
内核有一个__irqchip_of_table数组,里面有多个of_device_id,表示多种GIC
-
要使用哪类GIC?在设备树里指定
-
根据设备树,找到__irqchip_of_table树组中对应的项,调用它的初始化函数
-
IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
-
申请GIC中断:
在设备树里指定中断:
内核对设备树的处理:
函数调用过程如下,使用图片形式可以一目了然:
函数调用过程如下,使用文字格式方便复制:
-
为设备树节点分配设备
解析设备树映射中断: irq_of_parse_and_map
下面我们来看看图片来进行分析:
首先的话,就是GIC去遍历自己的寄存器,判断发生了哪个中断,这个是在中断向量表里面的,汇编来着,小编也没有很明白(唯唯诺诺)
第二个就是那个irq_domain的关系是怎么去建立的,
他会调用里面的translate函数,去解析设备树
然后为他的hwirq找到一个空闲的virq,然后记录在domain里面,最后去调用domain里面的alloc函数去处理
allow主要是包括建立mapping关系,然后就是就是注册那些irq_data,这些在前面已经定义好了
这边就是提供irq_chip了,那么到这里,我们就彻底讲完啦,其实GIC也没有想象的那么复杂,逻辑性很强,嘿嘿,完结,撒花(doge.)