什么是Linux irq域,为什么需要它们? [英] What are linux irq domains, why are they needed?

查看:128
本文介绍了什么是Linux irq域,为什么需要它们?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是irq域,我阅读了内核文档( https://www.他们说:

What are irq domains, i read kernel documentation (https://www.kernel.org/doc/Documentation/IRQ-domain.txt) they say:

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

The number of interrupt controllers registered as unique irqchips show a rising tendency: for example subdrivers of different kinds such as GPIO controllers avoid reimplementing identical callback mechanisms as the IRQ core system by modeling their interrupt handlers as irqchips, i.e. in effect cascading interrupt controllers.

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

How GPIO controller can be called as interrupt controller?

推荐答案

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

What are linux irq domains, why are they needed?

Documentation/IRQ-domain.txt ,因此我假设您已经知道.如果不是,请询问有关该文档的不清楚之处.下面的文字说明了如何使用IRQ域API及其工作原理.

It's documented perfectly in the first paragraph of Documentation/IRQ-domain.txt, so I will assume that you already know it. If no -- please ask what is unclear regarding that documentation. The text below explains how to use IRQ domain API and how it works.

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

How GPIO controller can be called as interrupt controller?

让我使用驱动程序作为参考(驱动程序代码).它是一个GPIO驱动程序,它的作用还类似于中断控制器,因此它应该是IRQ域API工作原理的一个很好的例子.

Let me answer this question using max732x.c driver as a reference (driver code). It's a GPIO driver and it also acts like interrupt controller, so it should be a good example of how IRQ domain API works.

为完全理解进一步的解释,让我们首先了解一下MAX732x的原理. 数据表的应用电路(在我们的示例中已简化):

To completely understand further explanation, let's first look into MAX732x mechanics. Application circuit from datasheet (simplified for our example):

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

When there is a change of voltage level on P0-P7 pins, MAX7325 will generate interrupt on INT pin. The driver (running on SoC) can read the status of P0-P7 pins via I2C (SCL/SDA pins) and generate separate interrupts for each of P0-P7 pins. This is why this driver acts as interrupt controller.

考虑下一个配置:

某些设备"改变P4引脚上的电平,以诱使MAX7325产生中断.来自MAX7325的中断连接到GPIO4 IP内核(在SoC内部),它使用该GPIO4模块的29号线通知CPU有关中断的信息.因此,可以说MAX7325是级联到GPIO4控制器. GPIO4还充当中断控制器,并级联到GIC中断控制器.

"Some device" changes level on P4 pin, tempting MAX7325 to generate interrupt. Interrupt from MAX7325 is connected to GPIO4 IP-core (inside of SoC), and it uses line #29 of that GPIO4 module to notify CPU about interrupt. So we can say that MAX7325 is cascaded to GPIO4 controller. GPIO4 also acts as interrupt controller, and it's cascaded to GIC interrupt controller.

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

Let's declare above configuration in device tree. We can use bindings from Documentation/devicetree/bindings/gpio/gpio-max732x.txt as reference:

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属性描述中断线连接
  • interrupt-controller property defines that device generates interrupts; it will be needed further to use this node as interrupt-parent in "Some device" node.
  • #interrupt-cells defines format of interrupts property; in our case it's 2: 1 cell for line number and 1 cell for interrupt type
  • interrupt-parent and interrupts properties are describing interrupt line connection

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

Let's say we have driver for MAX7325 and driver for "Some device". Both are running in CPU, of course. In "Some device" driver we want to request interrupt for event when "Some device" changes level on P4 pin of MAX7325. Let's first declare this in device tree:

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

中断传播

现在,我们可以执行以下操作(在某些设备"驱动程序中):

Interrupt propagation

Now we can do something like this (in "Some device" driver):

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

每当MAX7325的P4引脚上的电平从低到高(上升沿)时,都会调用

some_device_isr().怎么运行的?从左到右,如果您看上面的图片:

And some_device_isr() will be called each time when level on P4 pin of MAX7325 goes from low to high (rising edge). How it works? From left to the right, if you look to the picture above:

  • 某些设备"更改了MAX7325 P4的电平
  • MAX7325更改其INT引脚上的电平
  • GPIO4模块被配置为捕获此类更改,因此会生成GIC中断
  • GIC通知CPU

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

All those actions are happening on hardware level. Let's see what's happening on software level. It actually goes backwards (from right to the left on the picture):

  • 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处理程序(此处)调用handle_nested_irq(),以便连接到MAX7325的设备的所有IRQ处理程序(在我们的示例中为某些设备" IRQ处理程序)将在max732x_irq_handler()线程中调用
  • 最后,称为某些设备"驱动程序的IRQ处理程序
  • CPU now is in interrupt context in GIC interrupt handler. From gic_handle_irq() it calls handle_domain_irq(), which in turn calls generic_handle_irq(). See Documentation/gpio/driver.txt for details. Now we are in SoC's GPIO controller IRQ handler.
  • SoC's GPIO driver also calls generic_handle_irq() to run handler, which is set for each particular pin. See for example how it's done in omap_gpio_irq_handler(). Now we are in MAX7325 IRQ handler.
  • MAX7325 IRQ handler (here) calls handle_nested_irq(), so that all IRQ handlers of devices connected to MAX7325 ("Some device" IRQ handler, in our case) will be called in max732x_irq_handler() thread
  • finally, IRQ handler of "Some device" driver is called

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

GIC driver, GPIO driver and MAX7325 driver -- they all are using IRQ domain API to represent those drivers as interrupt controllers. Let's take a look how it's done in MAX732x driver. It was added in this commit. It's easy to figure out how it works just by reading IRQ domain documentation and looking to this commit. The most interesting part of that commit is this line (in max732x_irq_handler()):

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

irq_find_mapping()将按硬件IRQ号找到Linux IRQ号(使用IRQ域 mapping 功能).然后将调用handle_nested_irq()函数,该函数将运行某些设备"驱动程序的IRQ处理程序.

irq_find_mapping() will find linux IRQ number by hardware IRQ number (using IRQ domain mapping function). Then handle_nested_irq() function will be called, which will run IRQ handler of "Some device" driver.

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

Since many GPIO drivers are using IRQ domain in the same way, it was decided to extract that code to GPIOLIB framework, more specifically to GPIOLIB_IRQCHIP. From Documentation/gpio/driver.txt:

帮助处理GPIO irqchips和 关联的irqdomain和资源分配回调,gpiolib具有 可以通过选择GPIOLIB_IRQCHIP Kconfig启用一些帮助程序 符号:

To help out in handling the set-up and management of GPIO irqchips and the associated irqdomain and resource allocation callbacks, the gpiolib has some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig symbol:

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

  • gpiochip_irqchip_add(): adds an irqchip to a gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks need to embed the gpio_chip in its state container and obtain a pointer to the container using container_of(). (See Documentation/driver-model/design-patterns.txt)

gpiochip_set_chained_irqchip():为 来自父IRQ的gpio_chip并将struct gpio_chip*作为处理程序传递 数据. (请注意处理程序数据,因为irqchip数据很可能会被 父irqchip!)这是用于链接类型的芯片.这也用 如果NULL作为处理程序传递,则设置一个嵌套的irqchip.

gpiochip_set_chained_irqchip(): sets up a chained irq handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler data. (Notice handler data, since the irqchip data is likely used by the parent irqchip!) This is for the chained type of chip. This is also used to set up a nested irqchip if NULL is passed as handler.

commit在MAX732x驱动程序中将IRQ域API转换为GPIOLIB_IRQCHIP API.

This commit converts IRQ domain API to GPIOLIB_IRQCHIP API in MAX732x driver.

进一步的讨论在这里:

  • part 2
  • part 3

这篇关于什么是Linux irq域,为什么需要它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