GIC-500是ARM GICv3的一个实现,它只支持ARMv8核和实现了GIC Stream协议的GIC CPU Interface,比如Cortex-A53。
关于GIC有四份相关文档:《
Cortex-A53 TRM
》介绍了GIC CPU Interface;《
ARMv8-A Architecture Profile
》提供了GIC CPU Interface的细节;《
GIC-500 TRM
》介绍了GICv3的一个实现;《
GICv3/4 Architecture Specification
》介绍了GIC架构细节规范。
这四份文档可以分为两部分:GIC CPU Interface和GIC本身。
1 Introduction
SGIs - Software Generated Interrupts
ITS - Interrupt Translation Service
LPIs - Locality-specific Peripheral Interrupts
SPIs - Shared Peripheral Interrupts
PPIs - Private Peripheral Interrupts
1.1 About the GIC-500
GIC-500
支持高达128核,只支持ARMv8架构的核和GIC Stream Protocol接口的GIC CPU接口,Physical interrupt signals,SGIs,从AXI4 slave端口产生的中断,ITS提供ID转换等功能
。
GIC-500
从AXI4 Slave或者Physical interrupt inputs接收中断;和CPU通过AXI4-Stream接口连接;通过AXI4 Slave端口被编程;通过AXI Master Port访问外部内存。
GIC CPU interface属于GIC一部分,但不属于GIC-500,而更倾向于属于ARMv8 core的一部分。
GIC-500的Distributor->Redistributor->Cluster->Core的拓扑结构
:
ARM架构通过MPIDR(Multiprocessor Affinity Register)寄存器给给每个CPU制定一个逻辑地址。
ARMv7支持三层,ARMv8支持四层,MPIDR有着明显的分层结构,
<Aff3>.<Aff2>.<Aff1>.<Aff0>
。
GIC-500只支持两层,所以MPIDR的值只能是
0.0.c.d,c是process层,d是core层
。
GIC-500支持128 core或者32 processor,并且每processor不超过8 core
。
1.3 Features
支持高达128 core
affinity-level 1支持高达32 cluster
每cluster高达8 core
LPI、SPI
16个SGIs,ID0-ID15
16个PPIs,ID16-ID31
基于Affinity的可编程中断路由
中断屏蔽和优先级控制
每中断可配置32个优先级
中断分为3组:Group 0.、Non-secure Group 1、Secure Group 1。
1.7 相关文档
Technical Reference Manual、
Implementation Guide、
Integration Manual
2 Functional Description
2.1 About the functions
ICB: Interrupt Control Block.
ICB State RAM
是保存
SPIs、PPIs、SGIs
各种配置的地方。同样LPI State RAM和ITE State RAM是保存LPIs和ITS设置的地方。
2.2 Interfaces
从
Figure 2-1
可以看出GIC-500和外部的接口包括:
AXI4 Slave Interface、AXI4 Master Interface、RAM Interfaces、Physical interrupt signals、GIC-500 Stream Protocal Interface
。
AXI4 Slave Interface
:CPU可以通过此接口对GIC-500所有部分编程,包括Distributor、Redistributor、ITS。同时也负责处理message-based中断,也即通过写AXI4 slave interface产生的中断。message-based中断可以产生SGI/LPI类型的中断。
AXI4 Master Interface
:GIC-500通过此接口访问主内存,包括ITS的translation tables、ITS command queue、LPI配置表、LPI pending table等。
RAM Interfaces
:使用SRAM来缓存各种状态。
Physical interrupt signals
:产生
SPIs和PPIs
类型中断的信号,可配置成level-sensitive、edge-triggered。对于PPI,每个核都有一套;对于SPI,所有核共用一套。
GIC-500 Stream Protocal Interface
:用于发送中断给CPU核,并且从CPU接收激活中断的通知。
2.3 Operation
GIC-500可以分成三个主要部分:
ITS
(将外设message-based中断翻译成LPIs)、
Distributor
(接收Wire interrupts或者编程接口过来的中断,然后根据优先级发送到CPU Interface)、
Redistributor
(每CPU核一个Redistributor,保存每个核的PPIs/SGIs/:PIs状态)。
Interrupt types
GIC-500支持不同类型的中断,主要包括:
SGIs
- 是
核间中断,从一个核触发发送到另外核
。一个核上触发的中断,并不影响其他核上同样中断号,并且
每个核的SGI设置都是独立的
。可以通过System register或者GICD_SGIR触发中断,共
16个独立的SGIs,ID0-ID15
。
PPIs
- 用于和CPU和紧耦合的外设,因此
PPI仅发送到相关的CPU核
。一个核上触发的PPI中断并不会影响其他核相同ID号的PPI,而且每个核的PPI设置也是相互独立的。
SPIs
- 用于不和特定CPU和紧耦合的外设,一个核上触发的SPI中断,同时也会激活其他核上的中断。但是也可以通过编程设置SPI到特定的核。GIC-500只允许一个核响应SPI中断,SPI的设置是核间共享的。SPI可以被wire input或者AXI4 slave programming interface触发。GIC-500支持高达960各终端,spi[991:32]。
LPIs
- 多用于产生message-based类型中断的外设,一个LPI同一时刻只能指向一个核。外设通过写ITS产生LPI中断。
选择LPI还是SPI?
LPI和SPI都是message-based中断,都可以通过软件进行配置。下面可以作为选用何种中断参考因素:
仅有ITS提供中断ID翻译,因此虚拟机使用的中断最好使用LPI。
LPI一般是属于Group 1 Non-secure的,因此安全软件相关的message-based中断一般使用SPI。
仅有SPI可以送到所有的核,如果需要平衡各个核中断负载均衡的话需要使用SPI。
实现同样数量的中断LPI占用面积远小于SPI,因为LPI仅缓存不存储。
SPI的最坏情况延时要远好于LPI
Interrupt groups
Interrupt group
:Group 0、Group 1 Secure、Group 1 Non-secure。
每个中断组:
决定中断目标Exception Level和组中中断安全状态。
每个中断都有独立位,决定向特定核触发。
Interrupt triggering
Level-sensitive(这种类型的中断会一直pending,直到被asserted)和Edge-triggered(上升沿触发导致中断变成pending状态,直到被CPU interface activated时清pending位)。
Power Management
GIC-500不仅支持对应的核被关闭,同时自身也可以被关闭。通过GICR_WAKER寄存器来设置。
2.4 Clocking and resets
GIC-500仅有一个时钟输入clk,和一根reset信号resetn。
3 Programmers Model
3.2 The GIC-500 register map
GICD
- GIC Distributor register
GICR
- GIC Redistributor register
GITS
- GIC Interrupt Translation Service register
4 相关延伸
在每个平台的实现中都会对中断资源进行定义,这是一个GIC-500对应的中断控制器设置:
/* 0-15: SGI (software generated interrupts)
* 16-31: PPI (private peripheral interrupts)
* 32+: SPI (shared peripheral interrupts)
#define GIC_PPI_START 16
#define GIC_SPI_START 32
* software generated interrupts
#define SGI0_INT (0)
#define SGI1_INT (1)
#define SGI2_INT (2)
#define SGI3_INT (3)
#define SGI4_INT (4)
#define SGI5_INT (5)
#define SGI6_INT (6)
#define SGI7_INT (7)
#define SGI8_INT (8)
#define SGI9_INT (9)
#define SGI10_INT (10)
#define SGI11_INT (11)
#define SGI12_INT (12)
#define SGI13_INT (13)
#define SGI14_INT (14)
#define SGI15_INT (15)
* private peripheral interrupts
* shared peripheral interrupts
#define WDT_INT (GIC_SPI_START+0)
#define NR_SOC_IRQS (GIC_SPI_START+77)
更深入的分析,就需要和Linux kernel中GIC相关代码结合了。