aboutsummaryrefslogtreecommitdiffstats
path: root/unmodified_drivers
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-04-12 12:09:58 +0100
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-04-12 12:09:58 +0100
commite03858f635bfa0ee2f619f1f2f60575c98dbb564 (patch)
treec34a7492cc6af898fe4ae1d02dc446e05914be70 /unmodified_drivers
parent985378fb5c4b76d8a503b9077f44a40d7b9310f9 (diff)
downloadxen-e03858f635bfa0ee2f619f1f2f60575c98dbb564.tar.gz
xen-e03858f635bfa0ee2f619f1f2f60575c98dbb564.tar.bz2
xen-e03858f635bfa0ee2f619f1f2f60575c98dbb564.zip
PV-on-HVM: More carefully synchronise with APs when putting them to
sleep in a spin loop. Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'unmodified_drivers')
-rw-r--r--unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c b/unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c
index c6b1f91b7f..15ceef8da6 100644
--- a/unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c
+++ b/unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c
@@ -6,21 +6,32 @@
#include "platform-pci.h"
#include <asm/hypervisor.h>
+struct ap_suspend_info {
+ int do_spin;
+ atomic_t nr_spinning;
+};
+
/*
* Spinning prevents, for example, APs touching grant table entries while
* the shared grant table is not mapped into the address space imemdiately
* after resume.
*/
-static void ap_suspend(void *_ap_spin)
+static void ap_suspend(void *_info)
{
- int *ap_spin = _ap_spin;
+ struct ap_suspend_info *info = _info;
BUG_ON(!irqs_disabled());
- while (*ap_spin) {
+ atomic_inc(&info->nr_spinning);
+ mb();
+
+ while (info->do_spin) {
cpu_relax();
HYPERVISOR_yield();
}
+
+ mb();
+ atomic_dec(&info->nr_spinning);
}
static int bp_suspend(void)
@@ -42,7 +53,8 @@ static int bp_suspend(void)
int __xen_suspend(int fast_suspend)
{
- int err, suspend_cancelled, ap_spin;
+ int err, suspend_cancelled, nr_cpus;
+ struct ap_suspend_info info;
xenbus_suspend();
@@ -51,22 +63,30 @@ int __xen_suspend(int fast_suspend)
/* Prevent any races with evtchn_interrupt() handler. */
disable_irq(xen_platform_pdev->irq);
- ap_spin = 1;
+ info.do_spin = 1;
+ atomic_set(&info.nr_spinning, 0);
smp_mb();
- err = smp_call_function(ap_suspend, &ap_spin, 0, 0);
+ nr_cpus = num_online_cpus() - 1;
+
+ err = smp_call_function(ap_suspend, &info, 0, 0);
if (err < 0) {
preempt_enable();
xenbus_suspend_cancel();
return err;
}
+ while (atomic_read(&info.nr_spinning) != nr_cpus)
+ cpu_relax();
+
local_irq_disable();
suspend_cancelled = bp_suspend();
local_irq_enable();
smp_mb();
- ap_spin = 0;
+ info.do_spin = 0;
+ while (atomic_read(&info.nr_spinning) != 0)
+ cpu_relax();
enable_irq(xen_platform_pdev->irq);