aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLoic Prylli <loic@myri.com>2007-07-06 05:39:52 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-06 13:23:43 -0400
commitd25c1ba2fa1a9a1a4f68bef8edb0efefd79f0012 (patch)
tree105a72189d2783bfbca1ffda4f5ebf968ac69496 /arch
parent1e2e99f0e4aa6363e8515ed17011c210c8f1b52a (diff)
MTRR: Fix race causing set_mtrr to go into infinite loop
Processors synchronization in set_mtrr requires the .gate field to be set after .count field is properly initialized. Without an explicit barrier, the compiler was reordering those memory stores. That was sometimes causing a processor (in ipi_handler) to see the .gate change and decrement .count before the latter is set by set_mtrr() (which then hangs in a infinite loop with irqs disabled). Signed-off-by: Loic Prylli <loic@myri.com> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 55b005152a1..75dc6d5214b 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -229,6 +229,8 @@ static void set_mtrr(unsigned int reg, unsigned long base,
229 data.smp_size = size; 229 data.smp_size = size;
230 data.smp_type = type; 230 data.smp_type = type;
231 atomic_set(&data.count, num_booting_cpus() - 1); 231 atomic_set(&data.count, num_booting_cpus() - 1);
232 /* make sure data.count is visible before unleashing other CPUs */
233 smp_wmb();
232 atomic_set(&data.gate,0); 234 atomic_set(&data.gate,0);
233 235
234 /* Start the ball rolling on other CPUs */ 236 /* Start the ball rolling on other CPUs */
@@ -242,6 +244,7 @@ static void set_mtrr(unsigned int reg, unsigned long base,
242 244
243 /* ok, reset count and toggle gate */ 245 /* ok, reset count and toggle gate */
244 atomic_set(&data.count, num_booting_cpus() - 1); 246 atomic_set(&data.count, num_booting_cpus() - 1);
247 smp_wmb();
245 atomic_set(&data.gate,1); 248 atomic_set(&data.gate,1);
246 249
247 /* do our MTRR business */ 250 /* do our MTRR business */
@@ -260,6 +263,7 @@ static void set_mtrr(unsigned int reg, unsigned long base,
260 cpu_relax(); 263 cpu_relax();
261 264
262 atomic_set(&data.count, num_booting_cpus() - 1); 265 atomic_set(&data.count, num_booting_cpus() - 1);
266 smp_wmb();
263 atomic_set(&data.gate,0); 267 atomic_set(&data.gate,0);
264 268
265 /* 269 /*