Commit d25c1ba2 authored by Loic Prylli's avatar Loic Prylli Committed by Linus Torvalds

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: default avatarLoic Prylli <loic@myri.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1e2e99f0
...@@ -229,6 +229,8 @@ static void set_mtrr(unsigned int reg, unsigned long base, ...@@ -229,6 +229,8 @@ static void set_mtrr(unsigned int reg, unsigned long base,
data.smp_size = size; data.smp_size = size;
data.smp_type = type; data.smp_type = type;
atomic_set(&data.count, num_booting_cpus() - 1); atomic_set(&data.count, num_booting_cpus() - 1);
/* make sure data.count is visible before unleashing other CPUs */
smp_wmb();
atomic_set(&data.gate,0); atomic_set(&data.gate,0);
/* Start the ball rolling on other CPUs */ /* Start the ball rolling on other CPUs */
...@@ -242,6 +244,7 @@ static void set_mtrr(unsigned int reg, unsigned long base, ...@@ -242,6 +244,7 @@ static void set_mtrr(unsigned int reg, unsigned long base,
/* ok, reset count and toggle gate */ /* ok, reset count and toggle gate */
atomic_set(&data.count, num_booting_cpus() - 1); atomic_set(&data.count, num_booting_cpus() - 1);
smp_wmb();
atomic_set(&data.gate,1); atomic_set(&data.gate,1);
/* do our MTRR business */ /* do our MTRR business */
...@@ -260,6 +263,7 @@ static void set_mtrr(unsigned int reg, unsigned long base, ...@@ -260,6 +263,7 @@ static void set_mtrr(unsigned int reg, unsigned long base,
cpu_relax(); cpu_relax();
atomic_set(&data.count, num_booting_cpus() - 1); atomic_set(&data.count, num_booting_cpus() - 1);
smp_wmb();
atomic_set(&data.gate,0); atomic_set(&data.gate,0);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment