diff options
-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[] = { | |||
53 | static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS]; | 53 | static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS]; |
54 | static struct clockdomain *cpu_clkdm[NR_CPUS]; | 54 | static struct clockdomain *cpu_clkdm[NR_CPUS]; |
55 | 55 | ||
56 | static atomic_t abort_barrier; | ||
57 | static bool cpu_done[NR_CPUS]; | ||
58 | |||
56 | /** | 59 | /** |
57 | * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions | 60 | * omap4_enter_idle_coupled_[simple/coupled] - OMAP4 cpuidle entry functions |
58 | * @dev: cpuidle device | 61 | * @dev: cpuidle device |
@@ -90,8 +93,20 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | |||
90 | * out of coherency and in OFF mode. | 93 | * out of coherency and in OFF mode. |
91 | */ | 94 | */ |
92 | if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { | 95 | if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { |
93 | while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) | 96 | while (pwrdm_read_pwrst(cpu_pd[1]) != PWRDM_POWER_OFF) { |
94 | cpu_relax(); | 97 | cpu_relax(); |
98 | |||
99 | /* | ||
100 | * CPU1 could have already entered & exited idle | ||
101 | * without hitting off because of a wakeup | ||
102 | * or a failed attempt to hit off mode. Check for | ||
103 | * that here, otherwise we could spin forever | ||
104 | * waiting for CPU1 off. | ||
105 | */ | ||
106 | if (cpu_done[1]) | ||
107 | goto fail; | ||
108 | |||
109 | } | ||
95 | } | 110 | } |
96 | 111 | ||
97 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); | 112 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu_id); |
@@ -116,6 +131,7 @@ static int omap4_enter_idle_coupled(struct cpuidle_device *dev, | |||
116 | } | 131 | } |
117 | 132 | ||
118 | omap4_enter_lowpower(dev->cpu, cx->cpu_state); | 133 | omap4_enter_lowpower(dev->cpu, cx->cpu_state); |
134 | cpu_done[dev->cpu] = true; | ||
119 | 135 | ||
120 | /* Wakeup CPU1 only if it is not offlined */ | 136 | /* Wakeup CPU1 only if it is not offlined */ |
121 | if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) { | 137 | 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, | |||
138 | 154 | ||
139 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); | 155 | clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu_id); |
140 | 156 | ||
157 | fail: | ||
158 | cpuidle_coupled_parallel_barrier(dev, &abort_barrier); | ||
159 | cpu_done[dev->cpu] = false; | ||
160 | |||
141 | local_fiq_enable(); | 161 | local_fiq_enable(); |
142 | 162 | ||
143 | return index; | 163 | return index; |