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

ARM GIC(Generic Interrupt Controller)将中断源划分为四种基本类型:SPI(共享外设中断)、PPI(私有外设中断)、SGI(软件生成中断)和LPI(本地特定中断)。理解这四种中断类型的区别、路由规则和触发特性,是进行中断控制器配置和性能优化的基础。

4.1 中断类型概览

下表从中断源、路由目标、触发方式、配置粒度和典型用途五个维度,对四种中断类型进行对比:

特性 SPI PPI SGI LPI
中断源 片内外设(UART、I2C、DMA等) CPU私有外设(Timer、PMU等) 软件写GICD_SGIR寄存器 ITS(中断翻译服务)映射的设备MSI
路由目标 任意一个或一组指定的PE 固定的单个PE 目标PE列表(亲和路由) 通过ITS重定向到指定PE
触发方式 电平触发 / 边沿触发 电平触发 / 边沿触发 边沿触发(软件写寄存器) 边沿触发(MSI消息)
配置粒度 全局(GICD) 每PE私有(GICR) 每PE私有(GICR) 全局(ITS + GICR)
典型用途 多核共享外设中断 本地定时器、性能监控 核间通信(IPI)、自中断 PCIe MSI/MSI-X、虚拟化设备
关键区分:SPI 和 LPI 是全局中断,可以被任意 PE 处理;PPI 和 SGI 是每 PE 私有的中断,每个 PE 拥有独立的实例。在 GICv3/v4 中,LPI 通过 ITS 实现高效的大规模中断路由,是高性能设备中断的首选方案。

4.2 SPI(共享外设中断)

SPI 是嵌入式系统中最常见的中断类型,用于连接片内外设(如 UART、I2C、SPI、DMA 控制器等)。SPI 中断号范围在 GICv2 中为 ID32~ID1019,在 GICv3/v4 中扩展为 ID32~ID4095。

  • 路由特性:SPI 可以路由到任意一个 PE 或一组 PE(通过亲和路由寄存器配置)。
  • 触发配置:支持电平触发(Level-sensitive)和边沿触发(Edge-triggered),通过 GICD_ICFGRn 寄存器配置。
  • 优先级与安全:每个 SPI 可以独立配置优先级(GICD_IPRIORITYRn)和安全属性(GICD_IGROUPRn)。
  • 中断挂起:SPI 的中断挂起状态由 GICD_ISPENDRn 和 GICD_ICPENDRn 控制。
性能优化要点:对于高频率的 SPI 外设(如高速 DMA),建议使用边沿触发模式以减少电平采样带来的额外延迟;同时将中断路由到专用 PE,避免多核争抢 GICD 全局寄存器。

4.3 PPI(私有外设中断)

PPI 是每个 PE 私有的中断,每个 PE 拥有独立的 PPI 实例。PPI 中断号范围为 ID16~ID31。典型用途包括:

  • CPU 本地定时器:每个 PE 的 Generic Timer 产生的物理定时器中断(PPI ID26~ID29)。
  • 性能监控单元(PMU):每个 PE 的 PMU 溢出中断(PPI ID23)。
  • 调试接口:CoreSight 调试相关中断。

PPI 的配置寄存器位于每个 PE 的 Redistributor(GICR)中,包括:

// PPI 配置寄存器(GICR 基地址 + 偏移)
GICR_ICFGR1      // 触发方式配置(PPI ID16~31)
GICR_IPRIORITYR  // 优先级配置(每 PPI 8 bits)
GICR_IGROUPR0    // 安全组配置(PPI + SGI)
GICR_ISPENDR0    // 中断挂起置位
GICR_ICPENDR0    // 中断挂起清除
注意:PPI 的配置是每 PE 独立的。在多核系统中,每个 PE 的 PPI 定时器中断必须单独使能和配置,不能通过全局寄存器统一操作。错误的跨 PE 访问可能导致中断丢失或配置冲突。

4.4 SGI(软件生成中断)

SGI 由软件通过写 GICD_SGIR 寄存器(GICv2)或 GICR_SGIR 寄存器(GICv3)触发。SGI 中断号范围为 ID0~ID15,共 16 个。SGI 是核间通信(IPI)的核心机制。

SGI 的关键特性:

  • 边沿触发:SGI 只能边沿触发,由写寄存器操作产生。
  • 亲和路由:可以指定目标 PE 列表(通过 CPU mask 字段),支持广播到所有 PE。
  • 自中断:PE 可以向自己发送 SGI,用于软件定时器或任务调度。
  • 中断优先级:SGI 的优先级在 GICR_IPRIORITYR 中配置,与 PPI 共享寄存器。

