aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-vexpress
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-12-18 05:53:12 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-12-20 10:09:13 -0500
commit3705ff6da538aff6dba535e2e9cbcbb9456d0d53 (patch)
tree348fcec2be9d41e1839686a6c03f0b5479d7e4f9 /arch/arm/mach-vexpress
parented3768a8d9dc2d345d4f27eb44ee1e4825056c08 (diff)
ARM: Fix subtle race in CPU pen_release hotplug code
There is a subtle race in the CPU hotplug code, where a CPU which has been offlined can online itself before being requested, which results in things going astray on the next online/offline cycle. What happens in the normal online/offline/online cycle is: CPU0 CPU3 requests boot of CPU3 pen_release = 3 flush cache line checks pen_release, reads 3 starts boot pen_release = -1 ... requests CPU3 offline ... ... dies ... checks pen_release, reads -1 requests boot of CPU3 pen_release = 3 flush cache line checks pen_release, reads 3 starts boot pen_release = -1 However, as the write of -1 of pen_release is not fully flushed back to memory, and the checking of pen_release is done with caches disabled, this allows CPU3 the opportunity to read the old value of pen_release: CPU0 CPU3 requests boot of CPU3 pen_release = 3 flush cache line checks pen_release, reads 3 starts boot pen_release = -1 ... requests CPU3 offline ... ... dies ... checks pen_release, reads 3 starts boot pen_release = -1 requests boot of CPU3 pen_release = 3 flush cache line Fix this by grouping the write of pen_release along with its cache line flushing code to ensure that any update to pen_release is always pushed out to physical memory. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-vexpress')
-rw-r--r--arch/arm/mach-vexpress/platsmp.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index d7e0cb994e9d..8ce9fef29555 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -34,6 +34,19 @@ extern void vexpress_secondary_startup(void);
34 */ 34 */
35volatile int __cpuinitdata pen_release = -1; 35volatile int __cpuinitdata pen_release = -1;
36 36
37/*
38 * Write pen_release in a way that is guaranteed to be visible to all
39 * observers, irrespective of whether they're taking part in coherency
40 * or not. This is necessary for the hotplug code to work reliably.
41 */
42static void write_pen_release(int val)
43{
44 pen_release = val;
45 smp_wmb();
46 __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
47 outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
48}
49
37static void __iomem *scu_base_addr(void) 50static void __iomem *scu_base_addr(void)
38{ 51{
39 return MMIO_P2V(A9_MPCORE_SCU); 52 return MMIO_P2V(A9_MPCORE_SCU);
@@ -54,8 +67,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
54 * let the primary processor know we're out of the 67 * let the primary processor know we're out of the
55 * pen, then head off into the C entry point 68 * pen, then head off into the C entry point
56 */ 69 */
57 pen_release = -1; 70 write_pen_release(-1);
58 smp_wmb();
59 71
60 /* 72 /*
61 * Synchronise with the boot thread. 73 * Synchronise with the boot thread.
@@ -80,9 +92,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
80 * since we haven't sent them a soft interrupt, they shouldn't 92 * since we haven't sent them a soft interrupt, they shouldn't
81 * be there. 93 * be there.
82 */ 94 */
83 pen_release = cpu; 95 write_pen_release(cpu);
84 __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
85 outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
86 96
87 /* 97 /*
88 * Send the secondary CPU a soft interrupt, thereby causing 98 * Send the secondary CPU a soft interrupt, thereby causing