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

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

注册为唯一irqchips的中断控制器的数量呈上升趋势:例如,GPIO控制器等不同types的子驱动程序通过将它们的中断处理程序build模为irqchips(即有效的级联中断控制器),避免重新实现与IRQ核心系统相同的callback机制。

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

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

在Documentation / IRQ-domain.txt的第一段中有详细记录 ,所以我会假设你已经知道了。 如果不是,请询问关于该文档的内容。 下面的文本解释了如何使用IRQ域API以及它是如何工作的。

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

让我使用max732x.c驱动程序作为参考( 驱动程序代码 )来回答这个问题。 这是一个GPIO驱动程序,它也像中断控制器一样,所以它应该是IRQ域API如何工作的一个很好的例子。

体能水平

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

MAX7325典型应用电路

当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>; }; 

属性的含义如下:

  • 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() P4引脚上的电平从低电平变为高电平(上升沿)时,会调用some_device_isr()。 怎么运行的? 从左到右,如果你看上面的图片:

  • 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中断处理程序。
  • MAX7325 IRQ处理程序( 在这里 )调用handle_nested_irq() ,以便连接到MAX7325的设备(在本例中为“某个设备”IRQ处理程序handle_nested_irq()所有IRQ处理程序将在max732x_irq_handler()线程
  • 最后,调用“Some device”驱动程序的IRQ处理程序

IRQ域API

GIC驱动程序,GPIO驱动程序和MAX7325驱动程序 – 他们都使用IRQ域API来将这些驱动程序表示为中断控制器。 让我们来看看在MAX732x驱动程序中是如何完成的。 它在这个提交中被添加了。 通过阅读IRQ域的文档并寻找这个提交,很容易弄清楚它是如何工作的。 该提交最有趣的部分是这一行(在max732x_irq_handler() )中:

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

irq_find_mapping()将通过硬件IRQ号(使用IRQ域映射函数)来查找linux IRQ号。 然后handle_nested_irq()函数将被调用,这将运行“某些设备”驱动程序的IRQ处理程序。

GPIOLIB_IRQCHIP

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

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

  • gpiochip_irqchip_add() :增加一个irqchip到gpiochip。 它会将芯片的struct gpio_chip*传递给所有IRQ回调struct gpio_chip* ,所以回调gpio_chip需要将gpio_chip嵌入到状态容器中,并使用container_of()获取指向容器的指针。 (请参阅Documentation/driver-model/design-patterns.txt

  • gpiochip_set_chained_irqchip() :从父IRQ为gpio_chip设置一个链接的irq处理程序,并将struct gpio_chip*作为处理程序数据传递。 (通知处理程序数据,因为irqchip数据很可能被父级irqchip使用!)这是针对链接类型的芯片。 如果NULL作为处理程序传递,这也用于设置一个嵌套的irqchip。

该提交将IRQ域API转换为MAX732x驱动程序中的GPIOLIB_IRQCHIP API。

下一个问题

进一步的讨论在这里:

  • 第2部分
  • 第3部分

这是我在include / linux / irqdomain.h中找到的一个注释:

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

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