在 Linux 内核中,SGI 的典型用途包括:

// Linux 内核 SGI 分配示例(arch/arm64/kernel/smp.c)
#define IPI_RESCHEDULE      0   // 调度器重新调度
#define IPI_CALL_FUNC       1   // 调用函数
#define IPI_CPU_STOP        2   // 停止 CPU
#define IPI_IRQ_WORK        3   // 中断工作
#define IPI_WAKEUP          4   // 唤醒 CPU
性能优化要点:SGI 的延迟通常在几十纳秒级别,远低于 SPI 的硬件中断延迟。在实时系统中,使用 SGI 进行核间通信可以避免共享内存的锁竞争,但需注意 SGI 的优先级不能高于 PPI 中的定时器中断,否则可能导致调度延迟。

4.5 LPI(本地特定中断)

LPI 是 GICv3/v4 引入的新中断类型,专为大规模中断场景设计。LPI 中断号范围为 ID8192~ID16777215(共约 1600 万个)。LPI 不通过传统的 GICD 寄存器配置,而是通过 ITS(Interrupt Translation Service)和 GICR 的 LPI 配置表管理。

LPI 的核心机制:

  • ITS 映射:设备通过 ITS 发送 MSI 消息,ITS 将设备事件 ID 翻译为 LPI 中断号并路由到目标 PE。
  • 配置表:LPI 的优先级、使能状态存储在内存中的配置表(GICR_PROPBASER 指向的 LPI 配置表),中断挂起状态存储在 GICR_PENDBASER 指向的挂起表。
  • 边沿触发:LPI 只能边沿触发,由 MSI 消息产生。
  • 无硬件中断挂起清除:LPI 的挂起状态由软件通过写 GICR_PENDBASER 表清除,没有专用的清除寄存器。
性能优势:LPI 的配置表存储在内存中,避免了 GICD 全局寄存器的竞争;ITS 支持中断聚合和重映射,适合 PCIe 多队列设备(如 NVMe、GPU)的高吞吐中断场景。在 GICv4 中,LPI 还支持直接注入到虚拟 PE(vLPI),减少虚拟机中断开销。

4.6 中断类型选择指南

在实际系统设计中,根据中断源的特性和性能需求选择合适的中断类型:

场景 推荐中断类型 理由
低速外设(UART、GPIO) SPI 配置简单,兼容性好,延迟要求不高
高速外设(DMA、网络控制器) LPI(通过 ITS) 避免全局寄存器竞争,支持多队列
CPU 本地定时器 PPI 每 PE 私有,无需路由,延迟最低
核间通信(IPI) SGI 软件触发,延迟极低,支持亲和路由
虚拟化设备中断 LPI(vLPI) GICv4 支持直接注入,减少 VM exit
GIC 中断类型架构图 片内外设 CPU 私有外设 软件写寄存器 PCIe MSI/MSI-X SPI (ID32~4095) PPI (ID16~31) SGI (ID0~15) LPI (ID8192~) GICD 全局配置 任意 PE 路由 GICR 每 PE 私有 固定 PE 路由 GICR 每 PE 私有 亲和路由 ITS + GICR 表 内存配置表 中断分发 → PE 异常处理 → 中断服务例程 (ISR) 说明: SPI 和 LPI 为全局中断,可被任意 PE 处理;PPI 和 SGI 为每 PE 私有中断,每个 PE 拥有独立实例。 LPI 通过 ITS 和内存配置表管理,支持大规模中断场景(如 PCIe 多队列设备)。

4.7 中断类型与 GIC 版本的关系

不同 GIC 版本对中断类型的支持存在差异,下表总结了关键区别:

特性 GICv2 GICv3 GICv4
SPI 最大 ID 1019 4095 4095
LPI 支持 不支持 支持(需 ITS) 支持(增强 vLPI)
SGI 路由 通过 GICD_SGIR 通过 GICR_SGIR(每 PE) 同 GICv3
PPI 配置 GICD 全局寄存器 GICR 每 PE 寄存器 同 GICv3
虚拟中断 不支持 不支持 支持 vLPI 直接注入
兼容性注意:在 GICv2 系统中,所有中断配置都通过 GICD 全局寄存器完成,多核访问时存在锁竞争。GICv3/v4 将 PPI 和 SGI 的配置迁移到每 PE 的 GICR 寄存器,显著减少了全局寄存器争抢,是性能优化的重要改进。