Linux驱动子系统:中断子系统 —— Consumer和Provider(005)

深入理解 Linux IRQ 中断子系统:设计思想、UML 类图与设备树映射

IRQ 子系统:先讲设计思想,再按 Consumer → Core → Provider → 异常入口 → DT 映射自上而下展开;关键类统一用 UML 类图描述,并说明类与成员职责;最后给出逻辑漏洞与修正清单。


1. IRQ 子系统设计思想

1.1 它要解决的核心问题

中断是 Linux 内核最核心、最底层的机制。它看起来只是"注册一个 handler",但一旦进入内核,就会遇到八类复杂问题:

  1. 硬件差异:GIC、GPIO 中断控制器、级联 irqchip、MSI/LPI、PCIe、PCI INTx,寄存器模型完全不同。
  2. 编号混乱 :硬件中断号 hwirq、Linux 虚拟中断号 virq、DT 里的 <type hwirq trigger>,三套编号必须统一。
  3. 中断域 :同一个 hwirq 在不同 irq_domain 下可能映射到不同 virq,必须用域来隔离。
  4. 级联与层次化 :GPIO 中断挂在 GIC 下,GIC 又挂在 ITS 下,形成多层 irq_domain 链。
  5. 上下半部分离:硬中断上下文不能睡眠,但很多设备处理需要睡眠,必须拆成 primary handler + threaded handler。
  6. 共享中断 :多个驱动共享一条 IRQ 线,irqaction 必须组成链表,逐个回调。
  7. 使能与嵌套disable_irq 必须支持嵌套,depth 计数必须精确。
  8. 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
  • Consumerdrivers/mmcusbi2cspinetgpio 等。
  • Corekernel/irq/,包括 irqdesc.cirqdomain.cmanage.cchip.chandle.c
  • Providerdrivers/irqchip/,如 irq-gic-v3.cirq-gic-v3-its.c、GPIO 级联 irqchip。
  • 异常入口arch/arm64/kernel/entry.Sarch/arm64/kernel/irq.c

1.3 核心抽象:hwirq / virq / irq_desc / irq_data / irq_chip

IRQ 子系统最有价值的抽象是这五层:

抽象 归属 语义
hwirq 硬件 硬件中断号,域内唯一
virq Core Linux 虚拟中断号,全局唯一
irq_desc Core 每个 virq 对应一个描述符,含 actionhandle_irq
irq_data Core 下发给 irq_chip 回调的上下文,含 hwirqchipdomain
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()virqhwirq 关联。

级联 / 层次化解决的是"父控制器的一个中断线,代表子控制器的一组中断":

text 复制代码
GIC (根域)
  └─ SPI 34(GPIO1 的父中断)
        └─ GPIO1 irq_domain(子域)
              ├─ pin0 → virq A
              ├─ pin1 → virq B
              └─ pin2 → virq C

运行时:

  1. GIC 触发 SPI 34;
  2. GIC 的 handle_fasteoi_irq 调用 GPIO1 的 chained handler;
  3. chained handler 读取 GPIO1 的中断状态寄存器;
  4. 对每个 pending pin 调用 generic_handle_irq(子 virq)
  5. 子 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 设计原则总结

  1. 描述符优先 :每个 virq 一个 irq_desc
  2. 域隔离hwirq 只在域内有效,virq 全局有效。
  3. 回调表驱动 :Provider 实现 irq_chip,Core 调度。
  4. 流控可替换handle_level_irqhandle_fasteoi_irqhandle_edge_irq 按需选择。
  5. 上下半部可分离request_threaded_irq 支持线程化。
  6. 级联与层次化:支持多层 irqchip 叠加。
  7. 资源自动化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 的职责

  1. 维护全局描述符表:irq_desc_tree(radix tree)。
  2. 管理 irq_desc 生命周期:alloc_desc()free_desc()
  3. 管理 irq_domainirq_create_mapping()irq_find_mapping()
  4. 实现 request_threaded_irq() / free_irq()
  5. 实现 enable_irq() / disable_irq() 与嵌套计数。
  6. 提供 flow handler:handle_level_irqhandle_fasteoi_irqhandle_edge_irq
  7. 提供 /proc/interrupts 与 debugfs。
  8. 提供 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_SHAREDdev_id 唯一;
  • desc->action 是链表,每个节点一个 irqaction
  • 触发时遍历链表,逐个调用 handler
  • handler 必须自己判断是否是自己的中断。

4.6 线程化中断

