Properly handle suspend/resume events in the Xen device
framework. Sponsored by: BQ Internet sys/xen/xenbus/xenbusb.c: o In xenbusb_resume(), publish the state transition of the resuming device into XenbusStateIntiailising so that the remote peer can see it. Recording the state locally is not sufficient to trigger a re-connect sequence. o In xenbusb_resume(), defer new-bus resume processing until after the remote peer's XenStore address has been updated. The drivers may need to refer to this information during resume processing. sys/xen/xenbus/xenbusb_back.c: sys/xen/xenbus/xenbusb_front.c: Register xenbusb_resume() rather than bus_generic_resume() as the handler for device_resume events. sys/xen/xenstore/xenstore.c: o Fix grammer in a comment. o In xs_suspend(), pass suspend events on to the child devices (e.g. xenbusb_front/back, that are attached to the XenStore. Approved by: re MFC after: 1 week
This commit is contained in:
parent
b296414c62
commit
2ca7463bc7
@ -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
|
||||
|
||||
|
@ -773,7 +773,7 @@ xenbusb_resume(device_t dev)
|
||||
ivars = device_get_ivars(kids[i]);
|
||||
|
||||
xs_unregister_watch(&ivars->xd_otherend_watch);
|
||||
ivars->xd_state = XenbusStateInitialising;
|
||||
xenbus_set_state(kids[i], XenbusStateInitialising);
|
||||
|
||||
/*
|
||||
* Find the new backend details and
|
||||
@ -783,16 +783,16 @@ xenbusb_resume(device_t dev)
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
DEVICE_RESUME(kids[i]);
|
||||
|
||||
statepath = malloc(ivars->xd_otherend_path_len
|
||||
+ strlen("/state") + 1, M_XENBUS, M_WAITOK);
|
||||
sprintf(statepath, "%s/state", ivars->xd_otherend_path);
|
||||
|
||||
free(ivars->xd_otherend_watch.node, M_XENBUS);
|
||||
ivars->xd_otherend_watch.node = statepath;
|
||||
xs_register_watch(&ivars->xd_otherend_watch);
|
||||
|
||||
DEVICE_RESUME(kids[i]);
|
||||
|
||||
xs_register_watch(&ivars->xd_otherend_watch);
|
||||
#if 0
|
||||
/*
|
||||
* Can't do this yet since we are running in
|
||||
|
@ -292,7 +292,7 @@ static device_method_t xenbusb_back_methods[] = {
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
DEVMETHOD(device_resume, xenbusb_resume),
|
||||
|
||||
/* Bus Interface */
|
||||
DEVMETHOD(bus_print_child, xenbusb_print_child),
|
||||
|
@ -171,7 +171,7 @@ static device_method_t xenbusb_front_methods[] = {
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
DEVMETHOD(device_resume, xenbusb_resume),
|
||||
|
||||
/* Bus Interface */
|
||||
DEVMETHOD(bus_print_child, xenbusb_print_child),
|
||||
|
@ -721,8 +721,8 @@ xs_reply_filter(uint32_t request_msg_type,
|
||||
/*
|
||||
* The count of transactions drops if we attempted
|
||||
* to end a transaction (even if that attempt fails
|
||||
* in error), we receive a transaction end acknowledgement
|
||||
* or if our attempt to begin a transactionfails.
|
||||
* in error), we receive a transaction end acknowledgement,
|
||||
* or if our attempt to begin a transaction fails.
|
||||
*/
|
||||
if (request_msg_type == XS_TRANSACTION_END
|
||||
|| (request_reply_error == 0 && reply_msg_type == XS_TRANSACTION_END)
|
||||
@ -1194,8 +1194,14 @@ xs_attach(device_t dev)
|
||||
* all transactions and individual requests have completed.
|
||||
*/
|
||||
static int
|
||||
xs_suspend(device_t dev __unused)
|
||||
xs_suspend(device_t dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
/* Suspend child Xen devices. */
|
||||
error = bus_generic_suspend(dev);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
sx_xlock(&xs.suspend_mutex);
|
||||
sx_xlock(&xs.request_mutex);
|
||||
@ -1227,6 +1233,9 @@ xs_resume(device_t dev __unused)
|
||||
|
||||
sx_xunlock(&xs.suspend_mutex);
|
||||
|
||||
/* Resume child Xen devices. */
|
||||
bus_generic_resume(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user