From e03858f635bfa0ee2f619f1f2f60575c98dbb564 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 12 Apr 2007 12:09:58 +0100 Subject: PV-on-HVM: More carefully synchronise with APs when putting them to sleep in a spin loop. Signed-off-by: Keir Fraser --- .../linux-2.6/platform-pci/machine_reboot.c | 34 +++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'unmodified_drivers/linux-2.6/platform-pci') 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 +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); -- cgit v1.2.3