aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/xen/control
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>2011-09-20 23:44:34 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>2011-09-20 23:44:34 +0000
commit2ca7463bc7ac8a1c0ece154ee21aeab4cb394eec (patch)
tree6b8fcd349b3da3727d19a4671541e3c2563ca2d8 /sys/dev/xen/control
parentb296414c6222eecb519ad4e784e6ff7ca7821452 (diff)
Notes
Diffstat (limited to 'sys/dev/xen/control')
-rw-r--r--sys/dev/xen/control/control.c40
1 files changed, 31 insertions, 9 deletions
diff --git a/sys/dev/xen/control/control.c b/sys/dev/xen/control/control.c
index 301d4e827c6e..63ece1ef05f4 100644
--- a/sys/dev/xen/control/control.c
+++ b/sys/dev/xen/control/control.c
@@ -115,6 +115,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/rman.h>
+#include <sys/sched.h>
#include <sys/taskqueue.h>
#include <sys/types.h>
#include <sys/vnode.h>
@@ -201,6 +202,8 @@ xctrl_suspend()
int i, j, k, fpp;
unsigned long max_pfn, start_info_mfn;
+ EVENTHANDLER_INVOKE(power_suspend);
+
#ifdef SMP
struct thread *td;
cpuset_t map;
@@ -221,7 +224,13 @@ xctrl_suspend()
stop_cpus(map);
#endif
+ /*
+ * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
+ * drivers need this.
+ */
+ mtx_lock(&Giant);
if (DEVICE_SUSPEND(root_bus) != 0) {
+ mtx_unlock(&Giant);
printf("xen_suspend: device_suspend failed\n");
#ifdef SMP
if (!CPU_EMPTY(&map))
@@ -229,6 +238,7 @@ xctrl_suspend()
#endif
return;
}
+ mtx_unlock(&Giant);
local_irq_disable();
@@ -283,11 +293,14 @@ xctrl_suspend()
vcpu_prepare(i);
#endif
+
/*
* Only resume xenbus /after/ we've prepared our VCPUs; otherwise
* the VCPU hotplug callback can race with our vcpu_prepare
*/
+ mtx_lock(&Giant);
DEVICE_RESUME(root_bus);
+ mtx_unlock(&Giant);
#ifdef SMP
thread_lock(curthread);
@@ -296,6 +309,7 @@ xctrl_suspend()
if (!CPU_EMPTY(&map))
restart_cpus(map);
#endif
+ EVENTHANDLER_INVOKE(power_resume);
}
static void
@@ -322,39 +336,47 @@ xctrl_suspend()
{
int suspend_cancelled;
+ EVENTHANDLER_INVOKE(power_suspend);
+
+ /*
+ * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
+ * drivers need this.
+ */
+ mtx_lock(&Giant);
if (DEVICE_SUSPEND(root_bus)) {
+ mtx_unlock(&Giant);
printf("xen_suspend: device_suspend failed\n");
return;
}
-
- /*
- * Make sure we don't change cpus or switch to some other
- * thread. for the duration.
- */
- critical_enter();
+ mtx_unlock(&Giant);
/*
* Prevent any races with evtchn_interrupt() handler.
*/
- irq_suspend();
disable_intr();
+ irq_suspend();
suspend_cancelled = HYPERVISOR_suspend(0);
- if (!suspend_cancelled)
+ if (suspend_cancelled)
+ irq_resume();
+ else
xenpci_resume();
/*
* Re-enable interrupts and put the scheduler back to normal.
*/
enable_intr();
- critical_exit();
/*
* FreeBSD really needs to add DEVICE_SUSPEND_CANCEL or
* similar.
*/
+ mtx_lock(&Giant);
if (!suspend_cancelled)
DEVICE_RESUME(root_bus);
+ mtx_unlock(&Giant);
+
+ EVENTHANDLER_INVOKE(power_resume);
}
#endif