Files
xen/unmodified_drivers/linux-2.6/platform-pci/machine_reboot.c
T
Keir Fraser c65b3f8832 pv-on-hvm drivers: build fixes for Linux 2.6.27+
Make the drivers build properly in a 2.6.27 environment as well as
against a kernel with pv-ops Xen configured on (in the latter case
more work would be needed to also make the drivers work, as there's a
large number of duplicate exports).

Portions from Charles Arnold <carnold@novell.com>.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
2008-11-24 11:11:20 +00:00

115 lines
2.1 KiB
C

#include <linux/cpumask.h>
#include <linux/preempt.h>
#include <xen/evtchn.h>
#include <xen/gnttab.h>
#include <xen/xenbus.h>
#include "platform-pci.h"
#include <asm/hypervisor.h>
struct ap_suspend_info {
int do_spin;
atomic_t nr_spinning;
};
#ifdef CONFIG_SMP
/*
* 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 *_info)
{
struct ap_suspend_info *info = _info;
BUG_ON(!irqs_disabled());
atomic_inc(&info->nr_spinning);
mb();
while (info->do_spin)
cpu_relax();
mb();
atomic_dec(&info->nr_spinning);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
#define initiate_ap_suspend(i) smp_call_function(ap_suspend, i, 0, 0)
#else
#define initiate_ap_suspend(i) smp_call_function(ap_suspend, i, 0)
#endif
#else /* !defined(CONFIG_SMP) */
#define initiate_ap_suspend(i) 0
#endif
static int bp_suspend(void)
{
int suspend_cancelled;
BUG_ON(!irqs_disabled());
suspend_cancelled = HYPERVISOR_suspend(0);
if (!suspend_cancelled) {
platform_pci_resume();
gnttab_resume();
irq_resume();
}
return suspend_cancelled;
}
int __xen_suspend(int fast_suspend, void (*resume_notifier)(int))
{
int err, suspend_cancelled, nr_cpus;
struct ap_suspend_info info;
xenbus_suspend();
preempt_disable();
/* Prevent any races with evtchn_interrupt() handler. */
disable_irq(xen_platform_pdev->irq);
info.do_spin = 1;
atomic_set(&info.nr_spinning, 0);
smp_mb();
nr_cpus = num_online_cpus() - 1;
err = initiate_ap_suspend(&info);
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();
resume_notifier(suspend_cancelled);
local_irq_enable();
smp_mb();
info.do_spin = 0;
while (atomic_read(&info.nr_spinning) != 0)
cpu_relax();
enable_irq(xen_platform_pdev->irq);
preempt_enable();
if (!suspend_cancelled)
xenbus_resume();
else
xenbus_suspend_cancel();
return 0;
}