2. 中断控制器基础:中断控制器的作用与 GIC 架构简介
在嵌入式 Linux 系统中,中断是 CPU 与外部设备(如 GPIO 按键、网络控制器、定时器)进行异步通信的核心机制。中断控制器(Interrupt Controller)作为 CPU 与多个中断源之间的桥梁,负责中断的收集、优先级仲裁、分发和屏蔽。本章将深入剖析中断控制器的基本作用,并重点介绍 ARM 平台最通用的 GIC(Generic Interrupt Controller)架构,为后续设备树中 GPIO 与 IRQ 的绑定打下坚实基础。
2.1 中断控制器的核心作用
中断控制器并非简单的“信号转发器”,它承担着以下关键职责:
- 中断源管理: 管理多个外设中断请求(IRQ)和快速中断请求(FIQ),支持独立使能/禁止每个中断源。
- 优先级仲裁: 当多个中断同时到达时,根据预设的优先级决定哪个中断先被 CPU 处理。
- 中断分发: 在多核(SMP)系统中,将中断路由到指定的 CPU 核心,实现负载均衡。
- 中断类型转换: 将电平触发或边沿触发的中断信号,转换为 CPU 可识别的标准中断信号。
- 中断状态跟踪: 记录每个中断的挂起(Pending)、激活(Active)和完成(Completed)状态。
关键概念: 中断控制器是 CPU 与外部中断源的“代理”。CPU 不直接处理外设的中断引脚,而是通过中断控制器统一管理,从而降低 CPU 的负担并提高系统的实时性。
2.2 GIC 架构概述
GIC(Generic Interrupt Controller)是 ARM 架构下标准的中断控制器规范,从 ARMv7-A 开始广泛使用,并在 ARMv8-A(AArch64)中持续演进。GIC 架构分为多个版本,目前主流的是 GICv2 和 GICv3/GICv4。本课程以 GICv2 为基础进行讲解,因为它在嵌入式 Linux 设备树中最为常见。
2.2.1 GICv2 架构组件
GICv2 由两大逻辑单元组成:
| 组件 | 全称 | 功能描述 |
|---|---|---|
| Distributor | 中断分发器 | 全局中断控制单元。负责中断优先级配置、使能/屏蔽、中断类型(电平/边沿)设置,以及将中断路由到指定的 CPU 接口。 |
| CPU Interface | CPU 接口 | 每个 CPU 核心拥有独立的 CPU 接口。负责与 CPU 核心直接通信,处理中断的应答(ACK)、结束(EOI)和优先级掩码。 |
设备树视角: 在设备树中,GIC 节点通常描述 Distributor 和 CPU Interface 的寄存器基地址。例如,
reg = <0x0 0x10400000 0x0 0x10000> 表示 Distributor 的地址范围。
2.2.2 GIC 中断类型
GIC 将中断源分为三种类型,理解这些类型对于设备树中的 interrupts 属性配置至关重要:
- SPI(Shared Peripheral Interrupt): 共享外设中断。所有 CPU 核心都可以接收的中断,通常用于外设(如 UART、I2C、GPIO 控制器)。中断 ID 范围:32~1019(GICv2)。
- PPI(Private Peripheral Interrupt): 私有外设中断。每个 CPU 核心独有的中断,例如每个核心的本地定时器、性能监视单元(PMU)。中断 ID 范围:16~31。
- SGI(Software Generated Interrupt): 软件触发中断。一个 CPU 核心通过写寄存器触发另一个 CPU 核心的中断,用于核间通信(IPI)。中断 ID 范围:0~15。
常见误区: GPIO 控制器产生的中断通常属于 SPI 类型,而不是 PPI。初学者容易将 GPIO 中断误配置为 PPI,导致中断无法正确路由到目标 CPU。
2.3 GIC 中断处理流程
一个典型的中断从产生到处理完成,经历以下步骤:
- 中断产生: 外设(如 GPIO 引脚检测到上升沿)向 GIC Distributor 发送中断信号。
- 优先级仲裁: Distributor 检查该中断的优先级,并与当前正在处理的中断优先级比较。如果新中断优先级更高,则进入下一步。
- 中断分发: Distributor 根据配置的 CPU 掩码(
interrupt-affinity),将中断发送到目标 CPU 的 CPU Interface。 - CPU 应答: CPU Interface 向 CPU 核心发出 IRQ 信号。CPU 执行中断向量表,读取
GICC_IAR寄存器获取中断 ID。 - 中断处理: CPU 根据中断 ID 调用对应的中断服务程序(ISR)。
- 中断结束: ISR 执行完毕后,CPU 写
GICC_EOIR寄存器通知 GIC 中断处理完成,GIC 可以继续分发下一个中断。
设备树绑定要点: 在设备树中,外设节点通过
interrupts = <中断类型 中断号 触发类型> 属性描述其连接的中断。例如,interrupts = <0 89 4> 表示 SPI 类型(0)、中断号 89、高电平触发(4)。
2.4 GIC 架构内联 SVG 图
下图展示了 GICv2 架构中 Distributor、CPU Interface 与多核 CPU 之间的连接关系,以及中断从外设到 CPU 的流动路径:
2.5 设备树中的 GIC 节点示例
在设备树中,GIC 中断控制器本身也需要被描述为一个节点。以下是一个典型的 GICv2 设备树节点:
gic: interrupt-controller@10400000 {
compatible = "arm,cortex-a15-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x0 0x10400000 0x0 0x10000>, /* Distributor 基地址 */
<0x0 0x10410000 0x0 0x10000>; /* CPU Interface 基地址 */
interrupts = <1 9 0xf04>; /* 可选:GIC 自身的维护中断 */
};
属性解析:
#interrupt-cells = <3>:表示该中断控制器需要 3 个 cell 来描述一个中断(中断类型、中断号、触发类型)。interrupt-controller:空属性,声明该节点是一个中断控制器。reg:第一个地址范围是 Distributor,第二个是 CPU Interface。