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_TRACING */
|
||||
|
||||
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) \
|
||||
|| defined(CONFIG_ARMV7_R)
|
||||
cpsie i
|
||||
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
|
||||
/* clear BASEPRI so wfi is awakened by incoming interrupts */
|
||||
#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
|
||||
/*
|
||||
* PRIMASK is always cleared on ARMv7-M and ARMv8-M Mainline (not used
|
||||
* for interrupt locking), and configuring BASEPRI to the lowest
|
||||
* 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
|
||||
msr BASEPRI, r0
|
||||
#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
|
||||
|
||||
/* Clear PRIMASK to service any pending interrupt */
|
||||
cpsie i
|
||||
|
||||
bx lr
|
||||
|
||||
SECTION_FUNC(TEXT, arch_cpu_atomic_idle)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue