3. 中断类型详解:SPI、PPI、SGI、LPI

在 ARM GIC(Generic Interrupt Controller)架构中,中断被划分为四种基本类型:SPI(共享外设中断)、PPI(私有外设中断)、SGI(软件生成中断)和 LPI(本地特定中断)。理解这四种中断类型的区别、路由机制和触发方式,是进行中断号映射与配置的前提。

3.1 四种中断类型概览

下表从中断源、路由目标、触发方式、中断号范围等维度,对四种中断类型进行对比:

中断类型 中断源 路由目标 触发方式 典型中断号范围 是否可配置
SPI 共享外设(如 UART、I2C、Ethernet) 任意一个指定的 PE(处理单元) 电平触发 / 边沿触发 32 ~ 1019(GICv3) 是(路由、触发方式)
PPI 私有外设(如每个 CPU 的本地定时器、PMU) 固定的单个 PE 电平触发 / 边沿触发 16 ~ 31 是(触发方式)
SGI 软件(通过写 GIC 寄存器产生) 一个或多个 PE(可指定 CPU 掩码) 边沿触发(固定) 0 ~ 15 是(目标 PE、中断 ID)
LPI 支持 MSI(消息信号中断)的外设 任意一个指定的 PE 电平触发(固定) 8192 ~ 以上(GICv3) 是(路由、优先级)
关键概念:中断号(INTID)在 GICv3 中是一个 32 位整数,但实际使用范围被划分为上述四个区域。SPI 和 PPI 是传统板级外设中断的主要类型,SGI 用于核间通信(IPI),LPI 则是为高性能 PCIe 设备设计的可扩展中断机制。

3.2 SPI(共享外设中断)

SPI 是嵌入式系统中最常见的中断类型。它由片外或片内共享外设产生,可以被路由到任意一个指定的 CPU 核心。SPI 的中断号范围在 GICv3 中为 32 ~ 1019,每个 SPI 中断在 GIC 中都有一个独立的中断路由寄存器(GICD_IROUTERn),用于配置目标 PE。

  • 触发方式:支持电平触发(高电平/低电平)和边沿触发(上升沿/下降沿),通过 GICD_ICFGRn 寄存器配置。
  • 路由特性:一个 SPI 中断在任意时刻只能被一个 PE 处理,但可以通过软件动态修改路由目标,实现负载均衡。
  • 典型应用:UART 接收中断、I2C 传输完成中断、GPIO 外部中断等。
/* 设备树中 SPI 中断的典型描述 */
/* 中断控制器父节点为 GIC,第一个字段为中断类型(0=SPI),第二个字段为中断号偏移,第三个字段为触发方式 */
interrupts = <0 33 4>;  /* SPI 中断号 33,高电平触发 */

3.3 PPI(私有外设中断)

PPI 是每个 PE 私有的中断,中断号范围为 16 ~ 31。每个 PE 都有自己独立的 PPI 中断实例,例如每个 CPU 核心的本地定时器中断(通常映射到 PPI 13 或 14)和性能监视单元(PMU)中断。

  • 私有性:PPI 中断只能由它所属的 PE 处理,不能被路由到其他 PE。GIC 为每个 PE 维护独立的 PPI 配置寄存器。
  • 触发方式:同样支持电平触发和边沿触发,通过 GICR_ICFGRn(Redistributor 中的寄存器)配置。
  • 典型应用:CPU 本地定时器(Arch Timer)、PMU 溢出中断、调试中断。
驱动开发注意:在设备树中描述 PPI 中断时,中断类型字段应使用 1(代表 PPI)。例如:interrupts = <1 13 4>; 表示 PPI 中断号 13,高电平触发。驱动中不需要指定目标 CPU,因为 PPI 自动绑定到当前运行的 PE。

3.4 SGI(软件生成中断)

