深入理解 Linux IRQ 中断子系统:设计思想、UML 类图与设备树映射
IRQ 子系统:先讲设计思想,再按 Consumer → Core → Provider → 异常入口 → DT 映射自上而下展开;关键类统一用 UML 类图描述,并说明类与成员职责;最后给出逻辑漏洞与修正清单。
1. IRQ 子系统设计思想
1.1 它要解决的核心问题
中断是 Linux 内核最核心、最底层的机制。它看起来只是"注册一个 handler",但一旦进入内核,就会遇到八类复杂问题:
- 硬件差异:GIC、GPIO 中断控制器、级联 irqchip、MSI/LPI、PCIe、PCI INTx,寄存器模型完全不同。
- 编号混乱 :硬件中断号
hwirq、Linux 虚拟中断号virq、DT 里的<type hwirq trigger>,三套编号必须统一。 - 中断域 :同一个
hwirq在不同irq_domain下可能映射到不同virq,必须用域来隔离。 - 级联与层次化 :GPIO 中断挂在 GIC 下,GIC 又挂在 ITS 下,形成多层
irq_domain链。 - 上下半部分离:硬中断上下文不能睡眠,但很多设备处理需要睡眠,必须拆成 primary handler + threaded handler。
- 共享中断 :多个驱动共享一条 IRQ 线,
irqaction必须组成链表,逐个回调。 - 使能与嵌套 :
disable_irq必须支持嵌套,depth计数必须精确。 - CPU 亲和性 :SMP 下中断可以迁移到不同 CPU,
affinity必须可设置。
IRQ 子系统的使命,就是用一套统一的描述符 + 域映射 + 流控引擎,把这些全部收口到 kernel/irq/。
1.2 三个平面:Consumer、Core、Provider
IRQ 子系统的顶层设计是三层:
text
Consumer 层:设备驱动,拿 virq,注册 handler,等待回调
│
▼
Core 层:IRQ Core,维护 irq_desc、irq_domain、流控 handler、请求/释放/使能
│
▼
Provider 层:irqchip 驱动,实现 irq_chip、irq_domain_ops
│
▼
异常入口:arch entry.S → handle_arch_irq() → 分发到 Core
- Consumer :
drivers/mmc、usb、i2c、spi、net、gpio等。 - Core :
kernel/irq/,包括irqdesc.c、irqdomain.c、manage.c、chip.c、handle.c。 - Provider :
drivers/irqchip/,如irq-gic-v3.c、irq-gic-v3-its.c、GPIO 级联 irqchip。 - 异常入口 :
arch/arm64/kernel/entry.S、arch/arm64/kernel/irq.c。
1.3 核心抽象:hwirq / virq / irq_desc / irq_data / irq_chip
IRQ 子系统最有价值的抽象是这五层:
| 抽象 | 归属 | 语义 |
|---|---|---|
hwirq |
硬件 | 硬件中断号,域内唯一 |
virq |
Core | Linux 虚拟中断号,全局唯一 |
irq_desc |
Core | 每个 virq 对应一个描述符,含 action、handle_irq |
irq_data |
Core | 下发给 irq_chip 回调的上下文,含 hwirq、chip、domain |
irq_chip |
Provider | 硬件操作回调表 |
关键点:
virq是 Consumer 看到的句柄;hwirq是 Provider 操作硬件用的编号;irq_domain负责两者之间的映射。
1.4 中断域与级联
中断域 irq_domain 解决的是"同一硬件中断号在不同控制器下可能冲突"的问题:
- 每个 irqchip 创建自己的
irq_domain; irq_domain_ops->translate()把 DT 说明符翻译成hwirq;irq_domain_ops->alloc()分配virq;irq_domain_ops->map()把virq与hwirq关联。
级联 / 层次化解决的是"父控制器的一个中断线,代表子控制器的一组中断":
text
GIC (根域)
└─ SPI 34(GPIO1 的父中断)
└─ GPIO1 irq_domain(子域)
├─ pin0 → virq A
├─ pin1 → virq B
└─ pin2 → virq C
运行时:
- GIC 触发 SPI 34;
- GIC 的
handle_fasteoi_irq调用 GPIO1 的 chained handler; - chained handler 读取 GPIO1 的中断状态寄存器;
- 对每个 pending pin 调用
generic_handle_irq(子 virq); - 子 virq 的 flow handler 调用 Consumer 的 handler。
1.5 GIC 的 SPI / PPI / SGI
GICv3 的中断类型由 DT 里的第一个参数决定:
| 类型 | 值 | 含义 |
|---|---|---|
GIC_SPI |
0 | Shared Peripheral Interrupt,共享外设中断,可路由到任意 CPU |
GIC_PPI |
1 | Private Peripheral Interrupt,每 CPU 私有 |
GIC_SGI |
2 | Software Generated Interrupt,CPU 间 IPI |
编号细节:
- GIC 内部 SPI 从 32 开始编号;
hwirq = GIC_SPI_N + 32;- PPI 从 16 开始编号;
- SGI 从 0 开始编号。
1.6 上下半部分离
primary handler:硬中断上下文执行,不可睡眠,应尽快返回。
threaded handler:内核线程上下文执行,可睡眠,适合耗时操作。
c
request_threaded_irq(irq, primary, threaded, flags, name, dev);
primary == NULL:使用默认 primary handler,仅唤醒线程;threaded == NULL:非线程化,全部在硬中断上下文执行;IRQF_ONESHOT:线程化中断必须带此标志,表示线程结束前不 unmask。
1.7 与其它子系统的关系
| 子系统 | 交互 |
|---|---|
| GPIO | GPIO 作为中断源,通过层次化 irq_domain 级联到 GIC |
| pinctrl | pinctrl 负责 pin 复用与电气配置,IRQ 负责中断触发类型 |
| MSI / PCIe | ITS 提供 MSI 域,PCIe 设备通过 msi_domain 拿 virq |
| PM | irq_set_irq_wake() 配置唤醒源 |
| SMP | irq_set_affinity() 设置 CPU 亲和性 |
| NMI | request_nmi() 注册不可屏蔽中断 |
1.8 设计原则总结
- 描述符优先 :每个 virq 一个
irq_desc。 - 域隔离 :
hwirq只在域内有效,virq全局有效。 - 回调表驱动 :Provider 实现
irq_chip,Core 调度。 - 流控可替换 :
handle_level_irq、handle_fasteoi_irq、handle_edge_irq按需选择。 - 上下半部可分离 :
request_threaded_irq支持线程化。 - 级联与层次化:支持多层 irqchip 叠加。
- 资源自动化 :
devm_request_irq自动释放。
2. 总体架构:自上而下看 IRQ
2.1 框架图
text
┌───────────────────────────────────────────────────────────────────────────────┐
│ 消费者 (设备驱动) │
│ drivers/mmc|usb|i2c|spi|net|gpio ... │
│ irq = platform_get_irq(pdev,0) / of_irq_get(np,0) │
│ devm_request_irq(dev, irq, handler, flags, name, dev_id) │
│ → handler() 在硬/线程中断上下文被回调 │
└───────────────────────────────┬───────────────────────────────────────────────┘
│ Consumer API include/linux/interrupt.h / of_irq.h
▼
┌───────────────────────────────────────────────────────────────────────────────┐
│ IRQ CORE (kernel/irq/) │
│ │
│ ┌──────────────┐ ┌────────────────┐ ┌───────────────┐ ┌────────────────┐ │
│ │ irqdesc.c │ │ irqdomain.c │ │ manage.c │ │ chip.c/handle.c│ │
│ │ irq_desc │ │ irq_domain │ │ request/free │ │ irq_chip 封装 │ │
│ │ 描述符/统计 │ │ hwirq<->virq │ │ enable/disable│ │ flow handler │ │
│ └──────────────┘ └────────────────┘ └───────────────┘ └────────────────┘ │
│ ┌──────────────┐ ┌────────────────┐ ┌───────────────┐ ┌────────────────┐ │
│ │ generic-chip │ │ affinity/ │ │ proc.c │ │ pm.c/spurious │ │
│ │ 通用 irqchip │ │ migration/spread│ │ /proc/interrupt│ │ 电源/假中断 │ │
│ └──────────────┘ └────────────────┘ └───────────────┘ └────────────────┘ │
│ │
│ 全局: irq_desc_tree(radix) / irq_default_domain / handle_arch_irq │
│ 核心数据模型: irq_desc → irq_data → irq_chip ; irq_domain(revmap) │
└───────────▲───────────────────────────────────────────────┬──────────────────┘
│ Provider API (irqdomain.h / irq.h) │ 异常入口
│ irq_domain_add_* / irq_alloc_descs / │ (entry.S→handle_arch_irq)
│ irq_set_chip_and_handler_name / IRQCHIP_DECLARE │
▼ │
┌───────────────────────────────────────┐ ┌──────────┴────────────────────┐
│ Provider (中断控制器驱动 irqchip) │ │ CPU/异常层 │
│ drivers/irqchip/irq-gic-v3.c (GICv3) │ │ arch/arm64/kernel/entry.S │
│ + irq-gic-v3-its.c (MSI/LPI) │ │ el1_irq → handle_arch_irq() │
│ struct irq_chip / irq_domain / ops │ │ arch/arm64/kernel/irq.c: │
│ gic_chip_data / redist_region │ │ init_IRQ()→irqchip_init() │
└───────────────────┬───────────────────┘ └───────────────────────────────┘
│ readl/writel (GICD/GICR)
▼
RK3568 GICD@0xfd400000 / GICR@0xfd460000 / ITS@0xfd440000
2.2 关键源文件
核心层 kernel/irq/:
| 文件 | 功能 |
|---|---|
irqdesc.c |
irq_desc 生命周期、irq_desc_tree(radix)、__handle_domain_irq() |
irqdomain.c |
irq_domain 管理、irq_create_mapping*()、irq_find_mapping()、hierarchy |
manage.c |
request_threaded_irq()、free_irq()、enable/disable_irq()、线程化 |
chip.c |
irq_chip 封装、irq_set_chip_and_handler_name()、各 flow handler |
handle.c |
事件分发、__handle_irq_event_percpu()、线程唤醒 |
generic-chip.c |
通用 irqchip 库、irq_alloc_domain_generic_chips() |
affinity.c / migration.c |
SMP 亲和性与中断迁移 |
spurious.c |
假中断检测 |
pm.c |
中断系统 suspend/resume |
proc.c |
/proc/interrupts、/proc/irq/* |
devres.c |
devm_request_* / devm_free_irq |
resend.c |
check_irq_resend() |
ipi.c |
Generic IPI 支持 |
msi.c |
MSI 核心 |
提供者层 drivers/irqchip/:
| 文件 | 功能 |
|---|---|
irqchip.c |
irqchip_init()、platform_irqchip_probe() |
irq-gic-v3.c |
RK3568 根中断控制器 GICv3 |
irq-gic-v3-its.c |
GICv3 ITS(LPI/MSI 域) |
irq-gic-common.c |
GIC 公共寄存器操作 |
irq-gic.c / irq-gic-v2m.c |
GICv2 / v2m |
体系结构层 arch/arm64/kernel/:
| 文件 | 功能 |
|---|---|
irq.c |
init_IRQ():分配 IRQ 栈 → irqchip_init() → 校验 handle_arch_irq |
entry.S |
el1_irq 异常向量 → handle_arch_irq() |
2.3 初始化顺序与依赖
text
start_kernel()
│
├─ init_IRQ() arch/arm64/kernel/irq.c:74
│ ├─ init_irq_stacks() 分配 IRQ 栈
│ ├─ irqchip_init() drivers/irqchip/irqchip.c:29
│ │ └─ of_irq_init(__irqchip_of_table)
│ │ └─ 遍历 IRQCHIP_DECLARE 注册项
│ │ └─ gic_of_init() irq-gic-v3.c:1961
│ │ ├─ 映射 GICD/GICR 寄存器
│ │ ├─ irq_domain_create_tree()
│ │ ├─ set_handle_irq(gic_handle_irq)
│ │ └─ IRQCHIP_DECLARE 注册到 __irqchip_of_table
│ └─ 校验 handle_arch_irq 已设置
│
└─ 各驱动 probe()
├─ platform_get_irq() / of_irq_get()
├─ irq_create_fwspec_mapping() → virq
└─ devm_request_irq() → irq_desc.action
3. Consumer API:驱动如何使用中断
3.1 典型流程
text
设备驱动 consumer
│ irq = platform_get_irq(pdev, 0) → virq
│ devm_request_irq(dev, irq, handler, flags, ...) → 注册 irqaction
│ ... 等待中断 ...
│ handler(irq, dev_id) → 被 Core 回调
▼
Consumer 只持有 virq 与 handler,不关心 hwirq 与 irq_chip。
3.2 Consumer 常用 API
c
/* 注册:非线程化 */
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev);
/* 注册:线程化(推荐) */
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long flags,
const char *name, void *dev);
/* 自动选择硬/线程 */
int request_any_context_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev_id);
/* per-CPU 中断 */
int request_percpu_irq(unsigned int irq, irq_handler_t handler,
const char *devname, void __percpu *percpu_dev_id);
/* NMI */
int request_nmi(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev);
/* 释放 */
const void *free_irq(unsigned int irq, void *dev_id);
void free_percpu_irq(unsigned int irq, void __percpu *percpu_dev_id);
/* devres 版 */
int devm_request_threaded_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, irq_handler_t thread_fn,
unsigned long irqflags, const char *devname,
void *dev_id);
int devm_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, unsigned long irqflags,
const char *devname, void *dev_id);
void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
3.3 使能与禁止
c
void enable_irq(unsigned int irq);
void disable_irq(unsigned int irq); /* 等待处理完成(可睡眠) */
void disable_irq_nosync(unsigned int irq); /* 不等待 */
bool disable_hardirq(unsigned int irq);
void enable_percpu_irq(unsigned int irq, unsigned int type);
void disable_percpu_irq(unsigned int irq);
bool irq_percpu_is_enabled(unsigned int irq);
void irq_wake_thread(unsigned int irq, void *dev_id);
关键区分:
| API | 是否睡眠 | 用途 |
|---|---|---|
disable_irq |
是 | 常规禁用,等待在执行的 handler |
disable_irq_nosync |
否 | 不能睡眠的上下文 |
disable_hardirq |
否 | 仅禁用硬中断,保留线程 |
disable_irq支持嵌套,irq_desc.depth计数递减到 0 才真正禁用。
3.4 亲和性与唤醒
c
int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);
int irq_set_irq_wake(unsigned int irq, unsigned int on);
int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool state);
int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool *state);
3.5 DT 解析
c
int of_irq_get(struct device_node *dev, int index);
int of_irq_get_byname(struct device_node *dev, const char *name);
unsigned int irq_of_parse_and_map(struct device_node *dev, int index);
int of_irq_count(struct device_node *dev);
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq);
int platform_get_irq(struct platform_device *pdev, unsigned int num);
int platform_get_irq_byname(struct platform_device *pdev, const char *name);
int platform_get_irq_optional(struct platform_device *pdev, unsigned int num);
int platform_irq_count(struct platform_device *pdev);
3.6 级联分发
c
int generic_handle_irq(unsigned int irq);
generic_handle_irq() 由级联 irqchip 的父 handler 调用,用于把子域的中断分发给 Core。
3.7 典型使用示例
c
static irqreturn_t my_handler(int irq, void *dev_id)
{
struct my_dev *dev = dev_id;
/* 硬中断上下文:只做最少的事 */
return IRQ_WAKE_THREAD; /* 唤醒线程处理 */
}
static irqreturn_t my_thread_fn(int irq, void *dev_id)
{
struct my_dev *dev = dev_id;
/* 线程上下文:可以睡眠、可以访问 I2C/SPI */
return IRQ_HANDLED;
}
static int my_probe(struct platform_device *pdev)
{
struct my_dev *dev = dev_get_drvdata(&pdev->dev);
int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_threaded_irq(&pdev->dev, irq,
my_handler, my_thread_fn,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"my-dev", dev);
if (ret)
return ret;
return 0;
}
4. Core 核心层:IRQ 的描述符、域与流控
4.1 Core 的职责
- 维护全局描述符表:
irq_desc_tree(radix tree)。 - 管理
irq_desc生命周期:alloc_desc()、free_desc()。 - 管理
irq_domain:irq_create_mapping()、irq_find_mapping()。 - 实现
request_threaded_irq()/free_irq()。 - 实现
enable_irq()/disable_irq()与嵌套计数。 - 提供 flow handler:
handle_level_irq、handle_fasteoi_irq、handle_edge_irq。 - 提供
/proc/interrupts与 debugfs。 - 提供 devres 自动资源管理。
4.2 描述符生命周期
text
alloc_desc(virq)
│ 分配 struct irq_desc
│ 初始化 lock / action / handle_irq
▼
irq_desc 可用
│ irq_domain_associate() 关联 hwirq
│ irq_set_chip_and_handler_name() 设置 chip 与 flow handler
▼
request_irq()
│ __setup_irq() 挂 action
▼
handler 被回调
│ free_irq()
▼
irq_desc 回收(通常不释放,内核中 virq 空间有限)
4.3 请求流程
text
Consumer: request_threaded_irq(virq, handler, thread_fn, flags, name, dev)
│
▼
__setup_irq(irq, desc, action)
│
├─ 检查共享中断标志
│ IRQF_SHARED 时,所有 action 必须都带 IRQF_SHARED
│
├─ 分配/初始化 irqaction
│ handler / thread_fn / dev_id / name / flags
│
├─ 若 thread_fn 非空:
│ ├─ 创建内核线程 irq/<irq>-<name>
│ └─ 设置 IRQ_ONESHOT 语义
│
├─ 调用 chip->irq_request_resources()(如 GPIO 占用)
│
├─ 调用 chip->irq_set_type() 设置触发类型
│
├─ 调用 chip->irq_startup() 或 irq_enable()
│
└─ 挂 action 到 desc->action
4.4 中断触发流程
text
硬件触发 GIC
│
▼
el1_irq (entry.S)
│
▼
handle_arch_irq() = gic_handle_irq()
│
▼
handle_domain_irq(domain, hwirq, regs)
│
├─ irq_find_mapping(domain, hwirq) → virq
│
├─ generic_handle_irq(virq)
│ └─ desc->handle_irq(virq, desc) → flow handler
│
▼
handle_fasteoi_irq(desc)
│
├─ chip->irq_ack()
├─ handle_irq_event(desc)
│ └─ 遍历 desc->action
│ ├─ action->handler(virq, dev_id) → primary
│ └─ 若返回 IRQ_WAKE_THREAD,唤醒线程
│
└─ chip->irq_eoi()
4.5 共享中断
当 IRQF_SHARED 设置时:
- 所有
request_irq必须带IRQF_SHARED且dev_id唯一; desc->action是链表,每个节点一个irqaction;- 触发时遍历链表,逐个调用
handler; - handler 必须自己判断是否是自己的中断。
4.6 线程化中断
线程化中断的关键点:
- primary handler 返回
IRQ_WAKE_THREAD; - Core 唤醒
irq/<irq>-<name>内核线程; - 线程调用
thread_fn; IRQF_ONESHOT保证线程结束前不 unmask。
线程化适用场景:
- 处理需要睡眠(I2C/SPI 访问);
- 处理时间较长;
- 需要与其他线程同步。
4.7 中断域
irq_domain 的三种类型:
| 类型 | revmap 结构 | 适用 |
|---|---|---|
| Linear | linear_revmap[] 数组 |
hwirq 连续、范围小 |
| Tree | radix_tree_root |
hwirq 稀疏、范围大 |
| No Map | 无 revmap | 直接使用 virq=hwirq |
层次化域:
irq_domain_create_hierarchy()创建子域;- 子域的
parent指向父域; - 子域中断触发时,先父域后子域。
4.8 通用 irqchip 库
generic-chip.c 为简单 irqchip 提供通用实现:
c
int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, int num_chips,
const char *name, irq_flow_handler_t handler,
int irq_flags_to_set, int irq_flags_to_clear,
int gc_flags);
void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, int clr, int set, int clr_grp);
struct irq_chip_generic *irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq);
int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
5. Provider API:irqchip 驱动如何注册
5.1 Provider 的核心类
| 类 | 作用 |
|---|---|
irq_chip |
硬件操作回调表:enable/disable/ack/mask/eoi/set_type |
irq_domain |
中断域:hwirq ↔ virq 映射 |
irq_domain_ops |
域回调:translate/alloc/map/free |
irq_fwspec |
固件无关的中断描述符 |
irq_chip_generic |
通用 irqchip 库的控制器抽象 |
5.2 注册流程
创建 irq_domain:
c
struct irq_domain *irq_domain_add_linear(struct device_node *of_node, unsigned int size,
const struct irq_domain_ops *ops, void *host_data);
struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
const struct irq_domain_ops *ops, void *host_data);
struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
unsigned int flags, unsigned int size,
struct fwnode_handle *fwnode,
const struct irq_domain_ops *ops,
void *host_data);
void irq_domain_remove(struct irq_domain *domain);
建立映射:
c
unsigned int irq_create_mapping(struct irq_domain *domain, irq_hw_number_t hwirq);
unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec);
unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data);
unsigned int irq_find_mapping(struct irq_domain *domain, irq_hw_number_t hwirq);
int irq_domain_associate(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq);
void irq_domain_disassociate(struct irq_domain *domain, unsigned int virq);
设置 chip 与 handler:
c
void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq, struct irq_chip *chip,
void *chip_data, irq_flow_handler_t handler,
void *handler_data, const char *handler_name);
int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq, struct irq_chip *chip,
void *chip_data);
void irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
irq_flow_handler_t handle, const char *name);
void irq_set_chained_handler_and_data(unsigned int irq,
irq_flow_handler_t handle, void *data);
分配描述符:
c
int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);
void irq_free_descs(unsigned int irq, unsigned int cnt);
通用 irqchip:
c
int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, int num_chips,
const char *name, irq_flow_handler_t handler,
int irq_flags_to_set, int irq_flags_to_clear,
int gc_flags);
void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, int clr, int set, int clr_grp);
per-CPU 与 NMI:
c
int irq_set_percpu_devid(unsigned int irq);
int request_nmi(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev);
xlate 辅助:
c
int irq_domain_xlate_onecell(...);
int irq_domain_xlate_twocell(...);
int irq_domain_xlate_onetwocell(...);
int irq_domain_translate_onecell(...);
int irq_domain_translate_twocell(...);
IRQCHIP_DECLARE:
c
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
void irqchip_init(void);
IRQCHIP_DECLARE 把 fn 注册到 __irqchip_of_table,irqchip_init() 在 init_IRQ() 阶段遍历匹配。
5.3 GICv3 注册流程
c
IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init) irq-gic-v3.c:2031
└ gic_of_init(np, parent)
├─ 映射 GICD/GICR 寄存器
├─ 初始化 redist_region[]
├─ gic_init_bases()
│ ├─ irq_domain_create_tree(&gic_irq_domain_ops, ...)
│ ├─ gic_chip / gic_eoimode1_chip 初始化
│ └─ set_handle_irq(gic_handle_irq)
└─ 注册 PPI9(维护中断)
6. UML 类图:从 Consumer 到 Provider
说明:Mermaid 类图中的
note描述类的作用;类图后的表格补充关键成员职责。
6.1 Consumer 侧类图
#mermaid-svg-G9LHsbEaXUvsCSgA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-G9LHsbEaXUvsCSgA .error-icon{fill:#552222;}#mermaid-svg-G9LHsbEaXUvsCSgA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-G9LHsbEaXUvsCSgA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-G9LHsbEaXUvsCSgA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-G9LHsbEaXUvsCSgA .marker.cross{stroke:#333333;}#mermaid-svg-G9LHsbEaXUvsCSgA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-G9LHsbEaXUvsCSgA p{margin:0;}#mermaid-svg-G9LHsbEaXUvsCSgA g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-G9LHsbEaXUvsCSgA g.classGroup text .title{font-weight:bolder;}#mermaid-svg-G9LHsbEaXUvsCSgA .cluster-label text{fill:#333;}#mermaid-svg-G9LHsbEaXUvsCSgA .cluster-label span{color:#333;}#mermaid-svg-G9LHsbEaXUvsCSgA .cluster-label span p{background-color:transparent;}#mermaid-svg-G9LHsbEaXUvsCSgA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-G9LHsbEaXUvsCSgA .cluster text{fill:#333;}#mermaid-svg-G9LHsbEaXUvsCSgA .cluster span{color:#333;}#mermaid-svg-G9LHsbEaXUvsCSgA .nodeLabel,#mermaid-svg-G9LHsbEaXUvsCSgA .edgeLabel{color:#131300;}#mermaid-svg-G9LHsbEaXUvsCSgA .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-G9LHsbEaXUvsCSgA .label text{fill:#131300;}#mermaid-svg-G9LHsbEaXUvsCSgA .labelBkg{background:#ECECFF;}#mermaid-svg-G9LHsbEaXUvsCSgA .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-G9LHsbEaXUvsCSgA .classTitle{font-weight:bolder;}#mermaid-svg-G9LHsbEaXUvsCSgA .node rect,#mermaid-svg-G9LHsbEaXUvsCSgA .node circle,#mermaid-svg-G9LHsbEaXUvsCSgA .node ellipse,#mermaid-svg-G9LHsbEaXUvsCSgA .node polygon,#mermaid-svg-G9LHsbEaXUvsCSgA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-G9LHsbEaXUvsCSgA .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA g.clickable{cursor:pointer;}#mermaid-svg-G9LHsbEaXUvsCSgA g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-G9LHsbEaXUvsCSgA g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-G9LHsbEaXUvsCSgA .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-G9LHsbEaXUvsCSgA .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-G9LHsbEaXUvsCSgA .dashed-line{stroke-dasharray:3;}#mermaid-svg-G9LHsbEaXUvsCSgA .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-G9LHsbEaXUvsCSgA #compositionStart,#mermaid-svg-G9LHsbEaXUvsCSgA .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #compositionEnd,#mermaid-svg-G9LHsbEaXUvsCSgA .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #dependencyStart,#mermaid-svg-G9LHsbEaXUvsCSgA .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #dependencyStart,#mermaid-svg-G9LHsbEaXUvsCSgA .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #extensionStart,#mermaid-svg-G9LHsbEaXUvsCSgA .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #extensionEnd,#mermaid-svg-G9LHsbEaXUvsCSgA .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #aggregationStart,#mermaid-svg-G9LHsbEaXUvsCSgA .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #aggregationEnd,#mermaid-svg-G9LHsbEaXUvsCSgA .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #lollipopStart,#mermaid-svg-G9LHsbEaXUvsCSgA .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA #lollipopEnd,#mermaid-svg-G9LHsbEaXUvsCSgA .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-G9LHsbEaXUvsCSgA .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-G9LHsbEaXUvsCSgA .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-G9LHsbEaXUvsCSgA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-G9LHsbEaXUvsCSgA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-G9LHsbEaXUvsCSgA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} handler
next
Irqaction
+handler : irq_handler_t
+dev_id : void
+percpu_dev_id : void __percpu
+next : Irqaction
+thread_fn : irq_handler_t
+thread : task_struct
+secondary : Irqaction
+irq : unsigned int
+flags : unsigned int
+thread_flags : unsigned long
+thread_mask : unsigned long
+name : const char
+dir : proc_dir_entry
<<typedef>>
IrqHandler
irqreturn_t (*)(int irq, void *dev_id)
一次 request_irq 的动作描述;共享中断时 next 形成链表。
消费者回调原型:irqreturn_t (int irq, void *dev_id)。
| 类 | 作用 | 关键成员说明 |
|---|---|---|
Irqaction |
动作描述 | handler primary;thread_fn threaded;dev_id cookie;next 共享中断链表;flags IRQF_* |
IrqHandler |
回调原型 | 返回 IRQ_HANDLED / IRQ_WAKE_THREAD |
6.2 Provider 侧类图
#mermaid-svg-9zezEFpJ95DowyIC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9zezEFpJ95DowyIC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9zezEFpJ95DowyIC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9zezEFpJ95DowyIC .error-icon{fill:#552222;}#mermaid-svg-9zezEFpJ95DowyIC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9zezEFpJ95DowyIC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9zezEFpJ95DowyIC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9zezEFpJ95DowyIC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9zezEFpJ95DowyIC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9zezEFpJ95DowyIC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9zezEFpJ95DowyIC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9zezEFpJ95DowyIC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9zezEFpJ95DowyIC .marker.cross{stroke:#333333;}#mermaid-svg-9zezEFpJ95DowyIC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9zezEFpJ95DowyIC p{margin:0;}#mermaid-svg-9zezEFpJ95DowyIC g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-9zezEFpJ95DowyIC g.classGroup text .title{font-weight:bolder;}#mermaid-svg-9zezEFpJ95DowyIC .cluster-label text{fill:#333;}#mermaid-svg-9zezEFpJ95DowyIC .cluster-label span{color:#333;}#mermaid-svg-9zezEFpJ95DowyIC .cluster-label span p{background-color:transparent;}#mermaid-svg-9zezEFpJ95DowyIC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9zezEFpJ95DowyIC .cluster text{fill:#333;}#mermaid-svg-9zezEFpJ95DowyIC .cluster span{color:#333;}#mermaid-svg-9zezEFpJ95DowyIC .nodeLabel,#mermaid-svg-9zezEFpJ95DowyIC .edgeLabel{color:#131300;}#mermaid-svg-9zezEFpJ95DowyIC .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-9zezEFpJ95DowyIC .label text{fill:#131300;}#mermaid-svg-9zezEFpJ95DowyIC .labelBkg{background:#ECECFF;}#mermaid-svg-9zezEFpJ95DowyIC .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-9zezEFpJ95DowyIC .classTitle{font-weight:bolder;}#mermaid-svg-9zezEFpJ95DowyIC .node rect,#mermaid-svg-9zezEFpJ95DowyIC .node circle,#mermaid-svg-9zezEFpJ95DowyIC .node ellipse,#mermaid-svg-9zezEFpJ95DowyIC .node polygon,#mermaid-svg-9zezEFpJ95DowyIC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9zezEFpJ95DowyIC .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC g.clickable{cursor:pointer;}#mermaid-svg-9zezEFpJ95DowyIC g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-9zezEFpJ95DowyIC g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-9zezEFpJ95DowyIC .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-9zezEFpJ95DowyIC .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-9zezEFpJ95DowyIC .dashed-line{stroke-dasharray:3;}#mermaid-svg-9zezEFpJ95DowyIC .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-9zezEFpJ95DowyIC #compositionStart,#mermaid-svg-9zezEFpJ95DowyIC .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #compositionEnd,#mermaid-svg-9zezEFpJ95DowyIC .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #dependencyStart,#mermaid-svg-9zezEFpJ95DowyIC .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #dependencyStart,#mermaid-svg-9zezEFpJ95DowyIC .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #extensionStart,#mermaid-svg-9zezEFpJ95DowyIC .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #extensionEnd,#mermaid-svg-9zezEFpJ95DowyIC .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #aggregationStart,#mermaid-svg-9zezEFpJ95DowyIC .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #aggregationEnd,#mermaid-svg-9zezEFpJ95DowyIC .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #lollipopStart,#mermaid-svg-9zezEFpJ95DowyIC .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC #lollipopEnd,#mermaid-svg-9zezEFpJ95DowyIC .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-9zezEFpJ95DowyIC .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-9zezEFpJ95DowyIC .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9zezEFpJ95DowyIC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9zezEFpJ95DowyIC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9zezEFpJ95DowyIC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} ops
parent
关联
IrqChip
+parent_device : device
+name : const char
+flags : unsigned long
+irq_startup()
+irq_shutdown()
+irq_enable()
+irq_disable()
+irq_ack()
+irq_mask()
+irq_mask_ack()
+irq_unmask()
+irq_eoi()
+irq_set_affinity()
+irq_retrigger()
+irq_set_type()
+irq_set_wake()
+irq_bus_lock()
+irq_bus_sync_unlock()
+irq_request_resources()
+irq_release_resources()
+irq_compose_msi_msg()
+irq_write_msi_msg()
+irq_get_irqchip_state()
+irq_set_irqchip_state()
IrqFwspec
+fwnode : fwnode_handle
+param_count : int
+param : u32\[\]
IrqDomainOps
+match()
+select()
+map()
+unmap()
+xlate()
+alloc()
+free()
+activate()
+deactivate()
+translate()
IrqDomain
+link : list_head
+name : const char
+ops : IrqDomainOps
+host_data : void
+flags : unsigned int
+mapcount : unsigned int
+fwnode : fwnode_handle
+parent : IrqDomain
+gc : irq_domain_chip_generic
+revmap_direct_max_irq : unsigned int
+revmap_size : unsigned int
+revmap_tree : radix_tree_root
+linear_revmap : unsigned int\[\]
硬件操作回调表:Provider 实现,Core 调度。
固件无关的中断描述符,由 DT 解析产生。
域回调:translate/alloc/map 是核心三件套。
中断域:hwirq ↔ virq 映射,支持层次化。
| 类 | 作用 | 关键成员说明 |
|---|---|---|
IrqChip |
硬件回调表 | irq_mask/irq_unmask 屏蔽;irq_ack/irq_eoi 应答;irq_set_type 触发类型;irq_set_affinity 亲和性 |
IrqFwspec |
固件描述 | fwnode 节点;param[] 参数(如 <type hwirq trigger>) |
IrqDomainOps |
域回调 | translate 解析;alloc 分配 virq;map 关联 chip;xlate 传统解析 |
IrqDomain |
中断域 | revmap hwirq→virq;parent 层次化;host_data Provider 私有 |
6.3 Core 层类图
#mermaid-svg-Qv7cfDLWxuqx1Jfb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .error-icon{fill:#552222;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .marker.cross{stroke:#333333;}#mermaid-svg-Qv7cfDLWxuqx1Jfb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Qv7cfDLWxuqx1Jfb p{margin:0;}#mermaid-svg-Qv7cfDLWxuqx1Jfb g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-Qv7cfDLWxuqx1Jfb g.classGroup text .title{font-weight:bolder;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .cluster-label text{fill:#333;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .cluster-label span{color:#333;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .cluster-label span p{background-color:transparent;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .cluster text{fill:#333;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .cluster span{color:#333;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .nodeLabel,#mermaid-svg-Qv7cfDLWxuqx1Jfb .edgeLabel{color:#131300;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .label text{fill:#131300;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .labelBkg{background:#ECECFF;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .classTitle{font-weight:bolder;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .node rect,#mermaid-svg-Qv7cfDLWxuqx1Jfb .node circle,#mermaid-svg-Qv7cfDLWxuqx1Jfb .node ellipse,#mermaid-svg-Qv7cfDLWxuqx1Jfb .node polygon,#mermaid-svg-Qv7cfDLWxuqx1Jfb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb g.clickable{cursor:pointer;}#mermaid-svg-Qv7cfDLWxuqx1Jfb g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-Qv7cfDLWxuqx1Jfb g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .dashed-line{stroke-dasharray:3;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #compositionStart,#mermaid-svg-Qv7cfDLWxuqx1Jfb .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #compositionEnd,#mermaid-svg-Qv7cfDLWxuqx1Jfb .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #dependencyStart,#mermaid-svg-Qv7cfDLWxuqx1Jfb .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #dependencyStart,#mermaid-svg-Qv7cfDLWxuqx1Jfb .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #extensionStart,#mermaid-svg-Qv7cfDLWxuqx1Jfb .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #extensionEnd,#mermaid-svg-Qv7cfDLWxuqx1Jfb .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #aggregationStart,#mermaid-svg-Qv7cfDLWxuqx1Jfb .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #aggregationEnd,#mermaid-svg-Qv7cfDLWxuqx1Jfb .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #lollipopStart,#mermaid-svg-Qv7cfDLWxuqx1Jfb .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb #lollipopEnd,#mermaid-svg-Qv7cfDLWxuqx1Jfb .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Qv7cfDLWxuqx1Jfb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Qv7cfDLWxuqx1Jfb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} irq_common_data
irq_data
action
chip
domain
chip_types
IrqDesc
+irq_common_data : IrqCommonData
+irq_data : IrqData
+kstat_irqs : unsigned int __percpu
+handle_irq : irq_flow_handler_t
+action : Irqaction
+status_use_accessors : unsigned int
+depth : unsigned int
+lock : raw_spinlock_t
+percpu_enabled : cpumask
+percpu_affinity : cpumask
+name : const char
+request_mutex : mutex
IrqCommonData
+state_use_accessors : unsigned int
+handler_data : void
+msi_desc : msi_desc
+affinity : cpumask_var_t
+effective_affinity : cpumask_var_t
IrqData
+mask : u32
+irq : unsigned int
+hwirq : unsigned long
+common : IrqCommonData
+chip : IrqChip
+domain : IrqDomain
+parent_data : IrqData
+chip_data : void
IrqChipGeneric
+lock : raw_spinlock_t
+reg_base : void __iomem
+irq_base : unsigned int
+irq_cnt : unsigned int
+mask_cache : u32
+type_cache : u32
+polarity_cache : u32
+num_ct : unsigned int
+private : void
+installed : unsigned long
+unused : unsigned long
+domain : IrqDomain
+list : list_head
+chip_types : IrqChipType\[\]
+reg_readl()
+reg_writel()
IrqChipType
+chip : IrqChip
+regs : IrqChipRegs
+handler : irq_flow_handler_t
+type : u32
+mask_cache : u32
Irqaction
IrqChip
IrqDomain
每个 Linux 中断号对应一个描述符。
下发给 irq_chip 回调的上下文。
通用 irqchip 库:批量管理简单 irqchip。
| 类 | 作用 | 关键成员说明 |
|---|---|---|
IrqDesc |
中断描述符 | action 动作链表;handle_irq flow handler;depth disable 嵌套;lock 保护 |
IrqCommonData |
公共数据 | handler_data;msi_desc;affinity |
IrqData |
回调上下文 | irq virq;hwirq 硬件号;chip/domain;chip_data |
IrqChipGeneric |
通用控制器 | reg_base;mask_cache;chip_types[] |
IrqChipType |
类型描述 | chip;regs;handler |
6.4 全局容器与流控类图
#mermaid-svg-utAlYhEWMzpnvgN4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-utAlYhEWMzpnvgN4 .error-icon{fill:#552222;}#mermaid-svg-utAlYhEWMzpnvgN4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-utAlYhEWMzpnvgN4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-utAlYhEWMzpnvgN4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-utAlYhEWMzpnvgN4 .marker.cross{stroke:#333333;}#mermaid-svg-utAlYhEWMzpnvgN4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-utAlYhEWMzpnvgN4 p{margin:0;}#mermaid-svg-utAlYhEWMzpnvgN4 g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-utAlYhEWMzpnvgN4 g.classGroup text .title{font-weight:bolder;}#mermaid-svg-utAlYhEWMzpnvgN4 .cluster-label text{fill:#333;}#mermaid-svg-utAlYhEWMzpnvgN4 .cluster-label span{color:#333;}#mermaid-svg-utAlYhEWMzpnvgN4 .cluster-label span p{background-color:transparent;}#mermaid-svg-utAlYhEWMzpnvgN4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-utAlYhEWMzpnvgN4 .cluster text{fill:#333;}#mermaid-svg-utAlYhEWMzpnvgN4 .cluster span{color:#333;}#mermaid-svg-utAlYhEWMzpnvgN4 .nodeLabel,#mermaid-svg-utAlYhEWMzpnvgN4 .edgeLabel{color:#131300;}#mermaid-svg-utAlYhEWMzpnvgN4 .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-utAlYhEWMzpnvgN4 .label text{fill:#131300;}#mermaid-svg-utAlYhEWMzpnvgN4 .labelBkg{background:#ECECFF;}#mermaid-svg-utAlYhEWMzpnvgN4 .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-utAlYhEWMzpnvgN4 .classTitle{font-weight:bolder;}#mermaid-svg-utAlYhEWMzpnvgN4 .node rect,#mermaid-svg-utAlYhEWMzpnvgN4 .node circle,#mermaid-svg-utAlYhEWMzpnvgN4 .node ellipse,#mermaid-svg-utAlYhEWMzpnvgN4 .node polygon,#mermaid-svg-utAlYhEWMzpnvgN4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-utAlYhEWMzpnvgN4 .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 g.clickable{cursor:pointer;}#mermaid-svg-utAlYhEWMzpnvgN4 g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-utAlYhEWMzpnvgN4 g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-utAlYhEWMzpnvgN4 .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-utAlYhEWMzpnvgN4 .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-utAlYhEWMzpnvgN4 .dashed-line{stroke-dasharray:3;}#mermaid-svg-utAlYhEWMzpnvgN4 .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-utAlYhEWMzpnvgN4 #compositionStart,#mermaid-svg-utAlYhEWMzpnvgN4 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #compositionEnd,#mermaid-svg-utAlYhEWMzpnvgN4 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #dependencyStart,#mermaid-svg-utAlYhEWMzpnvgN4 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #dependencyStart,#mermaid-svg-utAlYhEWMzpnvgN4 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #extensionStart,#mermaid-svg-utAlYhEWMzpnvgN4 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #extensionEnd,#mermaid-svg-utAlYhEWMzpnvgN4 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #aggregationStart,#mermaid-svg-utAlYhEWMzpnvgN4 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #aggregationEnd,#mermaid-svg-utAlYhEWMzpnvgN4 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #lollipopStart,#mermaid-svg-utAlYhEWMzpnvgN4 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 #lollipopEnd,#mermaid-svg-utAlYhEWMzpnvgN4 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-utAlYhEWMzpnvgN4 .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-utAlYhEWMzpnvgN4 .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-utAlYhEWMzpnvgN4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-utAlYhEWMzpnvgN4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-utAlYhEWMzpnvgN4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} <<global>>
IrqDescTree
radix_tree_root
<<global>>
HandleArchIrq
void (*)(struct pt_regs *)
<<global>>
IrqDefaultDomain
IrqDomain
<<typedef>>
FlowHandler
void (*)(struct irq_desc *)
HandleLevelIrq
handle_level_irq()
HandleFasteoiIrq
handle_fasteoi_irq()
HandleEdgeIrq
handle_edge_irq()
HandleSimpleIrq
handle_simple_irq()
全局 virq → irq_desc 的 radix tree。
异常入口:irqchip 通过 set_handle_irq 注册。
流控 handler:决定 ack/mask/eoi 的时序。
| 类 | 作用 | 关键说明 |
|---|---|---|
IrqDescTree |
全局容器 | irq_to_desc(virq) 查表 |
HandleArchIrq |
异常入口 | GIC 注册 gic_handle_irq |
FlowHandler |
流控 | 电平、边沿、fasteoi、simple 四种 |
HandleLevelIrq |
电平触发 | mask → handle → unmask |
HandleFasteoiIrq |
流控 eoi | ack → handle → eoi(GIC 常用) |
HandleEdgeIrq |
边沿触发 | ack → handle |
6.5 GICv3 专有类图
#mermaid-svg-gWYCFaNNOsCaT5F6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gWYCFaNNOsCaT5F6 .error-icon{fill:#552222;}#mermaid-svg-gWYCFaNNOsCaT5F6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gWYCFaNNOsCaT5F6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gWYCFaNNOsCaT5F6 .marker.cross{stroke:#333333;}#mermaid-svg-gWYCFaNNOsCaT5F6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gWYCFaNNOsCaT5F6 p{margin:0;}#mermaid-svg-gWYCFaNNOsCaT5F6 g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-gWYCFaNNOsCaT5F6 g.classGroup text .title{font-weight:bolder;}#mermaid-svg-gWYCFaNNOsCaT5F6 .cluster-label text{fill:#333;}#mermaid-svg-gWYCFaNNOsCaT5F6 .cluster-label span{color:#333;}#mermaid-svg-gWYCFaNNOsCaT5F6 .cluster-label span p{background-color:transparent;}#mermaid-svg-gWYCFaNNOsCaT5F6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gWYCFaNNOsCaT5F6 .cluster text{fill:#333;}#mermaid-svg-gWYCFaNNOsCaT5F6 .cluster span{color:#333;}#mermaid-svg-gWYCFaNNOsCaT5F6 .nodeLabel,#mermaid-svg-gWYCFaNNOsCaT5F6 .edgeLabel{color:#131300;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-gWYCFaNNOsCaT5F6 .label text{fill:#131300;}#mermaid-svg-gWYCFaNNOsCaT5F6 .labelBkg{background:#ECECFF;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-gWYCFaNNOsCaT5F6 .classTitle{font-weight:bolder;}#mermaid-svg-gWYCFaNNOsCaT5F6 .node rect,#mermaid-svg-gWYCFaNNOsCaT5F6 .node circle,#mermaid-svg-gWYCFaNNOsCaT5F6 .node ellipse,#mermaid-svg-gWYCFaNNOsCaT5F6 .node polygon,#mermaid-svg-gWYCFaNNOsCaT5F6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gWYCFaNNOsCaT5F6 .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 g.clickable{cursor:pointer;}#mermaid-svg-gWYCFaNNOsCaT5F6 g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-gWYCFaNNOsCaT5F6 g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-gWYCFaNNOsCaT5F6 .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-gWYCFaNNOsCaT5F6 .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-gWYCFaNNOsCaT5F6 .dashed-line{stroke-dasharray:3;}#mermaid-svg-gWYCFaNNOsCaT5F6 .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-gWYCFaNNOsCaT5F6 #compositionStart,#mermaid-svg-gWYCFaNNOsCaT5F6 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #compositionEnd,#mermaid-svg-gWYCFaNNOsCaT5F6 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #dependencyStart,#mermaid-svg-gWYCFaNNOsCaT5F6 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #dependencyStart,#mermaid-svg-gWYCFaNNOsCaT5F6 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #extensionStart,#mermaid-svg-gWYCFaNNOsCaT5F6 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #extensionEnd,#mermaid-svg-gWYCFaNNOsCaT5F6 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #aggregationStart,#mermaid-svg-gWYCFaNNOsCaT5F6 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #aggregationEnd,#mermaid-svg-gWYCFaNNOsCaT5F6 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #lollipopStart,#mermaid-svg-gWYCFaNNOsCaT5F6 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 #lollipopEnd,#mermaid-svg-gWYCFaNNOsCaT5F6 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-gWYCFaNNOsCaT5F6 .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-gWYCFaNNOsCaT5F6 .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gWYCFaNNOsCaT5F6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gWYCFaNNOsCaT5F6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gWYCFaNNOsCaT5F6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} domain
rdists
GicChipData
+domain : IrqDomain
+dist_base : void __iomem
+rdists : redist_region
+supports_deactivate : bool
+gicd_phys_base : phys_addr_t
+gicd_base : void __iomem
+nr_redist_regions : unsigned int
RedistRegion
+phys_base : phys_addr_t
+base : void __iomem
+rd_base : void __iomem
+sgi_base : void __iomem
+typer : u32
+nr_irqs : unsigned int
+RedistRegion* next
GicIrqDomainOps
+translate()
+alloc()
+free()
+activate()
+deactivate()
IrqDomain
GICv3 控制器数据:GICD 基址 + redist 区域。
GICR 重分发器:每 CPU 一个。
| 类 | 作用 | 关键成员说明 |
|---|---|---|
GicChipData |
GIC 控制器 | dist_base GICD;rdists GICR 链;domain 根域 |
RedistRegion |
重分发器 | rd_base/sgi_base;nr_irqs |
7. 设备树到内核结构体的映射
7.1 根中断控制器 DT
dts
gic: interrupt-controller@fd400000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>; /* <type hwirq trigger> */
#address-cells = <2>;
#size-cells = <2>;
ranges;
interrupt-controller;
reg = <0x0 0xfd400000 0 0x10000>, /* GICD */
<0x0 0xfd460000 0 0xc0000>; /* GICR */
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
its: interrupt-controller@fd440000 {
compatible = "arm,gic-v3-its";
msi-controller;
#msi-cells = <1>;
reg = <0x0 0xfd440000 0x0 0x20000>;
};
};
7.2 根中断控制器映射表
| DT 元素/属性 | 内核类/处理 |
|---|---|
compatible="arm,gic-v3" |
IRQCHIP_DECLARE → __irqchip_of_table → gic_of_init() |
interrupt-controller; |
根 irq_domain |
#interrupt-cells=<3> |
irq_domain_ops->translate 读取 <type,hwirq,trigger> |
reg = <GICD,GICR> |
gic_chip_data / redist_region[] |
interrupts=<GIC_PPI 9 ...> |
GIC 自身 PPI 中断 |
its(msi-controller) |
ITS MSI/LPI 域 |
7.3 消费者 DT(外设中断)
dts
usb_host0_ehci: usb@fd800000 {
interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
};
7.4 消费者映射流程
text
DT: interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>
│
│ GIC_SPI=0 / GIC_PPI=1 / GIC_SGI=2
▼
platform_get_irq() → of_irq_get(np, 0)
└ of_irq_parse_one() → of_phandle_args{np=&gic, args={0, 130, IRQ_TYPE_LEVEL_HIGH}}
└ 组装成 struct irq_fwspec{fwnode, param_count=3, param[]}
▼
irq_create_fwspec_mapping(&fwspec)
├ irq_find_matching_fwspec() → 找到 gic 的 irq_domain
├ domain->ops->translate() → hwirq=130, type=IRQ_TYPE_LEVEL_HIGH
├ domain->ops->alloc() → 分配 virq / 设置 chip
│ gic_irq_domain_map() → irq_domain_set_info(chip=&gic_chip,
│ handler=handle_fasteoi_irq, name="GICv3")
└ 返回 virq
▼
驱动拿到 virq → devm_request_irq(dev, virq, handler, flags, name, dev_id)
└ request_threaded_irq → __setup_irq → desc->action
7.5 GPIO 作为中断源(级联 / 层次化域)
dts
gpio1: gpio1@fe740000 {
compatible = "rockchip,gpio-bank";
gpio-controller;
#gpio-cells = <2>;
interrupt-controller; /* GPIO 自身也是中断控制器 */
#interrupt-cells = <2>; /* <pin trigger> */
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>; /* 父中断(GIC) */
};
sh3001_acc@36 {
interrupt-parent = <&gpio1>;
interrupts = <RK_PB0 IRQ_TYPE_LEVEL_HIGH>;
};
映射:
text
GPIO bank 的 interrupts = <GIC_SPI 34 ...> → 自身是 GIC 的一个 SPI,建立层次化子域
#interrupt-cells=<2> + interrupt-controller → gpio 驱动创建 irq_domain(IRQ_DOMAIN_FLAG_HIERARCHY)
parent = GIC 域
消费者 interrupt-parent=<&gpio1> + interrupts=<pin type>
└ irq_find_matching_fwspec → gpio 域 → translate → hwirq=pin
→ alloc → 分配 virq,chip=gpio 的 irq_chip
→ 父域(GIC)也分配对应 virq,形成 hierarchy
└ 运行时父 handler 调 generic_handle_irq(子 virq) 分发
(pinctrl/gpio-rockchip 的 rockchip_irq_demux 正是这种 chained/级联模式)
7.6 DT 说明符 → 域 → 描述符全过程
text
interrupts = <c 0/1/2, hwirq, trigger>
→ of_irq_parse_one() → of_phandle_args
→ struct irq_fwspec
→ irq_create_fwspec_mapping()
→ irq_find_matching_fwspec() 找 irq_domain
→ domain->ops->translate() → (hwirq, type)
→ domain->ops->alloc() → irq_domain_alloc_descs() 分配 virq
→ irq_domain_set_info() → 设置 irq_desc.irq_data.chip/handle_irq
→ virq 返回给驱动 → request_irq() → irq_desc.action
运行:
GIC 触发 → el1_irq/entry.S → handle_arch_irq = gic_handle_irq
→ handle_domain_irq(gic_data.domain, hwirq, regs)
→ irq_find_mapping() 得 virq
→ generic_handle_irq(virq) → desc->handle_irq(flow handler)
→ handle_irq_event() → irqaction->handler()
7.7 DT 与内核类映射总表
| DT 元素 | 内核类/字段 | 源码 |
|---|---|---|
compatible="arm,gic-v3" |
IRQCHIP_DECLARE → __irqchip_of_table |
irqchip.h:29、irqchip.c:31 |
interrupt-controller; |
根/层次化 irq_domain |
irqdomain.h:163 |
#interrupt-cells |
irq_domain_ops.translate/xlate 参数格式 |
irq-gic-v3.c:1560 |
reg = <GICD,GICR> |
gic_chip_data / redist_region |
irq-gic-v3.c:1969/1996 |
interrupts = <GIC_SPI N type> |
virq(通过 irq_create_fwspec_mapping) |
irqdomain.c:752 |
interrupt-parent = <&gic/&gpioX> |
irq_find_matching_fwspec 查找目标 |
irqdomain.c |
interrupt-names |
of_irq_get_byname() 的键 |
of_irq.h:47 |
msi-controller/#msi-cells |
ITS(irq-gic-v3-its.c)的 MSI 域 |
rk3568.dtsi:684 |
IRQ_TYPE_LEVEL_HIGH 等 |
irq_chip.irq_set_type() 的 flow_type |
irq-gic-v3.c:560 gic_set_type |
8. 调试与实操
8.1 proc / sysfs / debugfs
/proc/interrupts:所有 IRQ 的触发次数与 CPU 分布;/proc/irq/<N>/:单中断信息、smp_affinity、spurious;/sys/kernel/debug/irq/:debugfs 域与描述符信息。
8.2 常用命令
bash
# 查看所有中断
cat /proc/interrupts
# 查看单中断亲和性
cat /proc/irq/130/smp_affinity
# 设置亲和性
echo 2 > /proc/irq/130/smp_affinity
# 查看中断域
ls /sys/kernel/debug/irq/domains/
# 查看单中断详情
cat /sys/kernel/debug/irq/irqs/130
8.3 常见错误码
| 错误码 | 含义 | 处理 |
|---|---|---|
-ENOENT |
DT 中找不到 interrupts | 检查 interrupts / interrupt-parent |
-EPROBE_DEFER |
irqchip 未就绪 | 返回 -EPROBE_DEFER |
-EINVAL |
virq 无效或 flags 非法 | 检查 platform_get_irq 返回值 |
-EBUSY |
中断已被占用且非共享 | 检查 IRQF_SHARED |
-ENOMEM |
分配 irqaction 失败 | 检查内存 |
8.4 验证步骤
dmesg | grep -i gic确认 GIC 注册;cat /proc/interrupts确认中断已注册;cat /sys/kernel/debug/irq/domains/确认域已建立;- 触发设备中断,确认计数增长;
- 检查
spurious计数,确认无假中断; - 检查
smp_affinity,确认 CPU 分布合理。
9. 总结
IRQ 子系统的本质是:
用
irq_desc+irq_domain+irq_chip三层抽象,把"编号映射、描述符管理、流控、上下半部、级联、亲和性"全部收口到kernel/irq/。
理解 IRQ 的关键是抓住四条线:
- 句柄线 :
platform_get_irq()→virq→request_irq()→handler(); - 域线 :
irq_domain→translate→alloc→map→virq; - Provider 线 :
irq_chip→irq_domain_ops→IRQCHIP_DECLARE; - 异常线 :
entry.S→handle_arch_irq()→handle_domain_irq()→ flow handler →action->handler()。
掌握这四条线,再看 irq-gic-v3.c、kernel/irq/irqdomain.c、kernel/irq/manage.c 和 RK3568 的 GICD / GICR / ITS 寄存器,就能把 IRQ 子系统串起来。
附:关键源码位置速查
| 主题 | 位置 |
|---|---|
| Consumer API | include/linux/interrupt.h、include/linux/of_irq.h |
| Provider API | include/linux/irq.h、include/linux/irqdomain.h、include/linux/irqchip.h |
| 核心类 | include/linux/irqdesc.h:55、include/linux/irq.h:147/177/505、include/linux/irqdomain.h:64/106/163 |
| 描述符管理 | kernel/irq/irqdesc.c(irq_to_desc:351、alloc_desc:387、irq_desc_tree:344) |
| 域映射 | kernel/irq/irqdomain.c(irq_create_mapping_affinity:639、irq_find_mapping:884、irq_domain_set_info:1325) |
| 请求/使能 | kernel/irq/manage.c(request_threaded_irq:2041、free_irq:1921、enable_irq:724、disable_irq:637) |
| 流控 handler | kernel/irq/chip.c、kernel/irq/handle.c |
| 通用 irqchip | kernel/irq/generic-chip.c |
| GICv3 提供者 | drivers/irqchip/irq-gic-v3.c(gic_chip:1344、gic_irq_domain_ops:1559、gic_handle_irq:692、gic_init_bases:~1773、gic_of_init:1961、IRQCHIP_DECLARE:2031) |
| irqchip 框架 | drivers/irqchip/irqchip.c(irqchip_init:29、platform_irqchip_probe:35) |
| 体系结构入口 | arch/arm64/kernel/irq.c(init_IRQ:74)、arch/arm64/kernel/entry.S |
| RK3568 DTS | rk3568.dtsi(gic:673、usb_host0_ehci:692、gpio*:3760 起) |
如需,可以继续展开:irq-gic-v3.c 中 gic_handle_irq() 到 EOI/affinity 的寄存器级细节、kernel/irq/manage.c::__setup_irq() 的线程化/共享中断实现,或 GPIO 级联 irq_domain(hierarchy)在 gpio-rockchip.c 中的建立过程。