diff options
Diffstat (limited to 'sys/dev/xen/control/control.c')
-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 |