* sysdev suspend/resume @ 2005-07-26 5:42 Shaohua Li 2005-07-26 10:14 ` Pavel Machek 0 siblings, 1 reply; 9+ messages in thread From: Shaohua Li @ 2005-07-26 5:42 UTC (permalink / raw) To: linux-pm [-- Attachment #1: Type: text/plain, Size: 199 bytes --] Hi, The return value of sysdev's suspend/resume methods is ignored, is this intended (it should not fail?) or just a bug? I'd like to abort the suspend process if one device fails. Thanks, Shaohua [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-26 5:42 sysdev suspend/resume Shaohua Li @ 2005-07-26 10:14 ` Pavel Machek 2005-07-27 8:50 ` Shaohua Li 0 siblings, 1 reply; 9+ messages in thread From: Pavel Machek @ 2005-07-26 10:14 UTC (permalink / raw) To: Shaohua Li; +Cc: linux-pm [-- Attachment #1: Type: text/plain, Size: 492 bytes --] Hi! > The return value of sysdev's suspend/resume methods is ignored, is this > intended (it should not fail?) or just a bug? I'd like to abort the > suspend process if one device fails. I guess patch would be accepted... but please make sure you test those error paths, and printk name of failing driver. Hmmm, I wonder how you are going to handle resume failure? AFAICS, there's no sane way to handle that. -- 64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-26 10:14 ` Pavel Machek @ 2005-07-27 8:50 ` Shaohua Li 2005-07-27 9:07 ` Pavel Machek 0 siblings, 1 reply; 9+ messages in thread From: Shaohua Li @ 2005-07-27 8:50 UTC (permalink / raw) To: Pavel Machek; +Cc: linux-pm [-- Attachment #1: Type: text/plain, Size: 4816 bytes --] On Tue, 2005-07-26 at 12:14 +0200, Pavel Machek wrote: > Hi! > > > The return value of sysdev's suspend/resume methods is ignored, is this > > intended (it should not fail?) or just a bug? I'd like to abort the > > suspend process if one device fails. > > I guess patch would be accepted... but please make sure you test those > error paths, and printk name of failing driver. It's a challenge to me, so many loops :). Below patch is a little ugly, but should cover all error paths. > Hmmm, I wonder how you are going to handle resume failure? AFAICS, there's > no sane way to handle that. We can't refuse to resume :). Thanks, Shaohua Signed-off-by: Shaohua Li<shaohua.li@intel.com> --- linux-2.6.13-rc3-root/drivers/base/sys.c | 104 +++++++++++++++++++++++-------- 1 files changed, 80 insertions(+), 24 deletions(-) diff -puN drivers/base/sys.c~sysdev drivers/base/sys.c --- linux-2.6.13-rc3/drivers/base/sys.c~sysdev 2005-07-27 10:49:52.831538832 +0800 +++ linux-2.6.13-rc3-root/drivers/base/sys.c 2005-07-27 16:25:49.154312008 +0800 @@ -288,6 +288,22 @@ void sysdev_shutdown(void) up(&sysdev_drivers_lock); } +#define SYSDEV_RESUME(cls, dev, 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 +321,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 "Clss 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(cls, err_dev, err_drv); + } + + /* 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(cls, err_dev, err_drv); + } + } + return ret; } @@ -365,22 +436,7 @@ int sysdev_resume(void) 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(cls, sysdev, drv); } } return 0; _ [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-27 8:50 ` Shaohua Li @ 2005-07-27 9:07 ` Pavel Machek 2005-07-27 9:30 ` Shaohua Li 0 siblings, 1 reply; 9+ messages in thread From: Pavel Machek @ 2005-07-27 9:07 UTC (permalink / raw) To: Shaohua Li; +Cc: linux-pm [-- Attachment #1: Type: text/plain, Size: 1951 bytes --] Hi! > > > The return value of sysdev's suspend/resume methods is ignored, is this > > > intended (it should not fail?) or just a bug? I'd like to abort the > > > suspend process if one device fails. > > > > I guess patch would be accepted... but please make sure you test those > > error paths, and printk name of failing driver. > It's a challenge to me, so many loops :). Below patch is a little ugly, > but should cover all error paths. It is indeed quite ugly. Could we get SYSDEV_RESUME inline function instead of ugly macro? > diff -puN drivers/base/sys.c~sysdev drivers/base/sys.c > --- linux-2.6.13-rc3/drivers/base/sys.c~sysdev 2005-07-27 10:49:52.831538832 +0800 > +++ linux-2.6.13-rc3-root/drivers/base/sys.c 2005-07-27 16:25:49.154312008 +0800 > @@ -288,6 +288,22 @@ void sysdev_shutdown(void) > up(&sysdev_drivers_lock); > } > > +#define SYSDEV_RESUME(cls, dev, 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); \ > + } Are you sure you are resuming already-resumed devices? > /** > * sysdev_suspend - Suspend all system devices. > @@ -305,38 +321,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; ~~~~~~~~~~~~ use space not tab here. I see you got that habit from ACPI, but it is just wrong. > +cls_driver: > + drv = NULL; > + printk(KERN_ERR "Clss suspend failed for %s\n", ~~~~ Mssng vwls. Pavel -- teflon -- maybe it is a trademark, but it should not be. [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-27 9:07 ` Pavel Machek @ 2005-07-27 9:30 ` Shaohua Li 2005-07-27 9:40 ` Pavel Machek 2005-07-27 17:43 ` Patrick Mochel 0 siblings, 2 replies; 9+ messages in thread From: Shaohua Li @ 2005-07-27 9:30 UTC (permalink / raw) To: Pavel Machek; +Cc: linux-pm [-- Attachment #1: Type: text/plain, Size: 5890 bytes --] Hi, On Wed, 2005-07-27 at 11:07 +0200, Pavel Machek wrote: > > > > The return value of sysdev's suspend/resume methods is ignored, is this > > > > intended (it should not fail?) or just a bug? I'd like to abort the > > > > suspend process if one device fails. > > > > > > I guess patch would be accepted... but please make sure you test those > > > error paths, and printk name of failing driver. > > It's a challenge to me, so many loops :). Below patch is a little ugly, > > but should cover all error paths. > > It is indeed quite ugly. Could we get SYSDEV_RESUME inline function > instead of ugly macro? It make senses. Thanks for your comments. > > > diff -puN drivers/base/sys.c~sysdev drivers/base/sys.c > > --- linux-2.6.13-rc3/drivers/base/sys.c~sysdev 2005-07-27 10:49:52.831538832 +0800 > > +++ linux-2.6.13-rc3-root/drivers/base/sys.c 2005-07-27 16:25:49.154312008 +0800 > > @@ -288,6 +288,22 @@ void sysdev_shutdown(void) > > up(&sysdev_drivers_lock); > > } > > > > +#define SYSDEV_RESUME(cls, dev, 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); \ > > + } > > Are you sure you are resuming already-resumed devices? What's your point? if sysdev_suspend failed, sysdev_resume isn't called, so it will not be resumed twice. Thanks, Shaohua Signed-off-by: Shaohua Li<shaohua.li@intel.com> --- linux-2.6.13-rc3-root/drivers/base/sys.c | 107 ++++++++++++++++++++++++------- 1 files changed, 83 insertions(+), 24 deletions(-) diff -puN drivers/base/sys.c~sysdev drivers/base/sys.c --- linux-2.6.13-rc3/drivers/base/sys.c~sysdev 2005-07-27 10:49:52.831538832 +0800 +++ linux-2.6.13-rc3-root/drivers/base/sys.c 2005-07-27 17:22:57.447132280 +0800 @@ -288,6 +288,25 @@ void sysdev_shutdown(void) up(&sysdev_drivers_lock); } +static void inline do_sysdev_resume(struct sysdev_class *cls, + struct sys_device *dev, 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 +324,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)); + do_sysdev_resume(cls, err_dev, err_drv); + } + + /* 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)); + do_sysdev_resume(cls, err_dev, err_drv); + } + } + return ret; } @@ -365,22 +439,7 @@ int sysdev_resume(void) 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); - } - + do_sysdev_resume(cls, sysdev, drv); } } return 0; _ [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-27 9:30 ` Shaohua Li @ 2005-07-27 9:40 ` Pavel Machek 2005-07-27 17:43 ` Patrick Mochel 1 sibling, 0 replies; 9+ messages in thread From: Pavel Machek @ 2005-07-27 9:40 UTC (permalink / raw) To: Shaohua Li; +Cc: linux-pm [-- Attachment #1: Type: text/plain, Size: 845 bytes --] Hi! > > > +#define SYSDEV_RESUME(cls, dev, 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); \ > > > + } > > > > Are you sure you are resuming already-resumed devices? > What's your point? if sysdev_suspend failed, sysdev_resume isn't called, > so it will not be resumed twice. Probably nothing then, sorry for noise. Pavel -- teflon -- maybe it is a trademark, but it should not be. [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-27 9:30 ` Shaohua Li 2005-07-27 9:40 ` Pavel Machek @ 2005-07-27 17:43 ` Patrick Mochel 2005-07-27 18:50 ` Patrick Mochel 2005-07-28 3:10 ` Shaohua Li 1 sibling, 2 replies; 9+ messages in thread From: Patrick Mochel @ 2005-07-27 17:43 UTC (permalink / raw) To: Shaohua Li; +Cc: linux-pm, Pavel Machek [-- Attachment #1: Type: TEXT/PLAIN, Size: 921 bytes --] On Wed, 27 Jul 2005, Shaohua Li wrote: The patch looks Ok, except for this function. > diff -puN drivers/base/sys.c~sysdev drivers/base/sys.c > --- linux-2.6.13-rc3/drivers/base/sys.c~sysdev 2005-07-27 10:49:52.831538832 +0800 > +++ linux-2.6.13-rc3-root/drivers/base/sys.c 2005-07-27 17:22:57.447132280 +0800 > @@ -288,6 +288,25 @@ void sysdev_shutdown(void) > up(&sysdev_drivers_lock); > } > > +static void inline do_sysdev_resume(struct sysdev_class *cls, > + struct sys_device *dev, struct sysdev_driver *drv) > +{ * It does not need to be inlined. * Internal helpers are prefix'd with "__" instead of "do_", so this would be '__sysdev_resume()'. * drv is a temporary variable * cls can be ascertained from the sys_device So, the first few lines should be static void __sysdev_resume(struct sys_device * dev) { struct sysdev_class * cls = dev->cls; struct sysdev_driver * dev; ... Thanks, Pat [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-27 17:43 ` Patrick Mochel @ 2005-07-27 18:50 ` Patrick Mochel 2005-07-28 3:10 ` Shaohua Li 1 sibling, 0 replies; 9+ messages in thread From: Patrick Mochel @ 2005-07-27 18:50 UTC (permalink / raw) To: Shaohua Li; +Cc: linux-pm, Pavel Machek [-- Attachment #1: Type: TEXT/PLAIN, Size: 340 bytes --] One small correction that one eagle-eyed participant noticed: On Wed, 27 Jul 2005, Patrick Mochel wrote: > So, the first few lines should be > > static void __sysdev_resume(struct sys_device * dev) > { > struct sysdev_class * cls = dev->cls; > struct sysdev_driver * dev; That should be: struct sysdev_driver * drv; Thanks, Pat [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: sysdev suspend/resume 2005-07-27 17:43 ` Patrick Mochel 2005-07-27 18:50 ` Patrick Mochel @ 2005-07-28 3:10 ` Shaohua Li 1 sibling, 0 replies; 9+ messages in thread From: Shaohua Li @ 2005-07-28 3:10 UTC (permalink / raw) To: Patrick Mochel; +Cc: linux-pm, Pavel Machek [-- Attachment #1: Type: text/plain, Size: 4905 bytes --] Hi, On Wed, 2005-07-27 at 10:43 -0700, Patrick Mochel wrote: > > +static void inline do_sysdev_resume(struct sysdev_class *cls, > > + struct sys_device *dev, struct sysdev_driver *drv) > > +{ > > > * It does not need to be inlined. > > * Internal helpers are prefix'd with "__" instead of "do_", so this would > be '__sysdev_resume()'. > > * drv is a temporary variable > > * cls can be ascertained from the sys_device > > > So, the first few lines should be > > static void __sysdev_resume(struct sys_device * dev) > { > struct sysdev_class * cls = dev->cls; > struct sysdev_driver * dev; > ... Thanks. A updated one. Signed-off-by: Shaohua Li<shaohua.li@intel.com> --- linux-2.6.13-rc3-root/drivers/base/sys.c | 110 +++++++++++++++++++++++-------- 1 files changed, 85 insertions(+), 25 deletions(-) diff -puN drivers/base/sys.c~sysdev drivers/base/sys.c --- linux-2.6.13-rc3/drivers/base/sys.c~sysdev 2005-07-27 10:49:52.000000000 +0800 +++ linux-2.6.13-rc3-root/drivers/base/sys.c 2005-07-28 10:56:10.373347264 +0800 @@ -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; _ [-- Attachment #2: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2005-07-28 3:10 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-07-26 5:42 sysdev suspend/resume Shaohua Li 2005-07-26 10:14 ` Pavel Machek 2005-07-27 8:50 ` Shaohua Li 2005-07-27 9:07 ` Pavel Machek 2005-07-27 9:30 ` Shaohua Li 2005-07-27 9:40 ` Pavel Machek 2005-07-27 17:43 ` Patrick Mochel 2005-07-27 18:50 ` Patrick Mochel 2005-07-28 3:10 ` Shaohua Li
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox