[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<shaohua.li@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Shaohua Li 2005-08-11 10:37:39 +08:00 committed by Greg Kroah-Hartman
parent 91e49001b9
commit ceaeade1f9

View file

@ -288,6 +288,27 @@ void sysdev_shutdown(void)
up(&sysdev_drivers_lock); 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. * sysdev_suspend - Suspend all system devices.
@ -305,38 +326,93 @@ void sysdev_shutdown(void)
int sysdev_suspend(pm_message_t state) int sysdev_suspend(pm_message_t state)
{ {
struct sysdev_class * cls; struct sysdev_class * cls;
struct sys_device *sysdev, *err_dev;
struct sysdev_driver *drv, *err_drv;
int ret;
pr_debug("Suspending System Devices\n"); pr_debug("Suspending System Devices\n");
list_for_each_entry_reverse(cls, &system_subsys.kset.list, list_for_each_entry_reverse(cls, &system_subsys.kset.list,
kset.kobj.entry) { kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Suspending type '%s':\n", pr_debug("Suspending type '%s':\n",
kobject_name(&cls->kset.kobj)); kobject_name(&cls->kset.kobj));
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj)); pr_debug(" %s\n", kobject_name(&sysdev->kobj));
/* Call global drivers first. */ /* Call global drivers first. */
list_for_each_entry(drv, &sysdev_drivers, entry) { list_for_each_entry(drv, &sysdev_drivers, entry) {
if (drv->suspend) if (drv->suspend) {
drv->suspend(sysdev, state); ret = drv->suspend(sysdev, state);
if (ret)
goto gbl_driver;
}
} }
/* Call auxillary drivers next. */ /* Call auxillary drivers next. */
list_for_each_entry(drv, &cls->drivers, entry) { list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->suspend) if (drv->suspend) {
drv->suspend(sysdev, state); ret = drv->suspend(sysdev, state);
if (ret)
goto aux_driver;
}
} }
/* Now call the generic one */ /* Now call the generic one */
if (cls->suspend) if (cls->suspend) {
cls->suspend(sysdev, state); ret = cls->suspend(sysdev, state);
if (ret)
goto cls_driver;
}
} }
} }
return 0; 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)); kobject_name(&cls->kset.kobj));
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj)); pr_debug(" %s\n", kobject_name(&sysdev->kobj));
/* First, call the class-specific one */ __sysdev_resume(sysdev);
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);
}
} }
} }
return 0; return 0;