soc: mec1501: modifies interrupt restoration after deep sleep

z_power_soc_deep_sleep() is called with interrupt locked already
so restoring BASEPRI is pointless here, as it would only allow
exceptions afterwards. The situation is complicated by the fact
that kernel/idle.c:idle() only locks interrupt without unlocking
which means the BASEBRI at entry of z_power_soc_deep_sleep() is
already set to allow exceptions only but not lower priority
interrupts like timer. So when, e.g. timer, interrupt fires,
the SoC would come out of deep sleep but the waking interrupts
are never delivered since they are masked, and idle() will try
to sleep again. And now it gets into a loop of going into deep
sleep briefly and waking up immediately and it goes on and on.
The solution is not to restore BASEPRI and simply leave it at
zero. This is a workaround as a proper fix would involve
invasion changes to the PM subsystem.

Also, _sys_pm_power_state_exit_post_ops() is not being called
when deep sleep is involved, so PRIMASK needs to be reset
after coming out of deep sleep.

Fixes #23274

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2020-04-09 17:43:31 -07:00 committed by Anas Nashif
commit b935903543

View file

@ -40,8 +40,6 @@
*/
static void z_power_soc_deep_sleep(void)
{
u32_t base_pri;
/* Mask all exceptions and interrupts except NMI and HardFault */
__set_PRIMASK(1);
@ -55,19 +53,13 @@ static void z_power_soc_deep_sleep(void)
/*
* Unmask all interrupts in BASEPRI. PRIMASK is used above to
* prevent entering an ISR after unmasking in BASEPRI.
* We clear PRIMASK in exit post ops.
*/
base_pri = __get_BASEPRI();
__set_BASEPRI(0);
__DSB();
__WFI(); /* triggers sleep hardware */
__NOP();
__NOP();
if (base_pri != 0) {
__set_BASEPRI(base_pri);
}
soc_deep_sleep_disable();
soc_deep_sleep_non_wake_dis();
@ -77,6 +69,13 @@ static void z_power_soc_deep_sleep(void)
};
soc_deep_sleep_periph_restore();
/*
* _sys_pm_power_state_exit_post_ops() is not being called
* after exiting deep sleep, so need to unmask exceptions
* and interrupts here.
*/
__set_PRIMASK(0);
}
#endif