diff options
author | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2012-07-26 14:08:42 +0100 |
---|---|---|
committer | Jon Medhurst <tixy@linaro.org> | 2012-07-26 19:14:54 +0100 |
commit | bf536fe80cd7bcb7e72dfc807e3760cd8552398a (patch) | |
tree | 683cd02ea5de2f62fa125c19d3268b7743710d38 | |
parent | 4b4fc27ea224acef8bb49773671f0288888a10f0 (diff) |
ARM: vexpress: fix CPU idle C1 state enablementtracking-tracking-armlt-tc2-pm-ll-20120727.0
This patch defines C1 as disabled by default on TC2. If the state is
later enabled but deep shutdown states are required to be enabled on
a cluster basis, a coupled barrier must be added to the coupled enter
function so that coupled CPUs cannot exit the polling C1 state while
other ones are still entering.
This patch fixes a race in C1 code where one CPU exits a coupled
C-state while another one, part of the coupled mask is still
selecting the coupled C-state value. This can cause some CPUs to
select the -1 state index which triggers an undefined instruction fault.
The added coupled C-state barrier fixes the issue by forcing coupled
C-states to be entered and exited at the same time by all CPUs even
if cluster shutdown is disabled.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-rw-r--r-- | arch/arm/mach-vexpress/cpuidle-tc2.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/arch/arm/mach-vexpress/cpuidle-tc2.c b/arch/arm/mach-vexpress/cpuidle-tc2.c index 11030b5c0ec4..cb9c64695b3c 100644 --- a/arch/arm/mach-vexpress/cpuidle-tc2.c +++ b/arch/arm/mach-vexpress/cpuidle-tc2.c @@ -72,6 +72,7 @@ static struct cpuidle_state tc2_cpuidle_set[] __initdata = { CPUIDLE_FLAG_COUPLED, .name = "C1", .desc = "ARM power down", + .disable = 1, }, }; @@ -138,8 +139,11 @@ static int tc2_enter_coupled(struct cpuidle_device *dev, /* Used to keep track of the total time in idle */ getnstimeofday(&ts_preidle); - if (!cpu_isset(cluster, cluster_mask)) + if (!cpu_isset(cluster, cluster_mask)) { + cpuidle_coupled_parallel_barrier(dev, + &abort_barrier[cluster]); goto shallow_out; + } BUG_ON(!irqs_disabled()); |