Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ceaeade1 authored by Shaohua Li's avatar Shaohua Li Committed by Greg Kroah-Hartman
Browse files

[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: default avatarShaohua <Li&lt;shaohua.li@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 91e49001
Loading
Loading
Loading
Loading
+85 −25
Original line number Diff line number Diff line
@@ -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;