diff options
author | gibbs <gibbs@FreeBSD.org> | 2013-09-20 05:06:03 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 2013-09-20 05:06:03 +0000 |
commit | a9c07a6f6791cbf5f8350541942b0dab762b0423 (patch) | |
tree | 297f8425e6baa2d90b45079c46930ff9d40e9994 /sys/dev/xen/control | |
parent | 45812e0f976ce4fd4915dda57316808d8bb5f23e (diff) | |
download | FreeBSD-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.c | 77 |
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 |