diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/cpuidle44xx.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c index 25655eb69408..eb93e45d3271 100644 --- a/arch/arm/mach-omap2/cpuidle44xx.c +++ b/arch/arm/mach-omap2/cpuidle44xx.c @@ -53,6 +53,9 @@ static struct omap4_idle_statedata omap4_idle_data[] = { static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS]; static struct clockdomain *cpu_clkdm[NR_CPUS]; +static atomic_t abort_barrier; +static bool cpu_done[NR_CPUS]; + /** * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions * @dev: cpuidle device @@ -90,8 +93,20 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, * out of coherency and in OFF mode. */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { - while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) + while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) { cpu_relax(); + + /* + * CPU1 could have already entered & exited idle + * without hitting off because of a wakeup + * or a failed attempt to hit off mode. Check for + * that here, otherwise we could spin forever + * waiting for CPU1 off. + */ + if (cpu_done[1]) + goto fail; + + } } clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); @@ -116,6 +131,7 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, } omap4_enter_lowpower(dev->cpu, cx->cpu_state); + cpu_done[dev->cpu] = true; /* Wakeup CPU1 only if it is not offlined */ if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { @@ -138,6 +154,10 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); +fail: + cpuidle_coupled_parallel_barrier(dev, &abort_barrier); + cpu_done[dev->cpu] = false; + local_fiq_enable(); return index; |