8
votes

What is chained IRQ ? What does chained_irq_enter and chained_irq_exit do, because after an interrupt is arised the IRQ line is disabled, but chained_irq_enter is calling functions related to masking interrupts. If the line is already disabled why to mask the interrupt ?

2
It's continuation of this question.Sam Protsenko
Next part is here.Sam Protsenko

2 Answers

11
votes

what is chained irq ?

There are two approaches how to call interrupt handlers for child devices in IRQ handler of parent (interrupt controller) device.

  1. Chained interrupts:

    • "chained" means that those interrupts are just chain of function calls (for example, SoC's GPIO module interrupt handler is being called from GIC interrupt handler, just as a function call)
    • generic_handle_irq() is used for interrupts chaining
    • child IRQ handlers are being called inside of parent HW IRQ handler
    • you can't call functions that may sleep in chained (child) interrupt handlers, because they are still in atomic context (HW interrupt)
    • this approach is commonly used in drivers for SoC's internal GPIO modules
  2. Nested interrupts

    • "nested" means that those interrupts can be interrupted by another interrupt; but they are not really HW IRQs, but rather threaded IRQs
    • handle_nested_irq() is used for creating nested interrupts
    • child IRQ handlers are being called inside of new thread created by handle_nested_irq() function; we need them to be run in process context, so that we can call sleeping bus functions (like I2C functions that may sleep)
    • you are able to call functions that may sleep inside of nested (child) interrupt handlers
    • this approach is commonly used in drivers for external chips, like GPIO expanders, because they are usually connected to SoC via I2C bus, and I2C functions may sleep

Speaking of drivers discussed above:

  • irq-gic driver uses CHAINED GPIO irqchips approach for handling systems with multiple GICs; this commit adds that functionality
  • gpio-omap driver (mentioned above) uses GENERIC CHAINED GPIO irqchips approach. See this commit. It was converted from using regular CHAINED GPIO irqchips so that on real-time kernel it will threaded IRQ handler, but on non-RT kernel it will be hard IRQ handler
  • 'gpio-max732x' driver uses NESTED THREADED GPIO irqchips approach

what does chained_irq_enter and chained_irq_exit do

Those functions implement hardware interrupt flow control, i.e. notifying interrupt controller chip when to mask and unmask current interrupt.

  1. For FastEOI interrupt controllers (most modern way):

    • chained_irq_enter() do nothing
    • chained_irq_exit() calls irq_eoi() callback to tell the interrupt controller that interrupt processing is finished
  2. For interrupt controllers with mask/unmask/ack capabilities

    • chained_irq_enter() masks current interrupt, and acknowledges it if ack callback is set as well
    • chained_irq_exit() unmasks interrupt

because after an interrupt is arised the irq line is disabled, but chained_irq_enter is calling functions related to masking interrupts if the line is already disabled why to mask the interrupt ?

IRQ line is disabled. But we still need to write to EOI register in the end of interrupt processing. Or send ACK for edge-level interrupts.

This explains why interrupts are disabled in interrupt handler.

2
votes

Read Linux kernel documentation itself for understanding these APIs:

https://www.kernel.org/doc/Documentation/gpio/driver.txt

  • CHAINED GPIO irqchips: these are usually the type that is embedded on an SoC. This means that there is a fast IRQ handler for the GPIOs that gets called in a chain from the parent IRQ handler, most typically the system interrupt controller. This means the GPIO irqchip is registered using irq_set_chained_handler() or the corresponding gpiochip_set_chained_irqchip() helper function, and the GPIO irqchip handler will be called immediately from the parent irqchip, while holding the IRQs disabled. The GPIO irqchip will then end up calling something like this sequence in its interrupt handler:

    static irqreturn_t tc3589x_gpio_irq(int irq, void *data)
        chained_irq_enter(...);
        generic_handle_irq(...);
        chained_irq_exit(...);