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 Answers
what is chained irq ?
There are two approaches how to call interrupt handlers for child devices in IRQ handler of parent (interrupt controller) device.
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
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 usesCHAINED GPIO irqchips
approach for handling systems with multiple GICs; this commit adds that functionalitygpio-omap
driver (mentioned above) usesGENERIC CHAINED GPIO irqchips
approach. See this commit. It was converted from using regularCHAINED 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
andchained_irq_exit
do
Those functions implement hardware interrupt flow control, i.e. notifying interrupt controller chip when to mask and unmask current interrupt.
For FastEOI interrupt controllers (most modern way):
chained_irq_enter()
do nothingchained_irq_exit()
callsirq_eoi()
callback to tell the interrupt controller that interrupt processing is finished
For interrupt controllers with mask/unmask/ack capabilities
chained_irq_enter()
masks current interrupt, and acknowledges it if ack callback is set as wellchained_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.
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(...);