diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2010-06-04 10:42:30 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2010-06-04 10:42:30 +0100 |
commit | 825a4dec27d5f2ecd1f28bb7aebdb6702975d07a (patch) | |
tree | 0d2d88cd2e9267c67037cab95822884bd2f9e77f | |
parent | aef42d382266de50a8f1414ec8e649a8cd706750 (diff) | |
download | xen-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.c | 25 |
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); |