- UID
- 1029342
- 性别
- 男
|
一、前言
GIC(Generic Interrupt Controller)是ARM公司提供的一个通用的中断控制器,其architecture specification目前有四个版本,V1~V4(V2最多支持8个ARM core,V3/V4支持更多的ARM core,主要用于ARM64服务器系统结构)。目前在ARM官方网站只能下载到Version 2的GIC architecture specification,因此,本文主要描述符合V2规范的GIC硬件及其驱动。
具体GIC硬件的实现形态有两种,一种是在ARM vensor研发自己的SOC的时候,会向ARM公司购买GIC的IP,这些IP包括的型号有:PL390,GIC-400,GIC-500。其中GIC-500最多支持128个 cpu core,它要求ARM core必须是ARMV8指令集的(例如Cortex-A57),符合GIC architecture specification version 3。另外一种形态是ARM vensor直接购买ARM公司的Cortex A9或者A15的IP,Cortex A9或者A15中会包括了GIC的实现,当然,这些实现也是符合GIC V2的规格。
本文在进行硬件描述的时候主要是以GIC-400为目标,当然,也会顺便提及一些Cortex A9或者A15上的GIC实现。
本文主要分析了linux kernel中GIC中断控制器的驱动代码(位于drivers/irqchip/irq-gic.c和irq-gic-common.c)。 irq-gic-common.c中是GIC V2和V3的通用代码,而irq-gic.c是V2 specific的代码,irq-gic-v3.c是V3 specific的代码,不在本文的描述范围。本文主要分成三个部分:第二章描述了GIC V2的硬件;第三章描述了GIC V2的初始化过程;第四章描述了底层的硬件call back函数。
注:具体的linux kernel的版本是linux-3.17-rc3。
二、GIC-V2的硬件描述
1、GIC-V2的输入和输出信号
(1)GIC-V2的输入和输出信号示意图
要想理解一个building block(无论软件还是硬件),我们都可以先把它当成黑盒子,只是研究其input,output。GIC-V2的输入和输出信号的示意图如下(注:我们以GIC-400为例,同时省略了clock,config等信号):
(2)输入信号
上图中左边就是来自外设的interrupt source输入信号。分成两种类型,分别是PPI(Private Peripheral Interrupt)和SPI(Shared Peripheral Interrupt)。其实从名字就可以看出来两种类型中断信号的特点,PPI中断信号是CPU私有的,每个CPU都有其特定的PPI信号线。而SPI是所有CPU之间共享的。通过寄存器GICD_TYPER可以配置SPI的个数(最多480个)。GIC-400支持多少个SPI中断,其输入信号线就有多少个SPI interrupt request signal。同样的,通过寄存器GICD_TYPER也可以配置CPU interface的个数(最多8个),GIC-400支持多少个CPU interface,其输入信号线就提供多少组PPI中断信号线。一组PPI中断信号线包括6个实际的signal:
(a)nLEGACYIRQ信号线。对应interrupt ID 31,在bypass mode下(这里的bypass是指bypass GIC functionality,直接连接到某个processor上),nLEGACYIRQ可以直接连到对应CPU的nIRQCPU信号线上。在这样的设置下,该CPU不参与其他属于该CPU的PPI以及SPI中断的响应,而是特别为这一根中断线服务。
(b)nCNTPNSIRQ信号线。来自Non-secure physical timer的中断事件,对应interrupt ID 30。
(c)nCNTPSIRQ信号线。来自secure physical timer的中断事件,对应interrupt ID 29。
(d)nLEGACYFIQ信号线。对应interrupt ID 28。概念同nLEGACYIRQ信号线,不再描述。
(e)nCNTVIRQ信号线。对应interrupt ID 27。Virtual Timer Event,和虚拟化相关,这里不与描述。
(f)nCNTHPIRQ信号线。对应interrupt ID 26。Hypervisor Timer Event,和虚拟化相关,这里不与描述。
对于Cortex A15的GIC实现,其PPI中断信号线除了上面的6个,还有一个叫做Virtual Maintenance Interrupt,对应interrupt ID 25。
对于Cortex A9的GIC实现,其PPI中断信号线包括5根:
(a)nLEGACYIRQ信号线和nLEGACYFIQ信号线。对应interrupt ID 31和interrupt ID 28。这部分和上面一致。
(b)由于Cortext A9的每个处理器都有自己的Private timer和watch dog timer,这两个HW block分别使用了ID 29和ID 30
(c)Cortext A9内嵌一个global timer为系统内的所有processor共享,对应interrupt ID 27
关于private timer和global timer的描述,请参考时间子系统的相关文档。
关于一系列和虚拟化相关的中断,请参考虚拟化的系列文档。
(3)输出信号
所谓输出信号,其实就是GIC和各个CPU直接的接口,这些接口包括:
(a)触发CPU中断的信号。nIRQCPU和nFIQCPU信号线,熟悉ARM CPU的工程师对这两个信号线应该不陌生,主要用来触发ARM cpu进入IRQ mode和FIQ mode。
(b)Wake up信号。nFIQOUT和nIRQOUT信号线,去ARM CPU的电源管理模块,用来唤醒CPU的
(c)AXI slave interface signals。AXI(Advanced eXtensible Interface)是一种总线协议,属于AMBA规范的一部分。通过这些信号线,ARM CPU可以和GIC硬件block进行通信(例如寄存器访问)。
(4)中断号的分配
GIC-V2支持的中断类型有下面几种:
(a)外设中断(Peripheral interrupt)。有实际物理interrupt request signal的那些中断,上面已经介绍过了。
(b)软件触发的中断(SGI,Software-generated interrupt)。软件可以通过写GICD_SGIR寄存器来触发一个中断事件,这样的中断,可以用于processor之间的通信。
(c)虚拟中断(Virtual interrupt)和Maintenance interrupt。这两种中断和本文无关,不再赘述。
为了标识这些interrupt source,我们必须要对它们进行编码,具体的ID分配情况如下:
(a)ID0~ID31是用于分发到一个特定的process的interrupt。标识这些interrupt不能仅仅依靠ID,因为各个interrupt source都用同样的ID0~ID31来标识,因此识别这些interrupt需要interrupt ID + CPU interface number。ID0~ID15用于SGI,ID16~ID31用于PPI。PPI类型的中断会送到其私有的process上,和其他的process无关。SGI是通过写GICD_SGIR寄存器而触发的中断。Distributor通过processor source ID、中断ID和target processor ID来唯一识别一个SGI。
(b)ID32~ID1019用于SPI。 这是GIC规范的最大size,实际上GIC-400最大支持480个SPI,Cortex-A15和A9上的GIC最多支持224个SPI。 |
|