tree fafff19d6510ce06e229b4cbacc1023f6845a8f7
parent 91e49001b9a7fe5dc2fa5b56039fbca9aa638ccc
author Shaohua Li <[EMAIL PROTECTED]> Thu, 11 Aug 2005 10:37:39 +0800
committer Greg Kroah-Hartman <[EMAIL PROTECTED]> Tue, 06 Sep 2005 06:03:12 -0700

[PATCH] Driver core: hande sysdev suspend failure

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<[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>

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

diff --git a/drivers/base/sys.c b/drivers/base/sys.c
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -288,6 +288,27 @@ void sysdev_shutdown(void)
        up(&sysdev_drivers_lock);
 }
 
+static void __sysdev_resume(struct sys_device *dev)
+{
+       struct sysdev_class *cls = dev->cls;
+       struct sysdev_driver *drv;
+
+       /* First, call the class-specific one */
+       if (cls->resume)
+               cls->resume(dev);
+
+       /* Call auxillary drivers next. */
+       list_for_each_entry(drv, &cls->drivers, entry) {
+               if (drv->resume)
+                       drv->resume(dev);
+       }
+
+       /* Call global drivers. */
+       list_for_each_entry(drv, &sysdev_drivers, entry) {
+               if (drv->resume)
+                       drv->resume(dev);
+       }
+}
 
 /**
  *     sysdev_suspend - Suspend all system devices.
@@ -305,38 +326,93 @@ void sysdev_shutdown(void)
 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, &system_subsys.kset.list,
                                    kset.kobj.entry) {
-               struct sys_device * sysdev;
 
                pr_debug("Suspending type '%s':\n",
                         kobject_name(&cls->kset.kobj));
 
                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       struct sysdev_driver * drv;
                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
                        /* Call global drivers first. */
                        list_for_each_entry(drv, &sysdev_drivers, entry) {
-                               if (drv->suspend)
-                                       drv->suspend(sysdev, state);
+                               if (drv->suspend) {
+                                       ret = drv->suspend(sysdev, state);
+                                       if (ret)
+                                               goto gbl_driver;
+                               }
                        }
 
                        /* Call auxillary drivers next. */
                        list_for_each_entry(drv, &cls->drivers, entry) {
-                               if (drv->suspend)
-                                       drv->suspend(sysdev, state);
+                               if (drv->suspend) {
+                                       ret = drv->suspend(sysdev, state);
+                                       if (ret)
+                                               goto aux_driver;
+                               }
                        }
 
                        /* Now call the generic one */
-                       if (cls->suspend)
-                               cls->suspend(sysdev, state);
+                       if (cls->suspend) {
+                               ret = cls->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(&sysdev->kobj));
+
+aux_driver:
+       if (drv)
+               printk(KERN_ERR "Class driver suspend failed for %s\n",
+                               kobject_name(&sysdev->kobj));
+       list_for_each_entry(err_drv, &cls->drivers, entry) {
+               if (err_drv == drv)
+                       break;
+               if (err_drv->resume)
+                       err_drv->resume(sysdev);
+       }
+       drv = NULL;
+
+gbl_driver:
+       if (drv)
+               printk(KERN_ERR "sysdev driver suspend failed for %s\n",
+                               kobject_name(&sysdev->kobj));
+       list_for_each_entry(err_drv, &sysdev_drivers, entry) {
+               if (err_drv == drv)
+                       break;
+               if (err_drv->resume)
+                       err_drv->resume(sysdev);
+       }
+       /* resume other sysdevs in current class */
+       list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
+               if (err_dev == sysdev)
+                       break;
+               pr_debug(" %s\n", kobject_name(&err_dev->kobj));
+               __sysdev_resume(err_dev);
+       }
+
+       /* resume other classes */
+       list_for_each_entry_continue(cls, &system_subsys.kset.list,
+                                       kset.kobj.entry) {
+               list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
+                       pr_debug(" %s\n", kobject_name(&err_dev->kobj));
+                       __sysdev_resume(err_dev);
+               }
+       }
+       return ret;
 }
 
 
@@ -362,25 +438,9 @@ int sysdev_resume(void)
                         kobject_name(&cls->kset.kobj));
 
                list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
-                       struct sysdev_driver * drv;
                        pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-                       /* First, call the class-specific one */
-                       if (cls->resume)
-                               cls->resume(sysdev);
-
-                       /* Call auxillary drivers next. */
-                       list_for_each_entry(drv, &cls->drivers, entry) {
-                               if (drv->resume)
-                                       drv->resume(sysdev);
-                       }
-
-                       /* Call global drivers. */
-                       list_for_each_entry(drv, &sysdev_drivers, entry) {
-                               if (drv->resume)
-                                       drv->resume(sysdev);
-                       }
-
+                       __sysdev_resume(sysdev);
                }
        }
        return 0;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to