arch: arm: aarch32: Fix arch_cpu_idle interrupt masking
The current AArch32 `arch_cpu_idle` implementation enables interrupt before executing the WFI instruction, and this has the side effect of allowing interruption and thereby calling wake-up notification functions before the CPU enters sleep. This commit fixes the problem described above by ensuring that interrupt is disabled when the WFI instruction is executed and re-enabled only after the processor wakes up. For ARMv6-M, ARMv8-M Baseline and ARM-R, the PRIMASK (ARM-M)/ CPSR.I (ARM-R) is used to lock interrupts and therefore it is not necessary to do anything before executing the WFI instruction. For ARMv7-M and ARMv8-M Mainline, the BASEPRI is used to lock interrupts and the PRIMASK is always cleared in non-interrupt context; therefore, it is necessary to set the PRIMASK to mask interrupts, before clearing the BASEPRI to configure wake-up interrupt priority to the lowest. Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
This commit is contained in:
parent
50e4f2a671
commit
ba0bcaf41b
1 changed files with 24 additions and 7 deletions
|
@ -62,19 +62,36 @@ SECTION_FUNC(TEXT, arch_cpu_idle)
|
||||||
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
|
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
|
||||||
#endif /* CONFIG_TRACING */
|
#endif /* CONFIG_TRACING */
|
||||||
|
|
||||||
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \
|
#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
|
||||||
|| defined(CONFIG_ARMV7_R)
|
/*
|
||||||
cpsie i
|
* PRIMASK is always cleared on ARMv7-M and ARMv8-M Mainline (not used
|
||||||
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
|
* for interrupt locking), and configuring BASEPRI to the lowest
|
||||||
/* clear BASEPRI so wfi is awakened by incoming interrupts */
|
* priority to ensure wake-up will cause interrupts to be serviced
|
||||||
|
* before entering low power state.
|
||||||
|
*
|
||||||
|
* Set PRIMASK before configuring BASEPRI to prevent interruption
|
||||||
|
* before wake-up.
|
||||||
|
*/
|
||||||
|
cpsid i
|
||||||
|
|
||||||
|
/* Set wake-up interrupt priority to the lowest */
|
||||||
eors.n r0, r0
|
eors.n r0, r0
|
||||||
msr BASEPRI, r0
|
msr BASEPRI, r0
|
||||||
#else
|
#else
|
||||||
#error Unknown ARM architecture
|
/*
|
||||||
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
|
* For all the other ARM architectures that do not implement BASEPRI,
|
||||||
|
* PRIMASK is used as the interrupt locking mechanism, and it is not
|
||||||
|
* necessary to set PRIMASK here, as PRIMASK would have already been
|
||||||
|
* set by the caller as part of interrupt locking if necessary
|
||||||
|
* (i.e. if the caller sets _kernel.idle).
|
||||||
|
*/
|
||||||
|
#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */
|
||||||
|
|
||||||
wfi
|
wfi
|
||||||
|
|
||||||
|
/* Clear PRIMASK to service any pending interrupt */
|
||||||
|
cpsie i
|
||||||
|
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
SECTION_FUNC(TEXT, arch_cpu_atomic_idle)
|
SECTION_FUNC(TEXT, arch_cpu_atomic_idle)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue