Zero latency interrupt extension for ARMv6-M
I would like to extend the zero latency interrupt feature to processors with an ARMv6-M architecture such as ARM Cortex M0, M0+ and M1. Is somebody already working on such a feature extension or has some ideas concerning this?
In the following I present a rough concept, how I would implement it. I am open to suggestions.
The concerning processors have two possibilities to disable exceptions with configurable priorities. First, the Priority Mask core register (PRIMASK), which prevents the activation of all exceptions with configurable priority. Secondly, the Interrupt Clear-Enable register (CLRENA) of the Nested Vector Interrupt Controller that can disable each of the 32 interrupts individually. The PRIMASK is currently used for the IRQ lock of these processors.
To implement a zero latency interrupt on ARMv6-M architecture the locking function has to be complemented by an additional compiler directive (#ifdef). The locking of the interrupts first saves the value of the NVIC_ICER into a shadow register and then clears all interrupts except of the interrupts registered as zero latency interrupt. For the functions that access the NVIC_ICER and NVIC_ISER register, a guard has to be implemented. This guard shall update the shadow register instead of writing to the NVIC_ICER and NVIC_ISER register. To unlock the interrupts, this shadow register will be written to NVIC_ISER and enable the interrupts again.
The feature that the IRQ lock is thread specific should not be restricted, since the changes mainly happen in the arch_irq_lock function.
There have to be some rules to prevent an inconsistency with the IRQ priority. The zero latency IRQ has to be registered with the highest interrupt priority available. If multiple zero latency interrupts are registered, they have to be on the same priority. With multiple zero latency IRQ, the zero latency can only be guaranteed, if they are strictly sequential.
Thanks for your email. To the best of my knowledge, none is working on ZLI on Baseline Cortex-M. If you would like to move with this forward, the best way is to an RFC issue in the Zephyr main tree Github, to get feedback from the architecture maintainers/collaborators. Remember to copy the content in this email thread.
Some comments to your suggestion:
ZLI works OK on Mainline Cortex-M, essentially because we can guarantee the following priority level order:
ZLI > Kernel > HW IRQs (+misc) > PendSV (Faults are always given highest configurable priority)
So ZLIs can preempt all HW IRQs, and can also preempt the Kernel (i.e. SVCs).
Now on Baseline (If I understand the proposal):
- PRIMASK won't be used at all for IRQ locking, if the ZLI feature is enabled.
- For ZLIs to preempt the kernel (thus, for ZLI to have the same functionality as in Mainline), SVCs need to be given a priority level lower than the ZLIs. That means, 1 out of 4 priority levels need to be reserved, which is something we were trying to avoid for some time.
There's also the performance of irq_lock and _unlock functions: the beauty of the current solution is that no memory-mapped register access is performed. This speeds up the execution, and requires only an ISB barrier. With NVIC, read-modify-write and ram-variable-storing we will need memory-mapped accesses in addition to data synchronization barriers, which might increase the overhead of locking and unlocking the IRQs. The problem will be harder on Armv8-m Baseline, which has support for much more than 32 IRQ lines.
Guess these are reasons why the software emulation of irq locking "up-to-a-priority-level" has not attracted much attention so far, but I'd be happy to see an actual discussion going on here, ideally in an RFC Github issue.