Interrupt Protection

Disabling interrupts in the CPU

The local_irq_save() and local_irq_disable() helpers are no more disabling interrupts in the CPU when interrupt pipelining is enabled, but only disable interrupt events virtually for the root stage.

A set of helpers is provided for manipulating the interrupt disable flag in the CPU instead. When CONFIG_IRQ_PIPELINE is disabled, this set maps 1:1 over the regular local_irq_*() API.

Original/Virtual Non-virtualized call
local_save_flags(flags) flags = hard_local_save_flags()
local_irq_disable() hard_local_irq_disable()
local_irq_enable() hard_local_irq_enable()
local_irq_save(flags) flags = hard_local_irq_save()
local_irq_restore(flags) hard_local_irq_restore(flags)
irqs_disabled() hard_irqs_disabled()
irqs_disabled_flags(flags) hard_irqs_disabled_flags(flags)

Stalling the head stage

Just like the root stage is affected by the state of the virtual interrupt disable flag, the interrupt state of the head stage is controlled by a dedicated stall bit flag in the head stage’s status. In combination with the interrupt disable bit in the CPU, this software bit controls interrupt delivery to the head stage.

When this stall bit is set, interrupts which might be pending in the head stage’s event log of the current CPU are not played. Conversely, the out-of-band handlers attached to pending IRQs are fired when the stall bit is clear. The following table represents the equivalent calls affecting the stall bit for each stage:

Root stage operation Head stage operation
local_save_flags(flags) -none-
local_irq_disable() head_irq_disable()
local_irq_enable() head_irq_enable()
local_irq_save(flags) flags = head_irq_save()
local_irq_restore(flags) head_irq_restore(flags)
irqs_disabled() head_irqs_disabled()
irqs_disabled_flags(flags) -none-

Using this set of helpers only makes sense from out-of-band code, typically in the real-time core implementation. Calling them from any other context would be highly suspicious. Adapting in-band code to interrupt pipelining might involve using the hard_local_*() set instead, but only in marginal cases, always with extreme care.