diff options
author | Loic Prylli <loic@myri.com> | 2007-07-06 05:39:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-06 13:23:43 -0400 |
commit | d25c1ba2fa1a9a1a4f68bef8edb0efefd79f0012 (patch) | |
tree | 105a72189d2783bfbca1ffda4f5ebf968ac69496 /arch | |
parent | 1e2e99f0e4aa6363e8515ed17011c210c8f1b52a (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.c | 4 |
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 55b005152a11..75dc6d5214bc 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 | /* |