summaryrefslogtreecommitdiffstats
path: root/sys/dev/xen/control/control.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/xen/control/control.c')
-rw-r--r--sys/dev/xen/control/control.c77
1 files changed, 65 insertions, 12 deletions
diff --git a/sys/dev/xen/control/control.c b/sys/dev/xen/control/control.c
index 649f281..a74042b 100644
--- a/sys/dev/xen/control/control.c
+++ b/sys/dev/xen/control/control.c
@@ -119,11 +119,9 @@ __FBSDID("$FreeBSD$");
#include <sys/taskqueue.h>
#include <sys/types.h>
#include <sys/vnode.h>
-
-#ifndef XENHVM
#include <sys/sched.h>
#include <sys/smp.h>
-#endif
+#include <sys/eventhandler.h>
#include <geom/geom.h>
@@ -140,6 +138,10 @@ __FBSDID("$FreeBSD$");
#include <xen/gnttab.h>
#include <xen/xen_intr.h>
+#ifdef XENHVM
+#include <xen/hvm.h>
+#endif
+
#include <xen/interface/event_channel.h>
#include <xen/interface/grant_table.h>
@@ -199,7 +201,7 @@ extern void xencons_resume(void);
static void
xctrl_suspend()
{
- int i, j, k, fpp;
+ int i, j, k, fpp, suspend_cancelled;
unsigned long max_pfn, start_info_mfn;
EVENTHANDLER_INVOKE(power_suspend);
@@ -264,7 +266,7 @@ xctrl_suspend()
*/
start_info_mfn = VTOMFN(xen_start_info);
pmap_suspend();
- HYPERVISOR_suspend(start_info_mfn);
+ suspend_cancelled = HYPERVISOR_suspend(start_info_mfn);
pmap_resume();
pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info);
@@ -287,7 +289,7 @@ xctrl_suspend()
HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
gnttab_resume();
- intr_resume();
+ intr_resume(suspend_cancelled != 0);
local_irq_enable();
xencons_resume();
@@ -331,16 +333,31 @@ xen_pv_shutdown_final(void *arg, int howto)
}
#else
-extern void xenpci_resume(void);
/* HVM mode suspension. */
static void
xctrl_suspend()
{
+#ifdef SMP
+ cpuset_t cpu_suspend_map;
+#endif
int suspend_cancelled;
EVENTHANDLER_INVOKE(power_suspend);
+ if (smp_started) {
+ thread_lock(curthread);
+ sched_bind(curthread, 0);
+ thread_unlock(curthread);
+ }
+ KASSERT((PCPU_GET(cpuid) == 0), ("Not running on CPU#0"));
+
+ /*
+ * Clear our XenStore node so the toolstack knows we are
+ * responding to the suspend request.
+ */
+ xs_write(XST_NIL, "control", "shutdown", "");
+
/*
* Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
* drivers need this.
@@ -353,31 +370,67 @@ xctrl_suspend()
}
mtx_unlock(&Giant);
+#ifdef SMP
+ if (smp_started) {
+ /*
+ * Suspend other CPUs. This prevents IPIs while we
+ * are resuming, and will allow us to reset per-cpu
+ * vcpu_info on resume.
+ */
+ cpu_suspend_map = all_cpus;
+ CPU_CLR(PCPU_GET(cpuid), &cpu_suspend_map);
+ if (!CPU_EMPTY(&cpu_suspend_map))
+ suspend_cpus(cpu_suspend_map);
+ }
+#endif
+
/*
* Prevent any races with evtchn_interrupt() handler.
*/
disable_intr();
intr_suspend();
+ xen_hvm_suspend();
suspend_cancelled = HYPERVISOR_suspend(0);
- intr_resume();
+ xen_hvm_resume(suspend_cancelled != 0);
+ intr_resume(suspend_cancelled != 0);
+ enable_intr();
/*
- * Re-enable interrupts and put the scheduler back to normal.
+ * Reset grant table info.
*/
- enable_intr();
+ gnttab_resume();
+
+#ifdef SMP
+ if (smp_started && !CPU_EMPTY(&cpu_suspend_map)) {
+ /*
+ * Now that event channels have been initialized,
+ * resume CPUs.
+ */
+ resume_cpus(cpu_suspend_map);
+ }
+#endif
/*
* FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or
* similar.
*/
mtx_lock(&Giant);
- if (!suspend_cancelled)
- DEVICE_RESUME(root_bus);
+ DEVICE_RESUME(root_bus);
mtx_unlock(&Giant);
+ if (smp_started) {
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+ }
+
EVENTHANDLER_INVOKE(power_resume);
+
+ if (bootverbose)
+ printf("System resumed after suspension\n");
+
}
#endif
OpenPOWER on IntegriCloud