ARM中断控制器GIC
一颗SOC集成了大量的外设,如何有序的控制和响应这些中断呢?
不同体系结构对中断控制器有着不同的设计理念,但是其设计方法基本相同。ARM公司提供了一个通用中断控制器GIC(Generic Interrupt Controller)。目前最新版本的GIC规范是version 3/4,支持Armv8-A,Armv8-R,Armv9-A架构,version 2通常在ARMv7处理器中使用。
gic v2
中断状态
gic为每个中断维护着4个状态,inactive、pending、active、active and pending。
中断类型
gic支持的中断类型有外设中断、软件中断。其中外设中断源来自于硬件,软件中断是通过软件写gic寄存器产生的。
gic v2架构划分
gic从逻辑上分为Distributor和CPU interface。Distributor是中断的统一入口,负责分发中断给具体的CPU。每个CPU都有一个CPU interface负责本CPU的中断屏蔽和抢占的。
Distributor的编程接口主要有:
中断ID
中断处理流程
其中第五步,CPU读取GICC_IAR
寄存器来响应该中断(一般是linux内核程序来读取寄存器),寄存器返回硬件中断号;第六步,CPU处理完中断后写GICC_EOIR
寄存器来通知CPU interface。
硬件中断号与Linux软件中断号的映射
每一款ARM SOC在芯片设计阶段时,就会把各种中断和外设分配情况固定下来,因此对于底层软件来说,需要查询SOC的芯片手册来确定的外设的中断号。
随着芯片硬件的发展,使用直接映射的方式难以应对多个中断控制器级联的情况,Linux引入了irq domain的管理框架,irq domain框架可支持多个中断控制器并且完美地支持device tree机制。git_init_of->gic_init_bases->__irq_domain_add(),添加到全局变量irq_domain_list
。
注册中断的API函数request_irq()/requeset_threaded_irq()
是使用内核软件中断号,而不是硬件中断号,那它们是如何映射的呢?
一般通过调用核心函数irq_of_parse_and_map
来解析DTS中的硬件中断号,返回内核使用的IRQ中断号。
它初始化时在位图中寻找空闲的bit来分配描述符。
irq_of_parse_and_map()->irq_domain_alloc_irqs()->__irq_alloc_descs()->bitmap_find_next_zero_area()
在内核中有两种方式来分配struct irq_desc数据结构,一是内核配置了CONFIG_SPARSE_IRQ使用radix tree树结构来存储;二是采用数组的方式,定义一个全局的数组struct irq_desc irq_desc[NR_IRQS]
,每个中断对应一个元素。
struct irq_desc
包含struct irq_data
,其中irq是软件中断号,hwirq是硬件中断号,当这两个成员填写完成,即完成了硬件中断的注册。struct irq_data
包含struct irq_chip
,struct irq_chip
是硬件中断控制器操作的抽象接口,如使能/去使能、响应、完成等接口。
struct irq_data {
unsigned int irq;
unsigned long hwirq;
struct irq_chip *chip;
...
};
struct irq_chip {
const char *name;
unsigned int (*irq_startup)(struct irq_data *data);
void (*irq_shutdown)(struct irq_data *data);
void (*irq_enable)(struct irq_data *data);
void (*irq_disable)(struct irq_data *data);
void (*irq_ack)(struct irq_data *data);
void (*irq_mask)(struct irq_data *data);
void (*irq_mask_ack)(struct irq_data *data);
void (*irq_unmask)(struct irq_data *data);
void (*irq_eoi)(struct irq_data *data);
...
};
gic v3
gic V3变化点
-
扩展性
v2架构最多支持8个PE,v3架构通过redistributor组件来引入affinity routing机制可以支持更多的PE。 -
中断分组
Group 0 physical interrupts are expected to be handled at the highest implemented Exceptionlevel.
Secure Group 1 physical interrupts are expected to be handled at Secure EL1 or Secure EL2.
Non-secure Group 1 physical interrupts are excepted to be handled at Non-secure EL1 or Non-secure EL2. -
将cpu interface独立出来,用户可以将其设计在core内部
-
增加了LPI(Locality-specific Peripheral Interrupt),使用ITS(Interrupt Translation Service)来解析
v3逻辑架构图
- The Distributor provides the routing configuration for SPIs, and holds all the associated routing and priority
information. - The Redistributor provides the configuration settings for PPIs and SGIs.
- A Redistributor always presents the pending interrupt with the highest priority to the CPU interface in finite time.
- v3架构支持affinity routing,在MPIDR_EL1寄存器中,Aff3.Aff2.Aff1.Aff0。