一、GIC介绍
GIC(Generic Interrupt Controller)
是ARM
公司提供的一个通用的中断控制器,目前有4个版本GICv1 ~ GICv4
(GICv1
已弃用;GICv2
最多支持8个ARM Core
;GICv3/GICv4
支持更多的ARM Core
)。
GIC
的核心功能:对SOC
中外设的中断源的管理,并提供给软件,配置以及控制这些中断源。当对应的中断源有效时,GIC
根据中断源配置,决定是否将该中断信号发给CPU
。如果有多个中断源有效,那么GIC
还会进行仲裁,选择最高优先级中断,发送给CPU
。当CPU
接收到GIC
发送的中断,通过读取GIC
的寄存器,可以知道中断的来源,从而做对应的处理。当CPU
处理完中断后,会配置GIC
寄存器,表示该中断已处理完毕。GIC
接收到信息后,就将该中断源取消,避免又重新发送该中断给CPU
,以及允许中断抢占。
二、GIC IP
对于不同的GIC
版本,ARM
公司设计了对应的GIC IP
。
1)GIC-400
:支持GICv2
版本。
2)GIC-500
:支持GICv3
版本。
3)GIC-600
:支持GICv3
版本。
4)GIC-700
:支持GICv3/GICv4.1
版本。
CPU
和GIC
之间兼容性见下图:
三、GIC框架
GICv3
架构包括:
1、Distributor
Distributor
:SPI
外设中断分发器,外设经特定硬件中断线连接到Distributor
。Distributor
判断SPI
中断的优先级,决定优先处理哪个中断,使用中断重映射表决定中断的目的PE
,同时维护中断的active/pending/acknowledged
状态。
2、Redistributor
Redistributor
:管理SGI/PPI/LPI
中断,决定他们的优先级,触发方式,控制他们的状态,以及enable/disable
特定中断。
3、CPU interface
CPU interface
:传输中断给Core
。每个Redistributor
连接一个CPU interface
,它负责打开和关闭PE
的中断处理能力,acknowledge
中断,为PE
维护一个中断优先级掩码(只响应更高优先级中断),定义中断抢占策略,执行中断降级。
4、ITS
ITS(Interrupt Translation Service)
:接收LPI
消息中断,根据消息携带的event id
和device id
,翻译得到物理中断线以及目标PE
。ITS
与device
之间通过系统总线连接,device
采用内存地址的形式发一个中断消息给ITS
。
5、 PE
PE(Process element)
处理器单元,中断的最终接收者和处理者。
GICv2
比GICv3
少了Redistributor
和ITS
等功能。
GICv4
与GICv3
的功能基本相同,增加了直接注入虚拟中断的能力。
四、GIC中断类型
GIC
中断类型包括:
1、 SGI(Software Generated Interrupt)
软中断,主要用于核间通信,通过写SGI
寄存器产生。
2、PPI(Private Peripheral Interrupt)
私有外设中断,为某个核的私有中断。例(arch/arm64/boot/dts/rockchip/rk3399.dtsi
):
# RK3399小核CortexA53 pmu PPI中断
pmu_a53 {
compatible = "arm,cortex-a53-pmu";
interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster0>;
};
# RK3399大核CortexA72 pmu PPI中断
pmu_a72 {
compatible = "arm,cortex-a72-pmu";
interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_LOW &ppi_cluster1>;
};
...
# ARMV8 timer PPI中断
timer {
compatible = "arm,armv8-timer";
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW 0>,
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW 0>,
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW 0>,
<GIC_PPI 10 IRQ_TYPE_LEVEL_LOW 0>;
arm,no-tick-in-suspend;
};
3、SPI(Shared Peripheral Interrupt)
共享外设中断,外设中断可以发送到任何一个连接的core
。例(arch/arm64/boot/dts/rockchip/rk3399.dtsi
):
# RK3399 uart SPI中断
uart0: serial@ff180000 {
compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
reg = <0x0 0xff180000 0x0 0x100>;
clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>;
clock-names = "baudclk", "apb_pclk";
interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH 0>;
reg-shift = <2>;
reg-io-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>;
status = "disabled";
};
4、 LPI(Locality-specific Peripheral Interrupt)
特定区域外设中断。只在GICv3
和GICv4
上支持。
不同中断类型的INITD
范围如下:
注:目前Linux内核驱动中,使用的是IRQ中断,没有使用FIQ中断,同时禁止IRQ中断嵌套。
五、GIC中断触发方式
GIC
中断触发方式包括:
1、edge-triggered interrupt
边沿触发中断。支持的中断类型有:SGI/PPI/SPI/LPI
。
2、 level-sensitive interrupt
电平触发中断。支持的中断类型有:PPI/SPI
。
注:GICv2/v3 SPI中断只支持上升沿或高电平触发。
代码如下:
drivers/irqchip/irq-gic-v3.c
static int gic_set_type(struct irq_data *d, unsigned int type)
{
unsigned int irq = gic_irq(d);
void (*rwp_wait)(void);
void __iomem *base;
/* Interrupt configuration for SGIs can't be changed */
if (irq < 16)
return -EINVAL;
## GICv3 SPI只支持高电平和上升沿触发中断
/* SPIs have restrictions on the supported types */
if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
...
}
drivers/irqchip/irq-gic.c
static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d);
/* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16)
return -EINVAL;
## GICv2 SPI只支持高电平和上升沿触发中断
/* SPIs have restrictions on the supported types */
if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
...
}
六、GIC中断状态
GIC
中断状态包括:
1、 Inactive
该中断源当前无效,未发生中断。
2、 Pending
已产生中断,未被PE
响应。
3、 Active
该中断源已经发生并且已被PE响应。
4、 Active and pending
这个中断已被响应,再一次的中断正在被pending
。
GIC
中断处理状态机如下:
七、GIC中断周期
GIC
中断处理基于GIC
中断生命周期,中断生命周期为描述中断处理过程,包括:
1、Generate interrupt
外设或软件产生一个中断。
2、Distribute
IRI(Interrupt Router Interface)
实现中断分组、中断优先级控制、并控制中断转发到CPU
接口。PPI/SGI
是各个Core
独有的中断,不参与目的Core
仲裁。SPI
是所有Core
共享的,根据配置决定中断发往的Core
。最后选择优先级最高的中断发给CPU interface
。寄存器用GICD_
做前缀。
3、Deliver
CPU
接口将中断发给PE
。将GICD
发送的中断信息,通过IRQ、FIRQ
引脚传输给Core
。寄存器使用GICC_
做前缀。
4、Activate
PE
通过读取GICC_IAR
寄存器识别中断,设置最高优先级的SGI/PPI/SPI
中断为激活状态。
5、Priority drop
PE
通过配置GICC_EOIR
寄存器,实现优先级重置。
6、Deactivation
PE
通过配置GICC_DIR
寄存器,使该中断无效。
中断生命周期流程如下:
image.png参考:
https://developer.arm.com/documentation/ka002107/1-0
IHI0048B_b_gic_architecture_specification.pdf
IHI0069H_gic_architecture_specification.pdf
网友评论