一、一级中断控制器处理流程
对于irq_desc
,内核有两种分配方法:
- 一次分配完所有
iqr_desc
- 按需分配(用到某个中断才分配它的
irq_desc
)
现在的内核基本使用第二种方法。
- 假设GIC可以向CPU发出16 ~ 1019号中断,这些数字被称为
hwirq
。0 ~ 15用于Process之间通信,比较特殊 - 假设要使用UART模块,它发出的中断连接到GIC的32号中断,分配的
irq_desc
序号为16 - 在
GIC domain
中会记录(32,16) - 那么注册中断时就是:
request_irq(16, ...)
,把处理程序注册进irqaction
- 发生UART中断时
- 程序从GIC中读取寄存器知道发生了32号中断,通过
GIC irq_domain
可以知道virq
为16 - 调用
irq_desc[16]
中的handlerA函数,它的作用是调用action链表中用户注册的函数
- 程序从GIC中读取寄存器知道发生了32号中断,通过
二、多级中断控制器处理流程
- 假设GPIO模块下有4个引脚,都可以产生中断,都连接到GIC的33号中断
- GPIO也可以看作一个中断控制器,对于它的4个中断
- 对于GPIO模块中0 ~ 3这四个
hwirq
,一般都会一下子分配四个irq_desc
- 假设这4个
irq_desc
的序号为100 ~ 103,在GPIOdomain
中记录(0, 100) (1,101) (2,102) (3,103) - 对于KEY,注册中断时就是:
request_irq(102, ...)
- 按下KEY时:
- 程序从GIC中读取寄存器知道发生了33号中断,通过
GIC irq_domain
可以知道virq为16 - 调用
irq_desc[16]
中的handleB函数- handleB读取GPIO寄存器,确定是GPIO里2号引脚发生中断
- 通过
GPIO irq_domain
可以知道virq
为102 - 调用
irq_desc[102]
中的handleA函数,它的作用是调用action链表中用户注册的函数
- 程序从GIC中读取寄存器知道发生了33号中断,通过
程序先是通过request_irq注册处理函数,和分配虚拟中断号,使得硬件中断号和虚拟中断号产生联系,并存储在irq_domain中。
当硬件触发时,CPU通过硬件中断号,判断哪个中断触发了,通过关联的软件中断号,找到对应的处理函数。
处理函数时,需要把对应的中断屏蔽住,处理完后再恢复。
有时候另一些情况时,像GPIO会有多个中断号,那么每个不同的中断号也会有不同的软件中断号,对应的处理函数也不一样。
三、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中的各个函数里实现
// drivers/irqchip/irq-gic.c
static const struct irq_chip gic_chip = {
.irq_mask = gic_mask_irq,
.irq_unmask = gic_unmask_irq,
.irq_eoi = gic_eoi_irq,
.irq_set_type = gic_set_type,
.irq_get_irqchip_state = gic_irq_get_irqchip_state,
.irq_set_irqchip_state = gic_irq_set_irqchip_state,
.flags = IRQCHIP_SET_TYPE_MASKED |
IRQCHIP_SKIP_SET_WAKE |
IRQCHIP_MASK_ON_SUSPEND,
};
irq_domain
:- 申请中断
- 在设备树里指定hwirq、flag,可以使用
irq_domain
的函数来解析设备树 - 根据hwirq可以分配virq,把(hwirq, virq)存入
irq_domain
中
- 在设备树里指定hwirq、flag,可以使用
- 发生中断时,从GIC读取hwirq,可以通过
irq_domain
找到virq,再找到处理函数
所以GIC用gic_chip_data
来表示,gic_chip_data
中重要的成员是:irq_chip
、irq_domain
- 申请中断