当前位置: 首页 > article >正文

Linux基础 -- 中断子系统之级联中断

Linux 级联中断 (irq_set_chained_handler_and_data) 详解

1. irq_set_chained_handler_and_data() 介绍

1.1. API 定义

void irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handler, void *data);
  • 参数

    • irq:需要绑定处理函数的中断号(通常是主中断控制器的 IRQ)。
    • handler:级联处理函数,在该 IRQ 触发时被调用。
    • data:传递给 handler 的私有数据。
  • 功能

    • 绑定 handlerirq,在 irq 触发时调用。
    • 适用于级联中断控制器,处理主控制器 IRQ 并触发次级控制器中断。
  • 作用

    • 用于 级联(Cascaded)中断控制器,如 GPIO 控制器、FPGA 软核等。
    • 多级中断控制(如 ARM GIC + GPIO 控制器)中,GPIO 控制器通常级联到 GIC。

2. 级联(Cascaded)中断的实现全过程

2.1. 级联中断背景

  • 主中断控制器(Primary Interrupt Controller)
    • 例如 ARM GIC(Generic Interrupt Controller)。
  • 次级(子)中断控制器(Secondary Interrupt Controller)
    • 例如 GPIO 控制器、FPGA 软核中断控制器等。

2.2. 级联中断工作流程

  1. 设备触发次级中断控制器上的中断
  2. 次级中断控制器向主中断控制器发送中断请求
  3. 主中断控制器检测到 IRQ,调用 irq_set_chained_handler_and_data() 绑定的处理函数
  4. 级联处理函数读取次级中断控制器状态
  5. 触发适当的次级 IRQ 处理

3. 级联中断完整实现

3.1. 设备树 (DTS) 配置

my_gpio: gpio-controller@10000000 {
    compatible = "mycompany,my-gpio";
    reg = <0x10000000 0x1000>;
    interrupt-parent = <&gic>;
    interrupts = <30 IRQ_TYPE_LEVEL_HIGH>; /* 级联到 GIC 的 IRQ */
    gpio-controller;
    #gpio-cells = <2>;
    interrupt-controller;
    #interrupt-cells = <2>;
};

3.2. 级联中断驱动实现

(1) 绑定 irq_set_chained_handler_and_data()
static struct irq_chip my_gpio_irq_chip = {
    .name = "my-gpio",
    .irq_mask = my_gpio_mask_irq,
    .irq_unmask = my_gpio_unmask_irq,
    .irq_ack = my_gpio_ack_irq,
};

static void my_gpio_irq_handler(struct irq_desc *desc)
{
    struct irq_chip *chip = irq_desc_get_chip(desc);
    struct my_gpio_chip *gpio = irq_desc_get_handler_data(desc);
    unsigned int irq;

    /* Acknowledge 主控制器 */
    chained_irq_enter(chip, desc);

    /* 读取次级控制器的 IRQ 状态 */
    irq = my_gpio_read_irq_status(gpio);

    /* 触发子级中断 */
    if (irq)
        generic_handle_irq(irq);

    /* 退出中断 */
    chained_irq_exit(chip, desc);
}

static int my_gpio_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct my_gpio_chip *gpio;
    int parent_irq;

    gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
    if (!gpio)
        return -ENOMEM;

    /* 获取主中断控制器 IRQ 号 */
    parent_irq = platform_get_irq(pdev, 0);
    if (parent_irq < 0)
        return parent_irq;

    /* 绑定级联中断处理函数 */
    irq_set_chained_handler_and_data(parent_irq, my_gpio_irq_handler, gpio);

    return 0;
}
(2) 触发子级中断
static irqreturn_t my_gpio_irq_handler(int irq, void *dev_id)
{
    unsigned int child_irq = get_mapped_irq_for_gpio(irq);

    if (child_irq)
        generic_handle_irq(child_irq);

    return IRQ_HANDLED;
}

4. 关键 API 解析

(1) irq_set_chained_handler_and_data()

  • 绑定 handlerirq,用于在 irq 触发时自动执行。
  • 只能用于级联中断,不可用于普通设备 IRQ 处理

(2) generic_handle_irq(irq)

  • 触发子级 IRQ,通知 irq_desc 进行处理。

(3) chained_irq_enter() / chained_irq_exit()

  • 进入/退出链式中断处理,确保正确处理 主控制器的 IRQ 处理流程

5. 级联中断的完整流程

  1. 外设触发子控制器 IRQ(如 GPIO 中断)。
  2. 子控制器触发主控制器 IRQ(如 GIC_IRQ_30)。
  3. 主控制器调用 my_gpio_irq_handler()
  4. my_gpio_irq_handler() 读取子控制器状态
  5. generic_handle_irq() 触发子 IRQ 进行处理
  6. 子 IRQ 驱动完成处理

6. 总结

  • irq_set_chained_handler_and_data() 主要用于 绑定级联中断处理函数,不用于普通设备 IRQ 处理。
  • 级联中断需要 主控制器和次级控制器配合,手动调用 generic_handle_irq() 处理子级 IRQ。
  • chained_irq_enter()/chained_irq_exit() 需要在 主 IRQ 处理前后调用 以保证正确性。
  • irq_chip 结构体定义了 子控制器的中断管理方式(屏蔽、中断确认等)。

http://www.kler.cn/a/556465.html

相关文章:

  • 【问题】Qt c++ 因编码问题解析json失败
  • 多环境日志管理:使用Logback与Logstash集成实现高效日志处理
  • 《炒股养家心法.pdf》 kimi总结
  • 腾讯云开源Deepseek-V3与R1大模型API免费使用 + Chatbox本地化部署指南:从零到一的AI探索之旅
  • stm32单片机个人学习笔记16(SPI通信协议)
  • 论文解读 | AAAI'25 Cobra:多模态扩展的大型语言模型,以实现高效推理
  • ZLG嵌入式笔记 | 为什么你的网卡工作会不正常?(中)
  • Mysql测试连接失败
  • 【Day45 LeetCode】图论问题 Ⅲ
  • 为什么要用 const 和 let,而不是 var?
  • 使用 Docker 部署 Apache Spark 集群教程
  • 2025寒假天梯训练7
  • Python应用算法之贪心算法理解和实践
  • [Android] Battery Guru - 手机电量管理优化
  • 【愚公系列】《Python网络爬虫从入门到精通》022-Splash的爬虫应用
  • 后“智驾平权”时代,谁为安全冗余和体验升级“买单”
  • 跳表的C语言实现
  • Java还是网络安全 java 网络安全面试题
  • 杰和科技GAM-AI视觉识别管理系统,让AI走进零售营销
  • 【算法与数据结构】字典树(Trie)详解