val*_*iki 7 linux interrupt linux-device-driver linux-kernel embedded-linux
什么是irq域,我读了内核文档(https://www.kernel.org/doc/Documentation/IRQ-domain.txt),他们说:
注册为唯一irqchips的中断控制器的数量显示出上升趋势:例如,GPIO控制器等不同类型的子驱动器通过将其中断处理程序建模为irqchips,即实际上是级联中断控制器,避免重新实现与IRQ核心系统相同的回调机制.
如何将GPIO控制器称为中断控制器?
Sam*_*nko 29
什么是linux irq域名,为什么需要它们?
它在Documentation/IRQ-domain.txt的第一段中完美记录,因此我假设您已经知道它.如果不是 - 请询问有关该文档的不清楚之处.下面的文本说明了如何使用IRQ域API及其工作原理.
如何将GPIO控制器称为中断控制器?
让我用max732x.c驱动程序作为参考(驱动程序代码)来回答这个问题.它是一个GPIO驱动程序,它也像中断控制器,所以它应该是IRQ域API如何工作的一个很好的例子.
为了完全理解进一步的解释,我们先来看看MAX732x的机制.数据表中的应用电路(我们的示例简化):
当P0-P7引脚上的电压电平发生变化时,MAX7325将在INT引脚上产生中断.驱动器(在SoC上运行)可以通过I2C(SCL/SDA引脚)读取P0-P7引脚的状态,并为每个P0-P7引脚产生单独的中断.这就是此驱动程序充当中断控制器的原因.
考虑下一个配置:
"某些器件"在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>;
};
Run Code Online (Sandbox Code Playgroud)
属性的含义如下:
interrupt-controllerproperty定义该设备生成中断; 需要进一步使用此节点,如interrupt-parent"某些设备"节点.#interrupt-cells定义interrupts财产的格式; 在我们的例子中,它是2:1个单元用于行号,1个单元用于中断类型interrupt-parent和interrupts属性描述中断线连接假设我们有MAX7325的驱动程序和"Some device"的驱动程序.当然,两者都在CPU中运行.在"Some device"驱动程序中,当"某些器件"在MAX7325的P4引脚上改变电平时,我们要求事件中断.让我们首先在设备树中声明:
some_device: some_device@1c {
reg = <0x1c>;
interrupt-parent = <&expander>;
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
};
Run Code Online (Sandbox Code Playgroud)
现在我们可以做这样的事情(在"Some device"驱动程序中):
devm_request_threaded_irq(core->dev, core->gpio_irq, NULL,
some_device_isr, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(core->dev), core);
Run Code Online (Sandbox Code Playgroud)
some_device_isr()每当MAX7325的P4引脚电平从低电平变为高电平(上升沿)时,将被调用.这个怎么运作?从左到右,如果您查看上图:
所有这些操作都发生在硬件级别上.让我们看看软件层面发生了什么.它实际上是倒退的(从图片的右侧到左侧):
handle_domain_irq(),然后调用generic_handle_irq().有关详细信息,请参阅Documentation/gpio/driver.txt.现在我们在SoC的GPIO控制器IRQ处理程序中.generic_handle_irq()运行处理程序,该处理程序为每个特定引脚设置.例如,请参阅omap_gpio_irq_handler()中的完成方式.现在我们在MAX7325 IRQ处理程序中.handle_nested_irq(),以便连接到MAX7325的设备的所有IRQ处理程序(在我们的例子中为"某些设备"IRQ处理程序)将在max732x_irq_handler()线程中调用GIC驱动程序,GPIO驱动程序和MAX7325驱动程序 - 它们都使用IRQ域API将这些驱动程序表示为中断控制器.我们来看看它是如何在MAX732x驱动程序中完成的.它已添加到此提交中.通过阅读IRQ域文档并查看此提交,很容易弄清楚它是如何工作的.该提交中最有趣的部分是这一行(in max732x_irq_handler()):
handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain, level));
Run Code Online (Sandbox Code Playgroud)
irq_find_mapping()将通过硬件IRQ号找到linux IRQ号(使用IRQ域映射功能).然后handle_nested_irq()将调用函数,它将运行"Some device"驱动程序的IRQ处理程序.
由于许多GPIO驱动程序以相同的方式使用IRQ域,因此决定将该代码提取到GPIOLIB框架,更具体地说是GPIOLIB_IRQCHIP.来自Documentation/gpio/driver.txt:
为了帮助处理GPIO irqchips的设置和管理以及相关的irqdomain和资源分配回调,gpiolib有一些帮助器可以通过选择
GPIOLIB_IRQCHIPKconfig符号来启用:
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 设置一个链式irq处理程序, 并传递struct gpio_chip*as处理程序数据.(注意处理程序数据,因为irqchip数据很可能被父irqchip使用!)这是针对链式芯片的.如果NULL作为处理程序传递,这也用于设置嵌套的irqchip .
此提交将IRQ域API转换为MAX732x驱动程序中的GPIOLIB_IRQCHIP API.
进一步讨论如下:
小智 1
这是我在include/linux/irqdomain.h中找到的评论:
中断控制器“域”数据结构。这可以定义为 irq 域控制器。也就是说,它处理给定中断域的硬件和虚拟中断号之间的映射。
我认为它指的是 irq_domain 的实际结构。