线程化中断的关键点:

  1. primary handler 返回 IRQ_WAKE_THREAD
  2. Core 唤醒 irq/<irq>-<name> 内核线程;
  3. 线程调用 thread_fn
  4. 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_DECLAREfn 注册到 __irqchip_of_tableirqchip_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_datamsi_descaffinity
IrqData 回调上下文 irq virq;hwirq 硬件号;chip/domainchip_data
IrqChipGeneric 通用控制器 reg_basemask_cachechip_types[]
IrqChipType 类型描述 chipregshandler

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_basenr_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_tablegic_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 中断
itsmsi-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:29irqchip.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_affinityspurious
  • /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 验证步骤

  1. dmesg | grep -i gic 确认 GIC 注册;
  2. cat /proc/interrupts 确认中断已注册;
  3. cat /sys/kernel/debug/irq/domains/ 确认域已建立;
  4. 触发设备中断,确认计数增长;
  5. 检查 spurious 计数,确认无假中断;
  6. 检查 smp_affinity,确认 CPU 分布合理。

9. 总结

IRQ 子系统的本质是:

irq_desc + irq_domain + irq_chip 三层抽象,把"编号映射、描述符管理、流控、上下半部、级联、亲和性"全部收口到 kernel/irq/

理解 IRQ 的关键是抓住四条线:

  1. 句柄线platform_get_irq()virqrequest_irq()handler()
  2. 域线irq_domaintranslateallocmapvirq
  3. Provider 线irq_chipirq_domain_opsIRQCHIP_DECLARE
  4. 异常线entry.Shandle_arch_irq()handle_domain_irq() → flow handler → action->handler()

掌握这四条线,再看 irq-gic-v3.ckernel/irq/irqdomain.ckernel/irq/manage.c 和 RK3568 的 GICD / GICR / ITS 寄存器,就能把 IRQ 子系统串起来。


附:关键源码位置速查

主题 位置
Consumer API include/linux/interrupt.hinclude/linux/of_irq.h
Provider API include/linux/irq.hinclude/linux/irqdomain.hinclude/linux/irqchip.h
核心类 include/linux/irqdesc.h:55include/linux/irq.h:147/177/505include/linux/irqdomain.h:64/106/163
描述符管理 kernel/irq/irqdesc.cirq_to_desc:351、alloc_desc:387、irq_desc_tree:344)
域映射 kernel/irq/irqdomain.cirq_create_mapping_affinity:639、irq_find_mapping:884、irq_domain_set_info:1325)
请求/使能 kernel/irq/manage.crequest_threaded_irq:2041、free_irq:1921、enable_irq:724、disable_irq:637)
流控 handler kernel/irq/chip.ckernel/irq/handle.c
通用 irqchip kernel/irq/generic-chip.c
GICv3 提供者 drivers/irqchip/irq-gic-v3.cgic_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.cirqchip_init:29、platform_irqchip_probe:35)
体系结构入口 arch/arm64/kernel/irq.cinit_IRQ:74)、arch/arm64/kernel/entry.S
RK3568 DTS rk3568.dtsigic:673、usb_host0_ehci:692、gpio*:3760 起)

如需,可以继续展开:irq-gic-v3.cgic_handle_irq() 到 EOI/affinity 的寄存器级细节、kernel/irq/manage.c::__setup_irq() 的线程化/共享中断实现,或 GPIO 级联 irq_domain(hierarchy)在 gpio-rockchip.c 中的建立过程。

相关推荐
草莓熊Lotso1 小时前
【Redis 进阶】主从复制深度解析:从配置落地到 PSYNC 同步原理
linux·开发语言·网络·数据库·redis·缓存·php
ShineWinsu1 小时前
对于Git:远程操作的超详细保姆级解析
linux·git·gitee·github·远程仓库·分布式版本控制系统·远程操作
小张成长计划..2 小时前
【Linux】21:进程间通信
linux
赵民勇2 小时前
systemd-sysusers命令详解
linux·运维
灿烂的贝壳2 小时前
FC SAN多路径负载均衡配置指南
linux
binqian2 小时前
【Linux】内核怎么管理侦听socket
linux·网络协议
j7~2 小时前
【Linux网络】三十七.TCP 协议通讯流程
linux·网络编程·三次握手·四次挥手·tcp 协议通讯流程
顶点多余3 小时前
9.15 面试问题总结(一面挂)
linux·面试·职场和发展
顺风尿一寸3 小时前
从 ls -U 到 Tomcat libs加载jar包:ext4 目录哈希序如何影响 Java 文件排序顺序
linux·jvm