<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">From shaohua.li@intel.com Wed Aug 10 19:38:35 2005
Subject: Driver core: hande sysdev suspend failure
From: Shaohua Li &lt;shaohua.li@intel.com&gt;
Cc: Greg KH &lt;greg@kroah.com&gt;
Date: Thu, 11 Aug 2005 10:37:39 +0800
Message-Id: &lt;1123727859.2918.4.camel@linux-hp.sh.intel.com&gt;

This patch adds the return value check for sysdev suspend and does
restore in failure case. Send the patch to pm-list, but seems lost, so I
resend it.


Signed-off-by: Shaohua Li&lt;shaohua.li@intel.com&gt;
Signed-off-by: Greg Kroah-Hartman &lt;gregkh@suse.de&gt;


---
 drivers/base/sys.c |  110 ++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 85 insertions(+), 25 deletions(-)

--- gregkh-2.6.orig/drivers/base/sys.c	2005-08-02 13:41:26.000000000 -0700
+++ gregkh-2.6/drivers/base/sys.c	2005-08-12 15:01:20.000000000 -0700
@@ -288,6 +288,27 @@
 	up(&amp;sysdev_drivers_lock);
 }
 
+static void __sysdev_resume(struct sys_device *dev)
+{
+	struct sysdev_class *cls = dev-&gt;cls;
+	struct sysdev_driver *drv;
+
+	/* First, call the class-specific one */
+	if (cls-&gt;resume)
+		cls-&gt;resume(dev);
+
+	/* Call auxillary drivers next. */
+	list_for_each_entry(drv, &amp;cls-&gt;drivers, entry) {
+		if (drv-&gt;resume)
+			drv-&gt;resume(dev);
+	}
+
+	/* Call global drivers. */
+	list_for_each_entry(drv, &amp;sysdev_drivers, entry) {
+		if (drv-&gt;resume)
+			drv-&gt;resume(dev);
+	}
+}
 
 /**
  *	sysdev_suspend - Suspend all system devices.
@@ -305,38 +326,93 @@
 int sysdev_suspend(pm_message_t state)
 {
 	struct sysdev_class * cls;
+	struct sys_device *sysdev, *err_dev;
+	struct sysdev_driver *drv, *err_drv;
+	int ret;
 
 	pr_debug("Suspending System Devices\n");
 
 	list_for_each_entry_reverse(cls, &amp;system_subsys.kset.list,
 				    kset.kobj.entry) {
-		struct sys_device * sysdev;
 
 		pr_debug("Suspending type '%s':\n",
 			 kobject_name(&amp;cls-&gt;kset.kobj));
 
 		list_for_each_entry(sysdev, &amp;cls-&gt;kset.list, kobj.entry) {
-			struct sysdev_driver * drv;
 			pr_debug(" %s\n", kobject_name(&amp;sysdev-&gt;kobj));
 
 			/* Call global drivers first. */
 			list_for_each_entry(drv, &amp;sysdev_drivers, entry) {
-				if (drv-&gt;suspend)
-					drv-&gt;suspend(sysdev, state);
+				if (drv-&gt;suspend) {
+					ret = drv-&gt;suspend(sysdev, state);
+					if (ret)
+						goto gbl_driver;
+				}
 			}
 
 			/* Call auxillary drivers next. */
 			list_for_each_entry(drv, &amp;cls-&gt;drivers, entry) {
-				if (drv-&gt;suspend)
-					drv-&gt;suspend(sysdev, state);
+				if (drv-&gt;suspend) {
+					ret = drv-&gt;suspend(sysdev, state);
+					if (ret)
+						goto aux_driver;
+				}
 			}
 
 			/* Now call the generic one */
-			if (cls-&gt;suspend)
-				cls-&gt;suspend(sysdev, state);
+			if (cls-&gt;suspend) {
+				ret = cls-&gt;suspend(sysdev, state);
+				if (ret)
+					goto cls_driver;
+			}
 		}
 	}
 	return 0;
+	/* resume current sysdev */
+cls_driver:
+	drv = NULL;
+	printk(KERN_ERR "Class suspend failed for %s\n",
+		kobject_name(&amp;sysdev-&gt;kobj));
+
+aux_driver:
+	if (drv)
+		printk(KERN_ERR "Class driver suspend failed for %s\n",
+				kobject_name(&amp;sysdev-&gt;kobj));
+	list_for_each_entry(err_drv, &amp;cls-&gt;drivers, entry) {
+		if (err_drv == drv)
+			break;
+		if (err_drv-&gt;resume)
+			err_drv-&gt;resume(sysdev);
+	}
+	drv = NULL;
+
+gbl_driver:
+	if (drv)
+		printk(KERN_ERR "sysdev driver suspend failed for %s\n",
+				kobject_name(&amp;sysdev-&gt;kobj));
+	list_for_each_entry(err_drv, &amp;sysdev_drivers, entry) {
+		if (err_drv == drv)
+			break;
+		if (err_drv-&gt;resume)
+			err_drv-&gt;resume(sysdev);
+	}
+	/* resume other sysdevs in current class */
+	list_for_each_entry(err_dev, &amp;cls-&gt;kset.list, kobj.entry) {
+		if (err_dev == sysdev)
+			break;
+		pr_debug(" %s\n", kobject_name(&amp;err_dev-&gt;kobj));
+		__sysdev_resume(err_dev);
+	}
+
+	/* resume other classes */
+	list_for_each_entry_continue(cls, &amp;system_subsys.kset.list,
+					kset.kobj.entry) {
+		list_for_each_entry(err_dev, &amp;cls-&gt;kset.list, kobj.entry) {
+			pr_debug(" %s\n", kobject_name(&amp;err_dev-&gt;kobj));
+			__sysdev_resume(err_dev);
+		}
+	}
+	return ret;
 }
 
 
@@ -362,25 +438,9 @@
 			 kobject_name(&amp;cls-&gt;kset.kobj));
 
 		list_for_each_entry(sysdev, &amp;cls-&gt;kset.list, kobj.entry) {
-			struct sysdev_driver * drv;
 			pr_debug(" %s\n", kobject_name(&amp;sysdev-&gt;kobj));
 
-			/* First, call the class-specific one */
-			if (cls-&gt;resume)
-				cls-&gt;resume(sysdev);
-
-			/* Call auxillary drivers next. */
-			list_for_each_entry(drv, &amp;cls-&gt;drivers, entry) {
-				if (drv-&gt;resume)
-					drv-&gt;resume(sysdev);
-			}
-
-			/* Call global drivers. */
-			list_for_each_entry(drv, &amp;sysdev_drivers, entry) {
-				if (drv-&gt;resume)
-					drv-&gt;resume(sysdev);
-			}
-
+			__sysdev_resume(sysdev);
 		}
 	}
 	return 0;
</pre></body></html>