http://www.wowotech.net/irq_subsystem/interrupt_subsystem_architecture.html
https://www.bilibili.com/video/BV1bD4y127dg?from=search&seid=11165508187878472473
BiliBili作者博客https://blog.csdn.net/weixin_42135087/category_9540436.html
https://blog.csdn.net/sunsissy/article/details/73791470
https://zhuanlan.zhihu.com/p/363129733
依据BiliBili视频整理的GIC中断笔记
general interrupt controller
GIC中断控制器的分类:gicv1(已弃用),gicv2,gicv3,gicv4.
比如RK3288的中断控制器gic-v400,就是支持gicv2架构版本
rk3288.dtsi
gic: interrupt-controller@ffc01000 {
compatible = "arm,gic-400";
interrupt-controller;
#interrupt-cells = <3>;
#address-cells = <0>;
reg = <0x0 0xffc01000 0x0 0x1000>,
<0x0 0xffc02000 0x0 0x2000>,
<0x0 0xffc04000 0x0 0x2000>,
<0x0 0xffc06000 0x0 0x2000>;
interrupts = <GIC_PPI 9 0xf04>;
};
gic的的核心功能,就是对soc中外设的中断源的管理,并且提供给软件,配置以及控制这些中断源.
如果没有GIC,那么外部的所有中断都需要直接连线到CPU,又gic,中断先到gic,处理后再到CPU,
1.当对应的中断源有效时,GIC根据该中断源的配置,决定是否将该中断信号,发生给cpu,如果有多个中断源有效,那么gic还会锦绣仲裁.选择最高优先级中断,发送给CPU.
2.当CPU接受到gic发送的中断,通过读取gic的寄存器,就可以知道,中断源的来源来自哪里,从而可以做相应的处理.
3.当CPU处理完中断之后,会告诉GIC,其实就是访问gic的寄存器,该中断处理完毕.gic接受到该信息后,就将该中断源取消.避免又重新发送该中断给cpu以及允许中断抢占.
ARM-Core访问gic寄存器的两种方式:
1.memory-mapped的方式:SOC在设计的时候,预留了一块区域给gic,ARM-CORE通过读写该地址来读写gic寄存器.
2.通过系统寄存器的方式:通过MSR/MRS来进行读写
gicv2的所有寄存器都是适用memory-map方式.
从gicv2架构图,可以,gic中的中断类型有:
SGI:软件中断,0~15(一般0-7给REF,8~15给TEE),相当于IPI,CPU core之间中断,通过向ICDSGIR寄存器写入SGI中断号/CPU ID,来产生一个软件中断.
PPI:私有外设中断,16~31,发送给特定CPU,每个CPU连接5个私有中断,
SPI:共享外设中断,32~1019,可以多个CPU或者core处理,不限定特定CPU,由各种IO控制器和存储器控制器产生,如 GPIO/DMA/定时器等.
虚拟中断:用于支持虚拟机
中断类型:边沿触发&电平触发
Group分组:
group0:安全中断,由nFIQ驱动
group1:非安全中断,由nFIQ驱动
gicv2的旁路/bypass功能:
GICV2支持中断旁路模式,也就是GPIO外部的FIQ,IRQ直接接到core的FIQ,IRQ上,相当于gic是不使能的.
GICV2资产bypass功能,gic不起作用,core的中断管脚,直接由soc的其他部门信号驱动.
Linux内核中断管理:
以SPI中断为例:
当中断产生后,中断信号传送给gic,gic组件进行管理和仲裁,然后再将中断信息 发送给响应的CPU,CPU随后进行FIQ IRQ 异常程序.然后跳到irq_handler->gic_handle_irq()
中断底半部实现
tasklet:执行在软中断上下文中(不可睡眠和调度)
在中断函数里调用tasklet_schedule(),会在适当的时候执行my_tasklet_func
工作队列:执行在内核线程上下文(可以睡眠和调度)
软中断(softirq):定时器/网络/块设备/RCU等
thread_irq:request_thread_irq()