ARM: OMAP4: Fix the boot regression with CPU_IDLE enabled
On OMAP4 panda board, there have been several bug reports about boot hang and lock-ups with CPU_IDLE enabled. The root cause of the issue is missing interrupts while in idle state. Commitcb7094e8
{cpuidle / omap4 : use CPUIDLE_FLAG_TIMER_STOP flag} moved the broadcast notifiers to common code for right reasons but on OMAP4 which suffers from a nasty ROM code bug with GIC, commitff999b8a
{ARM: OMAP4460: Workaround for ROM bug ..}, we loose interrupts which leads to issues like lock-up, hangs etc. Patch reverts commit cb7094 {cpuidle / omap4 : use CPUIDLE_FLAG_TIMER_STOP flag} and54769d6
{cpuidle: OMAP4: remove timer broadcast initialization} to avoid the issue. With this change, OMAP4 panda boards, the mentioned issues are getting fixed. We no longer loose interrupts which was the cause of the regression. Fixes:cb7094e8
(cpuidle / omap4 : use CPUIDLE_FLAG_TIMER_STOP flag) Fixes:ff999b8a
(cpuidle: OMAP4: remove timer broadcast initialization) Cc: stable@vger.kernel.org # v3.9+ Cc: Roger Quadros <rogerq@ti.com> Cc: Kevin Hilman <khilman@linaro.org> Cc: Tony Lindgren <tony@atomide.com> Cc: Daniel Lezcano <daniel.lezcano@linaro.org> Reported-tested-by: Roger Quadros <rogerq@ti.com> Reported-tested-by: Kevin Hilman <khilman@linaro.org> Tested-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
This commit is contained in:
Родитель
9ce2482fc6
Коммит
4b353a706a
|
@ -14,6 +14,7 @@
|
|||
#include <linux/cpuidle.h>
|
||||
#include <linux/cpu_pm.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/clockchips.h>
|
||||
|
||||
#include <asm/cpuidle.h>
|
||||
#include <asm/proc-fns.h>
|
||||
|
@ -83,6 +84,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
|
|||
{
|
||||
struct idle_statedata *cx = state_ptr + index;
|
||||
u32 mpuss_can_lose_context = 0;
|
||||
int cpu_id = smp_processor_id();
|
||||
|
||||
/*
|
||||
* CPU0 has to wait and stay ON until CPU1 is OFF state.
|
||||
|
@ -110,6 +112,8 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
|
|||
mpuss_can_lose_context = (cx->mpu_state == PWRDM_POWER_RET) &&
|
||||
(cx->mpu_logic_state == PWRDM_POWER_OFF);
|
||||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id);
|
||||
|
||||
/*
|
||||
* Call idle CPU PM enter notifier chain so that
|
||||
* VFP and per CPU interrupt context is saved.
|
||||
|
@ -165,6 +169,8 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
|
|||
if (dev->cpu == 0 && mpuss_can_lose_context)
|
||||
cpu_cluster_pm_exit();
|
||||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id);
|
||||
|
||||
fail:
|
||||
cpuidle_coupled_parallel_barrier(dev, &abort_barrier);
|
||||
cpu_done[dev->cpu] = false;
|
||||
|
@ -172,6 +178,16 @@ fail:
|
|||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each cpu, setup the broadcast timer because local timers
|
||||
* stops for the states above C1.
|
||||
*/
|
||||
static void omap_setup_broadcast_timer(void *arg)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
|
||||
}
|
||||
|
||||
static struct cpuidle_driver omap4_idle_driver = {
|
||||
.name = "omap4_idle",
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -189,8 +205,7 @@ static struct cpuidle_driver omap4_idle_driver = {
|
|||
/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
|
||||
.exit_latency = 328 + 440,
|
||||
.target_residency = 960,
|
||||
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED |
|
||||
CPUIDLE_FLAG_TIMER_STOP,
|
||||
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
|
||||
.enter = omap_enter_idle_coupled,
|
||||
.name = "C2",
|
||||
.desc = "CPUx OFF, MPUSS CSWR",
|
||||
|
@ -199,8 +214,7 @@ static struct cpuidle_driver omap4_idle_driver = {
|
|||
/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
|
||||
.exit_latency = 460 + 518,
|
||||
.target_residency = 1100,
|
||||
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED |
|
||||
CPUIDLE_FLAG_TIMER_STOP,
|
||||
.flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
|
||||
.enter = omap_enter_idle_coupled,
|
||||
.name = "C3",
|
||||
.desc = "CPUx OFF, MPUSS OSWR",
|
||||
|
@ -231,5 +245,8 @@ int __init omap4_idle_init(void)
|
|||
if (!cpu_clkdm[0] || !cpu_clkdm[1])
|
||||
return -ENODEV;
|
||||
|
||||
/* Configure the broadcast timer on each cpu */
|
||||
on_each_cpu(omap_setup_broadcast_timer, NULL, 1);
|
||||
|
||||
return cpuidle_register(&omap4_idle_driver, cpu_online_mask);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче