【问题标题】:What are linux irq domains, why are they needed?什么是 linux irq 域,为什么需要它们?
【发布时间】:2016-04-07 07:51:01
【问题描述】:

什么是 irq 域,我阅读内核文档 (https://www.kernel.org/doc/Documentation/IRQ-domain.txt) 他们说:

注册为唯一 irqchips 的中断控制器的数量 呈上升趋势:例如不同种类的子驱动程序 例如 GPIO 控制器避免重新实现相同的回调 通过对其中断建模作为 IRQ 核心系统的机制 处理程序作为 irqchips,即实际上级联中断控制器。

GPIO 控制器如何被称为中断控制器?

【问题讨论】:

    标签: linux linux-kernel linux-device-driver embedded-linux interrupt


    【解决方案1】:

    什么是 linux irq 域,为什么需要它们?

    Documentation/IRQ-domain.txt 的第一段完美地记录了它,所以我假设你已经知道了。如果不是 - 请询问关于该文档的不清楚之处。下面的文字解释了如何使用 IRQ 域 API 以及它是如何工作的。

    GPIO 控制器如何被称为中断控制器?

    让我以 驱动程序作为参考(driver code)来回答这个问题。它是一个 GPIO 驱动程序,它也充当中断控制器,因此它应该是 IRQ 域 API 工作原理的一个很好的例子。

    体力水平

    为了完全理解进一步的解释,让我们先来看看 MAX732x 的机制。来自datasheet的应用电路(为我们的例子做了简化):

    当P0-P7 引脚电压电平发生变化时,MAX7325 将在INT 引脚产生中断。驱动程序(在 SoC 上运行)可以通过 I2C(SCL/SDA 引脚)读取 P0-P7 引脚的状态,并为每个 P0-P7 引脚生成单独的中断。这就是该驱动程序充当中断控制器的原因。

    考虑下一个配置:

    “Some device”改变 P4 引脚的电平,诱使 MAX7325 产生中断。来自 MAX7325 的中断连接到 GPIO4 IP 内核(SoC 内部),它使用该 GPIO4 模块的第 29 行来通知 CPU 中断。所以我们可以说 MAX7325 级联到 GPIO4 控制器。 GPIO4也作为中断控制器,级联到GIC中断控制器。

    设备树

    让我们在设备树中声明上述配置。我们可以使用来自Documentation/devicetree/bindings/gpio/gpio-max732x.txt 的绑定作为参考:

    expander: max7325@6d {
        compatible = "maxim,max7325";
        reg = <0x6d>;
    
        gpio-controller;
        #gpio-cells = <2>;
    
        interrupt-controller;
        #interrupt-cells = <2>;
    
        interrupt-parent = <&gpio4>;
        interrupts = <29 IRQ_TYPE_EDGE_FALLING>;
    };
    

    属性含义如下:

    • interrupt-controller 属性定义设备产生中断;需要进一步将此节点用作“某些设备”节点中的interrupt-parent
    • #interrupt-cells 定义interrupts 属性的格式;在我们的例子中是2:1 个单元格用于行号,1 个单元格用于中断类型
    • interrupt-parentinterrupts 属性描述中断线连接

    假设我们有 MAX7325 的驱动程序和“某些设备”的驱动程序。当然,两者都在 CPU 中运行。在“Some device”驱动程序中,当“Some device”在 MAX7325 的 P4 引脚上改变电平时,我们希望请求中断事件。让我们首先在设备树中声明它:

    some_device: some_device@1c {
        reg = <0x1c>;
        interrupt-parent = <&expander>;
        interrupts = <4 IRQ_TYPE_EDGE_RISING>;
    };
    

    中断传播

    现在我们可以这样做(在“某些设备”驱动程序中):

    devm_request_threaded_irq(core->dev, core->gpio_irq, NULL,
            some_device_isr, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
            dev_name(core->dev), core);
    

    some_device_isr()会在每次MAX7325的P4引脚电平由低变高(上升沿)时被调用。这个怎么运作?如果你看上图,从左到右:

    • “Some device”在 MAX7325 的 P4 上改变电平
    • MAX7325 改变其 INT 引脚的电平
    • GPIO4 模块被配置为捕捉这样的变化,因此它会对 GIC 产生中断
    • GIC 通知 CPU

    所有这些操作都发生在硬件级别。让我们看看在软件层面发生了什么。它实际上是倒退的(图片上从右到左):

    • CPU 现在处于 GIC 中断处理程序的中断上下文中。它从gic_handle_irq() 调用handle_domain_irq(),而后者又调用generic_handle_irq()。有关详细信息,请参阅Documentation/gpio/driver.txt。现在我们在 SoC 的 GPIO 控制器 IRQ 处理程序中。
    • SoC 的 GPIO 驱动程序还调用generic_handle_irq() 来运行为每个特定引脚设置的处理程序。例如在omap_gpio_irq_handler() 中查看它是如何完成的。现在我们在 MAX7325 IRQ 处理程序中。
    • MAX7325 IRQ 处理程序 (here) 调用handle_nested_irq(),因此连接到 MAX7325 的设备的所有 IRQ 处理程序(在我们的例子中为“某些设备”IRQ 处理程序)将在max732x_irq_handler() 线程中调用
    • 最后,“某些设备”驱动程序的 IRQ 处理程序被调用

    IRQ 域 API

    GIC 驱动程序、GPIO 驱动程序和 MAX7325 驱动程序——它们都使用 IRQ 域 API 将这些驱动程序表示为中断控制器。让我们看看它是如何在MAX732x驱动中完成的。它是在this 提交中添加的。只需阅读 IRQ 域文档并查看此提交,就很容易弄清楚它是如何工作的。该提交中最有趣的部分是这一行(max732x_irq_handler()):

    handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain, level));
    

    irq_find_mapping() 将通过硬件 IRQ 号查找 linux IRQ 号(使用 IRQ 域 ma​​pping 功能)。然后将调用handle_nested_irq() 函数,该函数将运行“某些设备”驱动程序的 IRQ 处理程序。

    GPIOLIB_IRQCHIP

    由于许多 GPIO 驱动程序都以相同的方式使用 IRQ 域,因此决定将该代码提取到 GPIOLIB 框架,更具体地说,提取到 GPIOLIB_IRQCHIP。来自Documentation/gpio/driver.txt

    帮助处理 GPIO irqchips 的设置和管理以及 相关的 irqdomain 和资源分配回调,gpiolib 有 一些可以通过选择GPIOLIB_IRQCHIP Kconfig 来启用的助手 符号:

    • gpiochip_irqchip_add():将 irqchip 添加到 gpiochip。会过去的 struct gpio_chip* 用于所有 IRQ 回调的芯片,所以回调 需要在其状态容器中嵌入gpio_chip 并获取一个指针 使用container_of() 到容器。 (见Documentation/driver-model/design-patterns.txt

    • gpiochip_set_chained_irqchip():为一个 gpio_chip 来自父 IRQ 并将 struct gpio_chip* 作为处理程序传递 数据。 (注意处理程序数据,因为 irqchip 数据很可能被 parent irqchip!)这是针对链式芯片的。这也被使用 如果 NULL 作为处理程序传递,则设置嵌套的 irqchip。

    This commit 将 IRQ 域 API 转换为 MAX732x 驱动程序中的 GPIOLIB_IRQCHIP API。

    下一个问题

    这里有进一步的讨论:

    【讨论】:

    • 非常感谢,什么是链式中断? chained_irq_enter 和chained_irq_exit 是做什么的,因为在产生中断后,irq 线被禁用,但是如果该线已经被禁用,chained_irq_enter 正在调用与屏蔽中断相关的函数 为什么要屏蔽中断?
    【解决方案2】:

    这是我在 include/linux/irqdomain.h 中找到的一条评论:

    中断控制器“域”数据结构。这可以定义为 一个 irq 域控制器。也就是说,它处理之间的映射 给定中断域的硬件和虚拟中断号。

    我认为它所指的实际结构是 irq_domain。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 2017-02-24
      • 2011-08-19
      • 2017-08-24
      • 2023-03-04
      相关资源
      最近更新 更多