SGI 是一种由软件主动触发的中断类型,中断号范围为 0 ~ 15。它通过写 GIC 的 GICD_SGIR(GICv2)或 ICC_SGI1R(GICv3)寄存器产生,主要用于核间通信(IPI)。

  • 触发方式:固定为边沿触发,不可配置。
  • 路由特性:可以发送给一个 PE、一组 PE(通过 CPU 掩码指定),或所有 PE(广播)。
  • 典型应用:Linux 内核中的 smp_call_function()、TLB 刷新、任务迁移等 IPI 场景。
/* GICv3 中触发 SGI 的示例(汇编伪代码) */
/* 向 CPU 核心 1 和 2 发送 SGI 中断号 3 */
uint64_t sgi_value = (3 << 24) |   /* SGI ID */
                     (0x6 << 16) |  /* 目标 CPU 掩码:bit1 和 bit2 置位 */
                     (0 << 0);      /* 目标列表,0 表示使用掩码 */
asm volatile("msr ICC_SGI1R_EL1, %0" : : "r" (sgi_value));

3.5 LPI(本地特定中断)

LPI 是 GICv3 引入的新型中断类型,专为支持大量中断源的场景设计(如 PCIe MSI/MSI-X)。LPI 的中断号从 8192 开始,理论上可以扩展到非常大的范围(GICv3 支持最多 2^32 个 LPI)。

  • 触发方式:固定为电平触发,不可配置。
  • 路由特性:通过 ITS(中断翻译服务)和 Redistributor 中的 LPI 配置表进行路由,支持动态映射和优先级配置。
  • 配置方式:LPI 的配置不通过传统的 MMIO 寄存器,而是通过内存中的配置表(LPI Configuration Table 和 LPI Pending Table)进行管理,由 GIC 的 Redistributor 硬件自动读取。
  • 典型应用:NVMe SSD、高性能网卡、GPU 等 PCIe 设备的中断。
LPI 配置注意事项:LPI 的使能和优先级配置是通过写内存表实现的,而不是直接操作 GIC 寄存器。驱动开发中,通常由 PCIe 子系统或 ITS 驱动负责管理 LPI 的分配和映射。LPI 中断号在设备树中通常不直接描述,而是通过 PCIe MSI 控制器动态分配。

3.6 四种中断类型的架构关系

下面的 SVG 图展示了 GICv3 中四种中断类型与中断控制器组件(Distributor、Redistributor、ITS)之间的路由关系:

GICv3 四种中断类型架构关系 GICv3 中断类型与路由架构 中断源 SPI (32~1019) PPI (16~31) SGI (0~15) LPI (8192+) GIC 组件 Distributor Redistributor (per PE) ITS (中断翻译服务) 目标 PE PE0 (CPU0) PE1 (CPU1) PE2 (CPU2) PE3 (CPU3) 路由配置 私有绑定 软件触发 MSI 映射 路由路径说明 • SPI:外设 → Distributor(路由配置) → 指定 Redistributor → 目标 PE • PPI:私有外设 → 直接绑定到所属 PE 的 Redistributor → 该 PE • SGI:软件写寄存器 → Redistributor(根据 CPU 掩码) → 一个或多个 PE • LPI:外设 MSI → ITS(中断翻译) → Redistributor(查 LPI 配置表) → 目标 PE

3.7 中断类型选择与驱动开发建议

在实际的驱动开发中,选择哪种中断类型取决于硬件设计和性能需求:

场景 推荐中断类型 原因
板级外设(UART、I2C、SPI) SPI 中断号固定,路由灵活,支持多种触发方式
CPU 本地功能(定时器、PMU) PPI 每个 CPU 独立实例,无需路由配置,延迟最低
核间通信(IPI) SGI 软件触发快速,支持广播和掩码,延迟可控
PCIe 设备(NVMe、网卡) LPI 支持大量中断号,动态分配,无需硬件连线
需要负载均衡的外设 SPI 或 LPI 支持动态路由到不同 CPU,适合多核系统
实战要点:在编写设备驱动时,通过设备树或 ACPI 获取的中断号已经是经过 GIC 映射后的硬件中断号。驱动开发者不需要关心中断类型的具体路由细节,但需要正确配置触发方式(尤其是 SPI 和 PPI),并在中断处理函数中考虑中断亲和性(affinity)设置,以优化多核性能。