From 9e60686c4ccfeaa24d12fd489c29a63dffba08f3 Mon Sep 17 00:00:00 2001 From: Gaurav Sahitya Date: Fri, 13 Dec 2024 04:38:36 +0000 Subject: [PATCH] os/pm: fix board hang issue This commit resolve hang issue of pm with amp. The issue happens when CPU0 gated the CPU1 and exited from critical section without undoing gating of CPU1. Later when tick interrupt came, the gated CPU0 tries to pause CPU1, but since CPU1 is in gating it can not release spinlock require by CPU0 to proceed CPU pause request. This creates deadlock which results in hang. To prevent this case we are setting gated_cpu_count just after performing gating and at EXIT case it will ensure the gated CPUs get ungated. --- os/pm/pm_idle.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/os/pm/pm_idle.c b/os/pm/pm_idle.c index 285d30a53a..b3f207e8e6 100644 --- a/os/pm/pm_idle.c +++ b/os/pm/pm_idle.c @@ -98,6 +98,16 @@ void pm_idle(void) newstate = pm_checkstate(); #ifdef CONFIG_PM_METRICS pm_metrics_update_idle(); +#endif +#ifdef CONFIG_PM_TIMEDWAKEUP + /* get wakeup timer */ + if (newstate == PM_SLEEP) { + delay = wd_getwakeupdelay(); + if ((delay > 0) && (delay < MSEC2TICK(CONFIG_PM_SLEEP_ENTRY_WAIT_MS))) { + pmvdbg("Wdog Timer Delay: %ldms is less than SLEEP_ENTRY_WAIT: %ldms\n", TICK2MSEC(delay), CONFIG_PM_SLEEP_ENTRY_WAIT_MS); + goto EXIT; + } + } #endif /* Perform state-dependent logic here */ /* For SMP case, we need to check secondary core status @@ -118,12 +128,12 @@ void pm_idle(void) if (!up_get_gating_flag_status(cpu)) { up_set_gating_flag_status(cpu, 1); up_cpu_gating(cpu); + gated_cpu_count = cpu; } while (up_get_gating_flag_status(cpu) == 1) { /* If there is a pause request, we should handle it first */ if (up_cpu_pausereq(up_cpu_index())) { - pmdbg("Sleep abort! CPU%d task: %s!\n", cpu, tcb->name); - gated_cpu_count = cpu; + pmdbg("Sleep abort! CPU%d\n", cpu); goto EXIT; } } @@ -133,22 +143,11 @@ void pm_idle(void) * pause request on primary core */ if (tcb->pid != cpu) { - pmdbg("Sleep abort! CPU%d task: %s!\n", cpu, tcb->name); - gated_cpu_count = cpu; + pmvdbg("Sleep abort! CPU%d task: %s!\n", cpu, tcb->name); goto EXIT; } } } -#endif -#ifdef CONFIG_PM_TIMEDWAKEUP - /* get wakeup timer */ - if (newstate == PM_SLEEP) { - delay = wd_getwakeupdelay(); - if ((delay > 0) && (delay < MSEC2TICK(CONFIG_PM_SLEEP_ENTRY_WAIT_MS))) { - pmvdbg("Wdog Timer Delay: %ldms is less than SLEEP_ENTRY_WAIT: %ldms\n", TICK2MSEC(delay), CONFIG_PM_SLEEP_ENTRY_WAIT_MS); - goto EXIT; - } - } #endif /* Then force the global state change */ if (pm_changestate(newstate) < 0) { @@ -169,8 +168,9 @@ void pm_idle(void) /* Reset core gating status flag */ up_set_gating_flag_status(cpu, 0); /* Check whether each of the cpu has entered hotplug */ - while(up_get_cpu_state(cpu) != CPU_HOTPLUG); + while (up_get_cpu_state(cpu) != CPU_HOTPLUG); } + gated_cpu_count = 0; #endif #ifdef CONFIG_PM_TIMEDWAKEUP /* set wakeup timer */