gic为每个中断维护着4个状态,inactive、pending、active、active and pending
The following states apply at each interface between the GIC and a connected processor:
Inactive: An interrupt that is not active or pending.
Pending: An interrupt from a source to the GIC that is recognized at asserted in hardware,or generated by software,and is waitting to be serviced by a target processor.
Active: An interrupt from a source to the GIC thar has been acknowledeged by a processor, and is beging serviced but has not completed.
Active and pending: A processor is servicing the interrupt and the GIC has a pending interrupt from the same source.
gic支持的中断类型有外设中断、软件中断。其中外设中断源来自于硬件,软件中断通过软件写gic寄存器产生的。
Peripheral interrupt This ia an interrupt asserted by a signal to th GIC.The GIC architecture defines the following types of perpheral interrupt:
Private Peripheral Interrupt(PPI):This is a peripheral interrupt that is specific to a single processor.
Shared Peripheral Interrupt(SPI): This is a peripheral interrunpt that the Distributor can route to any o a specified combination of processors.
Each peripheral interrupt is either:
Edge-triggered
This is an interrupt that is asserted on detection of a rising edeg of an interruptt signal and then,regardless of the state of the signal,remains asserted until it is cleared by by the conditions defined by this specification.
Level-sensitive
This is an interrupt that is asserted whenever the interrupt signal level is active,and deasserted whenever the level is not active.
Software-generated interrupt(SGI)
This is an interrupt generated by software writing to a GICD_SGIR register in the GIC.The system uses SGIs for interprocessor communication.
An SGI has edge-triggered properties. The software triggering of the interrupt is equivalent to the edge transition of the interrupt requeset signal.
When an SIG occurs in a multiprocessor implementation, the CPUID field in the Interrupt Acknowledeg Register,GICC_IAR, or the Aliased Interrupt Acknowledeg Register, GICC_AIAR,identifies the processor that requested the interrupt.
In an implementaion that includes the GIC Virtualization Extensions:
gic从逻辑上分为Distributor和CPU interface。Distributor是中断的统一入口,负责分发中断给具体的CPU。每个CPU都有一个CPU interface负责本CPU的中断屏蔽和抢占。
Distributor The Distributor block performs interrupt prioritization and distribution on the CPU interface blocks that connect to the processors in the system.
The Distributor block regisgers are identified by the GICD_prefix.
CPU Interfaces Each CPU interface block performs priority masking and prempting handling for a connected processor in the system
CPU interface block register are identified by the GICC_prefix.
When describing a GIC that includes the GIC Virtualization Extensions, a CPU interface is sometimes called a physical CPU interface, to avoid possibel confusion with cpu interface.
Distributor的编程接口主要有:
The Distributor provides a programming interface for:
参考连接:https://www.cnblogs.com/lvzh/p/15058027.html
Interrupt IDs
Interrupts from sources are identifiled usring ID numbers.Each CPU interface can set up to 1020 interrupts.The banking of SPIs and PPIs increase the total number of interrupts supported by the Distributor.
The GIC assigns interrupt ID numbers ID0-ID1019 as follows:
A banked interrupt is one where the Distributor can have multiple interrupts with the same ID.A banked interrupt is identified uniquely by its ID number and its associated CPU interface number. Of the banked interrupt IDS:
ID0-ID15 are used for SGIs
ID16-ID31 are used for PPIs
中断处理流程
When the GIC recognizes an interrupt request, it marks its state as pending.Regenerating a pending interrupt does not affect the state of the interrupt.
The GIC interrupt handling sequence is
其中第五步,CPU读取GICC_IAR
寄存器来响应该中断(一般是linux内核程序来读取寄存器),寄存器返回硬件中断号;第六步,CPU处理完中断后写GICC_EOIR
寄存器来通知CPU interface。
每一款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); ... };
参考:zhuanlan.zhihu.com/p/85353687
Group 0 physical interrupts are expected to be handled at the highest implemented Exceptionlevel.
Secure Group 1 physical interrupts are expected to handled at Secure EL1 or Secure EL2.
Non-secure Group 1 physical interrupts are excepted to handled at Non-secure EL1 or Non-secure EL2.
GICv3 使用 hierarchy 来标识一个具体的 core, 如下图是一个四层的结构(aarch64):
用
https://oss-emcsprod-public.modb.pro/wechatSpider/modb_20210802_1251295a-f365-11eb-a003-00163e068ecd.png
各个 affinity 的定义是根据 SOC 自己的定义,比如:
. .. ...