@@ -50,6 +50,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/suspend.h>
#include <asm/page.h>
#include <asm/xen/hypervisor.h>
@@ -599,16 +600,33 @@ int xenbus_dev_suspend(struct device *dev)
struct xenbus_driver *drv;
struct xenbus_device *xdev
= container_of(dev, struct xenbus_device, dev);
+ bool xen_suspend = xen_is_xen_suspend();
DPRINTK("%s", xdev->nodename);
if (dev->driver == NULL)
return 0;
drv = to_xenbus_driver(dev->driver);
- if (drv->suspend)
- err = drv->suspend(xdev);
- if (err)
- dev_warn(dev, "suspend failed: %i\n", err);
+ if (xen_suspend) {
+ if (drv->suspend)
+ err = drv->suspend(xdev);
+ } else {
+ if (drv->freeze) {
+ err = drv->freeze(xdev);
+ if (!err) {
+ free_otherend_watch(xdev);
+ free_otherend_details(xdev);
+ return 0;
+ }
+ }
+ }
+
+ if (err) {
+ dev_warn(&xdev->dev, "%s %s failed: %d\n", xen_suspend ?
+ "suspend" : "freeze", xdev->nodename, err);
+ return err;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(xenbus_dev_suspend);
@@ -619,6 +637,7 @@ int xenbus_dev_resume(struct device *dev)
struct xenbus_driver *drv;
struct xenbus_device *xdev
= container_of(dev, struct xenbus_device, dev);
+ bool xen_suspend = xen_is_xen_suspend();
DPRINTK("%s", xdev->nodename);
@@ -627,23 +646,34 @@ int xenbus_dev_resume(struct device *dev)
drv = to_xenbus_driver(dev->driver);
err = talk_to_otherend(xdev);
if (err) {
- dev_warn(dev, "resume (talk_to_otherend) failed: %i\n", err);
+ dev_warn(&xdev->dev, "%s (talk_to_otherend) %s failed: %d\n",
+ xen_suspend ? "resume" : "restore",
+ xdev->nodename, err);
return err;
}
- xdev->state = XenbusStateInitialising;
+ if (xen_suspend) {
+ xdev->state = XenbusStateInitialising;
+ if (drv->resume)
+ err = drv->resume(xdev);
+ } else {
+ if (drv->restore)
+ err = drv->restore(xdev);
+ }
- if (drv->resume) {
- err = drv->resume(xdev);
- if (err) {
- dev_warn(dev, "resume failed: %i\n", err);
- return err;
- }
+ if (err) {
+ dev_warn(&xdev->dev, "%s %s failed: %d\n",
+ xen_suspend ? "resume" : "restore",
+ xdev->nodename, err);
+ return err;
}
err = watch_otherend(xdev);
if (err) {
- dev_warn(dev, "resume (watch_otherend) failed: %d\n", err);
+ dev_warn(&xdev->dev, "%s (watch_otherend) %s failed: %d.\n",
+ xen_suspend ? "resume" : "restore",
+ xdev->nodename, err);
+
return err;
}
@@ -653,8 +683,44 @@ EXPORT_SYMBOL_GPL(xenbus_dev_resume);
int xenbus_dev_cancel(struct device *dev)
{
- /* Do nothing */
- DPRINTK("cancel");
+ int err;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ bool xen_suspend = xen_is_xen_suspend();
+
+ if (xen_suspend) {
+ /* Do nothing */
+ DPRINTK("cancel");
+ return 0;
+ }
+
+ DPRINTK("%s", xendev->nodename);
+
+ if (dev->driver == NULL)
+ return 0;
+ drv = to_xenbus_driver(dev->driver);
+ err = talk_to_otherend(xendev);
+ if (err) {
+ dev_warn(&xendev->dev, "thaw (talk_to_otherend) %s failed: %d.\n",
+ xendev->nodename, err);
+ return err;
+ }
+
+ if (drv->thaw) {
+ err = drv->thaw(xendev);
+ if (err) {
+ dev_warn(&xendev->dev, "thaw %s failed: %d\n", xendev->nodename, err);
+ return err;
+ }
+ }
+
+ err = watch_otherend(xendev);
+ if (err) {
+ dev_warn(&xendev->dev, "thaw (watch_otherend) %s failed: %d.\n",
+ xendev->nodename, err);
+ return err;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(xenbus_dev_cancel);
@@ -104,6 +104,9 @@ struct xenbus_driver {
int (*remove)(struct xenbus_device *dev);
int (*suspend)(struct xenbus_device *dev);
int (*resume)(struct xenbus_device *dev);
+ int (*freeze)(struct xenbus_device *dev);
+ int (*thaw)(struct xenbus_device *dev);
+ int (*restore)(struct xenbus_device *dev);
int (*uevent)(struct xenbus_device *, struct kobj_uevent_env *);
struct device_driver driver;
int (*read_otherend_details)(struct xenbus_device *dev);