summaryrefslogtreecommitdiffstats
path: root/sys/dev/xen/control
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>2013-09-20 05:06:03 +0000
committergibbs <gibbs@FreeBSD.org>2013-09-20 05:06:03 +0000
commita9c07a6f6791cbf5f8350541942b0dab762b0423 (patch)
tree297f8425e6baa2d90b45079c46930ff9d40e9994 /sys/dev/xen/control
parent45812e0f976ce4fd4915dda57316808d8bb5f23e (diff)
downloadFreeBSD-src-a9c07a6f6791cbf5f8350541942b0dab762b0423.zip
FreeBSD-src-a9c07a6f6791cbf5f8350541942b0dab762b0423.tar.gz
Add support for suspend/resume/migration operations when running as a
Xen PVHVM guest. Submitted by: Roger Pau Monné Sponsored by: Citrix Systems R&D Reviewed by: gibbs Approved by: re (blanket Xen) MFC after: 2 weeks sys/amd64/amd64/mp_machdep.c: sys/i386/i386/mp_machdep.c: - Make sure that are no MMU related IPIs pending on migration. - Reset pending IPI_BITMAP on resume. - Init vcpu_info on resume. sys/amd64/include/intr_machdep.h: sys/i386/include/intr_machdep.h: sys/x86/acpica/acpi_wakeup.c: sys/x86/x86/intr_machdep.c: sys/x86/isa/atpic.c: sys/x86/x86/io_apic.c: sys/x86/x86/local_apic.c: - Add a "suspend_cancelled" parameter to pic_resume(). For the Xen PIC, restoration of interrupt services differs between the aborted suspend and normal resume cases, so we must provide this information. sys/dev/acpica/acpi_timer.c: sys/dev/xen/timer/timer.c: sys/timetc.h: - Don't swap out "suspend safe" timers across a suspend/resume cycle. This includes the Xen PV and ACPI timers. sys/dev/xen/control/control.c: - Perform proper suspend/resume process for PVHVM: - Suspend all APs before going into suspension, this allows us to reset the vcpu_info on resume for each AP. - Reset shared info page and callback on resume. sys/dev/xen/timer/timer.c: - Implement suspend/resume support for the PV timer. Since FreeBSD doesn't perform a per-cpu resume of the timer, we need to call smp_rendezvous in order to correctly resume the timer on each CPU. sys/dev/xen/xenpci/xenpci.c: - Don't reset the PCI interrupt on each suspend/resume. sys/kern/subr_smp.c: - When suspending a PVHVM domain make sure there are no MMU IPIs in-flight, or we will get a lockup on resume due to the fact that pending event channels are not carried over on migration. - Implement a generic version of restart_cpus that can be used by suspended and stopped cpus. sys/x86/xen/hvm.c: - Implement resume support for the hypercall page and shared info. - Clear vcpu_info so it can be reset by APs when resuming from suspension. sys/dev/xen/xenpci/xenpci.c: sys/x86/xen/hvm.c: sys/x86/xen/xen_intr.c: - Support UP kernel configurations. sys/x86/xen/xen_intr.c: - Properly rebind per-cpus VIRQs and IPIs on resume.
Diffstat (limited to 'sys/dev/xen/control')
-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