aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-06-04 10:42:30 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-06-04 10:42:30 +0100
commit825a4dec27d5f2ecd1f28bb7aebdb6702975d07a (patch)
tree0d2d88cd2e9267c67037cab95822884bd2f9e77f
parentaef42d382266de50a8f1414ec8e649a8cd706750 (diff)
downloadxen-825a4dec27d5f2ecd1f28bb7aebdb6702975d07a.tar.gz
xen-825a4dec27d5f2ecd1f28bb7aebdb6702975d07a.tar.bz2
xen-825a4dec27d5f2ecd1f28bb7aebdb6702975d07a.zip
x86 mtrr: Fix set_mtrr() race against cpu_online_map changes.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com> xen-unstable changeset: 21499:2f765c9825b2 xen-unstable date: Tue Jun 01 10:40:06 2010 +0100
-rw-r--r--xen/arch/x86/cpu/mtrr/main.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/xen/arch/x86/cpu/mtrr/main.c b/xen/arch/x86/cpu/mtrr/main.c
index fcbf1ccda6..f99054468c 100644
--- a/xen/arch/x86/cpu/mtrr/main.c
+++ b/xen/arch/x86/cpu/mtrr/main.c
@@ -229,29 +229,32 @@ static inline int types_compatible(mtrr_type type1, mtrr_type type2) {
static void set_mtrr(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type)
{
+ cpumask_t allbutself;
+ unsigned int nr_cpus;
struct set_mtrr_data data;
unsigned long flags;
+ allbutself = cpu_online_map;
+ cpu_clear(smp_processor_id(), allbutself);
+ nr_cpus = cpus_weight(allbutself);
+
data.smp_reg = reg;
data.smp_base = base;
data.smp_size = size;
data.smp_type = type;
- atomic_set(&data.count, num_booting_cpus() - 1);
- /* make sure data.count is visible before unleashing other CPUs */
- smp_wmb();
+ atomic_set(&data.count, nr_cpus);
atomic_set(&data.gate,0);
- /* Start the ball rolling on other CPUs */
- if (smp_call_function(ipi_handler, &data, 0) != 0)
- panic("mtrr: timed out waiting for other CPUs\n");
+ /* Start the ball rolling on other CPUs */
+ on_selected_cpus(&allbutself, ipi_handler, &data, 0);
local_irq_save(flags);
- while(atomic_read(&data.count))
+ while (atomic_read(&data.count))
cpu_relax();
/* ok, reset count and toggle gate */
- atomic_set(&data.count, num_booting_cpus() - 1);
+ atomic_set(&data.count, nr_cpus);
smp_wmb();
atomic_set(&data.gate,1);
@@ -271,10 +274,10 @@ static void set_mtrr(unsigned int reg, unsigned long base,
mtrr_if->set(reg,base,size,type);
/* wait for the others */
- while(atomic_read(&data.count))
+ while (atomic_read(&data.count))
cpu_relax();
- atomic_set(&data.count, num_booting_cpus() - 1);
+ atomic_set(&data.count, nr_cpus);
smp_wmb();
atomic_set(&data.gate,0);
@@ -282,7 +285,7 @@ static void set_mtrr(unsigned int reg, unsigned long base,
* Wait here for everyone to have seen the gate change
* So we're the last ones to touch 'data'
*/
- while(atomic_read(&data.count))
+ while (atomic_read(&data.count))
cpu_relax();
local_irq_restore(flags);