* [PATCH 1/3] PM: Handle device registrations during suspend/resume [not found] <200803120055.25885.rjw@sisk.pl> @ 2008-03-11 23:57 ` Rafael J. Wysocki 2008-03-11 23:59 ` [PATCH 2/3] Driver core: Call device_pm_add() after bus_add_device() in device_add() Rafael J. Wysocki ` (4 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Rafael J. Wysocki @ 2008-03-11 23:57 UTC (permalink / raw) To: Greg KH; +Cc: LKML, Andrew Morton, pm list From: Rafael J. Wysocki <rjw@sisk.pl> Modify the PM core to protect its data structures, specifically the dpm_active list, from being corrupted if a child of the currently suspending device is registered concurrently with its ->suspend() callback. In that case, since the new device (the child) is added to dpm_active after its parent, the PM core will attempt to suspend it after the parent, which is wrong. Introduce a new member of struct dev_pm_info, called 'sleeping', and use it to check if the parent of the device being added to dpm_active has been suspended, in which case the device registration fails. Also, use 'sleeping' for checking if the ordering of devices on dpm_active is correct. Introduce variable 'all_sleeping' that will be set to 'true' once all devices have been suspended and make new device registrations fail until 'all_sleeping' is reset to 'false', in order to avoid having unsuspended devices around while the system is going into a sleep state. Remove pm_sleep_rwsem which is not necessary any more. Special thanks to Alan Stern for discussions and suggestions that lead to the creation of this patch. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> --- Documentation/power/devices.txt | 5 +++ drivers/base/core.c | 6 +++- drivers/base/power/main.c | 57 ++++++++++++++++++---------------------- drivers/base/power/power.h | 23 ++-------------- include/linux/pm.h | 1 5 files changed, 40 insertions(+), 52 deletions(-) Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/include/linux/pm.h @@ -183,6 +183,7 @@ typedef struct pm_message { struct dev_pm_info { pm_message_t power_state; unsigned can_wakeup:1; + bool sleeping:1; /* Owned by the PM core */ #ifdef CONFIG_PM_SLEEP unsigned should_wakeup:1; struct list_head entry; Index: linux-2.6/drivers/base/power/main.c =================================================================== --- linux-2.6.orig/drivers/base/power/main.c +++ linux-2.6/drivers/base/power/main.c @@ -54,7 +54,8 @@ static LIST_HEAD(dpm_destroy); static DEFINE_MUTEX(dpm_list_mtx); -static DECLARE_RWSEM(pm_sleep_rwsem); +/* 'true' if all devices have been suspended, protected by dpm_list_mtx */ +static bool all_sleeping; int (*platform_enable_wakeup)(struct device *dev, int is_on); @@ -62,14 +63,28 @@ int (*platform_enable_wakeup)(struct dev * device_pm_add - add a device to the list of active devices * @dev: Device to be added to the list */ -void device_pm_add(struct device *dev) +int device_pm_add(struct device *dev) { + int error = 0; + pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", kobject_name(&dev->kobj)); mutex_lock(&dpm_list_mtx); - list_add_tail(&dev->power.entry, &dpm_active); + if ((dev->parent && dev->parent->power.sleeping) || all_sleeping) { + if (dev->parent->power.sleeping) + dev_warn(dev, + "parent %s is sleeping, will not add\n", + dev->parent->bus_id); + else + dev_warn(dev, "devices are sleeping, will not add\n"); + WARN_ON(true); + error = -EBUSY; + } else { + list_add_tail(&dev->power.entry, &dpm_active); + } mutex_unlock(&dpm_list_mtx); + return error; } /** @@ -107,32 +122,6 @@ void device_pm_schedule_removal(struct d } EXPORT_SYMBOL_GPL(device_pm_schedule_removal); -/** - * pm_sleep_lock - mutual exclusion for registration and suspend - * - * Returns 0 if no suspend is underway and device registration - * may proceed, otherwise -EBUSY. - */ -int pm_sleep_lock(void) -{ - if (down_read_trylock(&pm_sleep_rwsem)) - return 0; - - return -EBUSY; -} - -/** - * pm_sleep_unlock - mutual exclusion for registration and suspend - * - * This routine undoes the effect of device_pm_add_lock - * when a device's registration is complete. - */ -void pm_sleep_unlock(void) -{ - up_read(&pm_sleep_rwsem); -} - - /*------------------------- Resume routines -------------------------*/ /** @@ -242,11 +231,13 @@ static int resume_device(struct device * static void dpm_resume(void) { mutex_lock(&dpm_list_mtx); + all_sleeping = false; while(!list_empty(&dpm_off)) { struct list_head *entry = dpm_off.next; struct device *dev = to_device(entry); list_move_tail(entry, &dpm_active); + dev->power.sleeping = false; mutex_unlock(&dpm_list_mtx); resume_device(dev); mutex_lock(&dpm_list_mtx); @@ -285,7 +276,6 @@ void device_resume(void) might_sleep(); dpm_resume(); unregister_dropped_devices(); - up_write(&pm_sleep_rwsem); } EXPORT_SYMBOL_GPL(device_resume); @@ -426,6 +416,9 @@ static int dpm_suspend(pm_message_t stat struct list_head *entry = dpm_active.prev; struct device *dev = to_device(entry); + WARN_ON(dev->parent && dev->parent->power.sleeping); + + dev->power.sleeping = true; mutex_unlock(&dpm_list_mtx); error = suspend_device(dev, state); mutex_lock(&dpm_list_mtx); @@ -437,11 +430,14 @@ static int dpm_suspend(pm_message_t stat (error == -EAGAIN ? " (please convert to suspend_late)" : "")); + dev->power.sleeping = false; break; } if (!list_empty(&dev->power.entry)) list_move(&dev->power.entry, &dpm_off); } + if (!error) + all_sleeping = true; mutex_unlock(&dpm_list_mtx); return error; @@ -459,7 +455,6 @@ int device_suspend(pm_message_t state) int error; might_sleep(); - down_write(&pm_sleep_rwsem); error = dpm_suspend(state); if (error) device_resume(); Index: linux-2.6/drivers/base/power/power.h =================================================================== --- linux-2.6.orig/drivers/base/power/power.h +++ linux-2.6/drivers/base/power/power.h @@ -11,30 +11,13 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } -extern void device_pm_add(struct device *); +extern int device_pm_add(struct device *); extern void device_pm_remove(struct device *); -extern int pm_sleep_lock(void); -extern void pm_sleep_unlock(void); #else /* CONFIG_PM_SLEEP */ - -static inline void device_pm_add(struct device *dev) -{ -} - -static inline void device_pm_remove(struct device *dev) -{ -} - -static inline int pm_sleep_lock(void) -{ - return 0; -} - -static inline void pm_sleep_unlock(void) -{ -} +static inline int device_pm_add(struct device *dev) { return 0; } +static inline void device_pm_remove(struct device *dev) {} #endif Index: linux-2.6/drivers/base/core.c =================================================================== --- linux-2.6.orig/drivers/base/core.c +++ linux-2.6/drivers/base/core.c @@ -815,7 +815,11 @@ int device_add(struct device *dev) error = dpm_sysfs_add(dev); if (error) goto PMError; - device_pm_add(dev); + error = device_pm_add(dev); + if (error) { + dpm_sysfs_remove(dev); + goto PMError; + } error = bus_add_device(dev); if (error) goto BusError; Index: linux-2.6/Documentation/power/devices.txt =================================================================== --- linux-2.6.orig/Documentation/power/devices.txt +++ linux-2.6/Documentation/power/devices.txt @@ -196,6 +196,11 @@ its parent; and can't be removed or susp The policy is that the device tree should match hardware bus topology. (Or at least the control bus, for devices which use multiple busses.) +In particular, this means that a device registration may fail if the parent of +the device is suspending (ie. has been chosen by the PM core as the next +device to suspend) or has already suspended, as well as after all of the other +devices have been suspended. Device drivers must be prepared to cope with such +situations. Suspending Devices ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/3] Driver core: Call device_pm_add() after bus_add_device() in device_add() [not found] <200803120055.25885.rjw@sisk.pl> 2008-03-11 23:57 ` [PATCH 1/3] PM: Handle device registrations during suspend/resume Rafael J. Wysocki @ 2008-03-11 23:59 ` Rafael J. Wysocki 2008-03-12 0:01 ` [PATCH 3/3] PM: make wakeup flags available whenever CONFIG_PM is set Rafael J. Wysocki ` (3 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Rafael J. Wysocki @ 2008-03-11 23:59 UTC (permalink / raw) To: Greg KH; +Cc: LKML, Andrew Morton, pm list From: Rafael J. Wysocki <rjw@sisk.pl> Include dpm_sysfs_add() into device_pm_add(), in analogy with device_pm_remove(), and modify device_add() to call the latter after bus_add_device(), to avoid situations in which the PM core may attempt to suspend a device the registration of which has not been successful. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> --- drivers/base/core.c | 15 +++++---------- drivers/base/power/main.c | 4 +++- 2 files changed, 8 insertions(+), 11 deletions(-) Index: linux-2.6/drivers/base/core.c =================================================================== --- linux-2.6.orig/drivers/base/core.c +++ linux-2.6/drivers/base/core.c @@ -812,17 +812,12 @@ int device_add(struct device *dev) error = device_add_attrs(dev); if (error) goto AttrsError; - error = dpm_sysfs_add(dev); - if (error) - goto PMError; - error = device_pm_add(dev); - if (error) { - dpm_sysfs_remove(dev); - goto PMError; - } error = bus_add_device(dev); if (error) goto BusError; + error = device_pm_add(dev); + if (error) + goto PMError; kobject_uevent(&dev->kobj, KOBJ_ADD); bus_attach_device(dev); if (parent) @@ -842,9 +837,9 @@ int device_add(struct device *dev) Done: put_device(dev); return error; - BusError: - device_pm_remove(dev); PMError: + bus_remove_device(dev); + BusError: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); Index: linux-2.6/drivers/base/power/main.c =================================================================== --- linux-2.6.orig/drivers/base/power/main.c +++ linux-2.6/drivers/base/power/main.c @@ -81,7 +81,9 @@ int device_pm_add(struct device *dev) WARN_ON(true); error = -EBUSY; } else { - list_add_tail(&dev->power.entry, &dpm_active); + error = dpm_sysfs_add(dev); + if (!error) + list_add_tail(&dev->power.entry, &dpm_active); } mutex_unlock(&dpm_list_mtx); return error; ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/3] PM: make wakeup flags available whenever CONFIG_PM is set [not found] <200803120055.25885.rjw@sisk.pl> 2008-03-11 23:57 ` [PATCH 1/3] PM: Handle device registrations during suspend/resume Rafael J. Wysocki 2008-03-11 23:59 ` [PATCH 2/3] Driver core: Call device_pm_add() after bus_add_device() in device_add() Rafael J. Wysocki @ 2008-03-12 0:01 ` Rafael J. Wysocki [not found] ` <200803120057.23101.rjw@sisk.pl> ` (2 subsequent siblings) 5 siblings, 0 replies; 9+ messages in thread From: Rafael J. Wysocki @ 2008-03-12 0:01 UTC (permalink / raw) To: Greg KH; +Cc: LKML, Andrew Morton, pm list From: Alan Stern <stern@rowland.harvard.edu> The various wakeup flags and their accessor macros in struct dev_pm_info should be available whenever CONFIG_PM is enabled, not just when CONFIG_PM_SLEEP is on. Otherwise remote wakeup won't always be configurable for runtime power management. This patch (as1056) fixes the oversight. [rjw: rebased the patch on top of the previous two.] Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: David Brownell <david-b@pacbell.net> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> --- drivers/base/power/main.c | 2 - drivers/base/power/sysfs.c | 2 + include/linux/pm.h | 64 +++++++++++++++++++++++++-------------------- 3 files changed, 38 insertions(+), 30 deletions(-) Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/include/linux/pm.h @@ -183,9 +183,9 @@ typedef struct pm_message { struct dev_pm_info { pm_message_t power_state; unsigned can_wakeup:1; + unsigned should_wakeup:1; bool sleeping:1; /* Owned by the PM core */ #ifdef CONFIG_PM_SLEEP - unsigned should_wakeup:1; struct list_head entry; #endif }; @@ -198,11 +198,6 @@ extern void device_resume(void); extern int device_suspend(pm_message_t state); extern int device_prepare_suspend(pm_message_t state); -#define device_set_wakeup_enable(dev,val) \ - ((dev)->power.should_wakeup = !!(val)) -#define device_may_wakeup(dev) \ - (device_can_wakeup(dev) && (dev)->power.should_wakeup) - extern void __suspend_report_result(const char *function, void *fn, int ret); #define suspend_report_result(fn, ret) \ @@ -210,6 +205,35 @@ extern void __suspend_report_result(cons __suspend_report_result(__FUNCTION__, fn, ret); \ } while (0) +#else /* !CONFIG_PM_SLEEP */ + +static inline int device_suspend(pm_message_t state) +{ + return 0; +} + +#define suspend_report_result(fn, ret) do {} while (0) + +#endif /* !CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM + +/* changes to device_may_wakeup take effect on the next pm state change. + * by default, devices should wakeup if they can. + */ +#define device_can_wakeup(dev) \ + ((dev)->power.can_wakeup) +#define device_init_wakeup(dev,val) \ + do { \ + device_can_wakeup(dev) = !!(val); \ + device_set_wakeup_enable(dev,val); \ + } while(0) + +#define device_set_wakeup_enable(dev,val) \ + ((dev)->power.should_wakeup = !!(val)) +#define device_may_wakeup(dev) \ + (device_can_wakeup(dev) && (dev)->power.should_wakeup) + /* * Platform hook to activate device wakeup capability, if that's not already * handled by enable_irq_wake() etc. @@ -224,35 +248,19 @@ static inline int call_platform_enable_w return 0; } -#else /* !CONFIG_PM_SLEEP */ - -static inline int device_suspend(pm_message_t state) -{ - return 0; -} - -#define device_set_wakeup_enable(dev,val) do{}while(0) -#define device_may_wakeup(dev) (0) +#else /* !CONFIG_PM */ -#define suspend_report_result(fn, ret) do { } while (0) +#define device_can_wakeup(dev) 0 +#define device_init_wakeup(dev,val) do {} while (0) +#define device_set_wakeup_enable(dev,val) do {} while (0) +#define device_may_wakeup(dev) 0 static inline int call_platform_enable_wakeup(struct device *dev, int is_on) { return 0; } -#endif /* !CONFIG_PM_SLEEP */ - -/* changes to device_may_wakeup take effect on the next pm state change. - * by default, devices should wakeup if they can. - */ -#define device_can_wakeup(dev) \ - ((dev)->power.can_wakeup) -#define device_init_wakeup(dev,val) \ - do { \ - device_can_wakeup(dev) = !!(val); \ - device_set_wakeup_enable(dev,val); \ - } while(0) +#endif /* !CONFIG_PM */ /* * Global Power Management flags Index: linux-2.6/drivers/base/power/main.c =================================================================== --- linux-2.6.orig/drivers/base/power/main.c +++ linux-2.6/drivers/base/power/main.c @@ -57,8 +57,6 @@ static DEFINE_MUTEX(dpm_list_mtx); /* 'true' if all devices have been suspended, protected by dpm_list_mtx */ static bool all_sleeping; -int (*platform_enable_wakeup)(struct device *dev, int is_on); - /** * device_pm_add - add a device to the list of active devices * @dev: Device to be added to the list Index: linux-2.6/drivers/base/power/sysfs.c =================================================================== --- linux-2.6.orig/drivers/base/power/sysfs.c +++ linux-2.6/drivers/base/power/sysfs.c @@ -6,6 +6,8 @@ #include <linux/string.h> #include "power.h" +int (*platform_enable_wakeup)(struct device *dev, int is_on); + /* * wakeup - Report/change current wakeup option for device ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <200803120057.23101.rjw@sisk.pl>]
* Re: [PATCH 1/3] PM: Handle device registrations during suspend/resume [not found] ` <200803120057.23101.rjw@sisk.pl> @ 2008-03-13 8:37 ` Pavel Machek 2008-03-13 20:54 ` patch pm-handle-device-registrations-during-suspend-resume.patch added to gregkh-2.6 tree gregkh 1 sibling, 0 replies; 9+ messages in thread From: Pavel Machek @ 2008-03-13 8:37 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: LKML, Andrew Morton, pm list On Wed 2008-03-12 00:57:22, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rjw@sisk.pl> > > Modify the PM core to protect its data structures, specifically the > dpm_active list, from being corrupted if a child of the currently > suspending device is registered concurrently with its ->suspend() > callback. In that case, since the new device (the child) is added > to dpm_active after its parent, the PM core will attempt to > suspend it after the parent, which is wrong. > > Introduce a new member of struct dev_pm_info, called 'sleeping', > and use it to check if the parent of the device being added to > dpm_active has been suspended, in which case the device registration > fails. Also, use 'sleeping' for checking if the ordering of devices > on dpm_active is correct. > > Introduce variable 'all_sleeping' that will be set to 'true' once all > devices have been suspended and make new device registrations fail > until 'all_sleeping' is reset to 'false', in order to avoid having > unsuspended devices around while the system is going into a sleep state. > > Remove pm_sleep_rwsem which is not necessary any more. > > Special thanks to Alan Stern for discussions and suggestions that > lead to the creation of this patch. > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> ACK. -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 9+ messages in thread
* patch pm-handle-device-registrations-during-suspend-resume.patch added to gregkh-2.6 tree [not found] ` <200803120057.23101.rjw@sisk.pl> 2008-03-13 8:37 ` [PATCH 1/3] PM: Handle device registrations during suspend/resume Pavel Machek @ 2008-03-13 20:54 ` gregkh 1 sibling, 0 replies; 9+ messages in thread From: gregkh @ 2008-03-13 20:54 UTC (permalink / raw) To: rjw, akpm, david-b, greg, gregkh, linux-kernel, linux-pm, pavel This is a note to let you know that I've just added the patch titled Subject: PM: Handle device registrations during suspend/resume to my gregkh-2.6 tree. Its filename is pm-handle-device-registrations-during-suspend-resume.patch This tree can be found at http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/ >From rjw@sisk.pl Thu Mar 13 13:44:50 2008 From: "Rafael J. Wysocki" <rjw@sisk.pl> Date: Wed, 12 Mar 2008 00:57:22 +0100 Subject: PM: Handle device registrations during suspend/resume To: Greg KH <greg@kroah.com> Cc: Alan Stern <stern@rowland.harvard.edu>, Andrew Morton <akpm@linux-foundation.org>, David Brownell <david-b@pacbell.net>, LKML <linux-kernel@vger.kernel.org>, Pavel Machek <pavel@ucw.cz>, pm list <linux-pm@lists.linux-foundation.org> Message-ID: <200803120057.23101.rjw@sisk.pl> Content-Disposition: inline From: Rafael J. Wysocki <rjw@sisk.pl> Modify the PM core to protect its data structures, specifically the dpm_active list, from being corrupted if a child of the currently suspending device is registered concurrently with its ->suspend() callback. In that case, since the new device (the child) is added to dpm_active after its parent, the PM core will attempt to suspend it after the parent, which is wrong. Introduce a new member of struct dev_pm_info, called 'sleeping', and use it to check if the parent of the device being added to dpm_active has been suspended, in which case the device registration fails. Also, use 'sleeping' for checking if the ordering of devices on dpm_active is correct. Introduce variable 'all_sleeping' that will be set to 'true' once all devices have been suspended and make new device registrations fail until 'all_sleeping' is reset to 'false', in order to avoid having unsuspended devices around while the system is going into a sleep state. Remove pm_sleep_rwsem which is not necessary any more. Special thanks to Alan Stern for discussions and suggestions that lead to the creation of this patch. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- Documentation/power/devices.txt | 5 +++ drivers/base/core.c | 6 +++- drivers/base/power/main.c | 57 ++++++++++++++++++---------------------- drivers/base/power/power.h | 23 ++-------------- include/linux/pm.h | 1 5 files changed, 40 insertions(+), 52 deletions(-) --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -196,6 +196,11 @@ its parent; and can't be removed or susp The policy is that the device tree should match hardware bus topology. (Or at least the control bus, for devices which use multiple busses.) +In particular, this means that a device registration may fail if the parent of +the device is suspending (ie. has been chosen by the PM core as the next +device to suspend) or has already suspended, as well as after all of the other +devices have been suspended. Device drivers must be prepared to cope with such +situations. Suspending Devices --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -821,7 +821,11 @@ int device_add(struct device *dev) error = dpm_sysfs_add(dev); if (error) goto PMError; - device_pm_add(dev); + error = device_pm_add(dev); + if (error) { + dpm_sysfs_remove(dev); + goto PMError; + } error = bus_add_device(dev); if (error) goto BusError; --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -54,7 +54,8 @@ static LIST_HEAD(dpm_destroy); static DEFINE_MUTEX(dpm_list_mtx); -static DECLARE_RWSEM(pm_sleep_rwsem); +/* 'true' if all devices have been suspended, protected by dpm_list_mtx */ +static bool all_sleeping; int (*platform_enable_wakeup)(struct device *dev, int is_on); @@ -62,14 +63,28 @@ int (*platform_enable_wakeup)(struct dev * device_pm_add - add a device to the list of active devices * @dev: Device to be added to the list */ -void device_pm_add(struct device *dev) +int device_pm_add(struct device *dev) { + int error = 0; + pr_debug("PM: Adding info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", kobject_name(&dev->kobj)); mutex_lock(&dpm_list_mtx); - list_add_tail(&dev->power.entry, &dpm_active); + if ((dev->parent && dev->parent->power.sleeping) || all_sleeping) { + if (dev->parent->power.sleeping) + dev_warn(dev, + "parent %s is sleeping, will not add\n", + dev->parent->bus_id); + else + dev_warn(dev, "devices are sleeping, will not add\n"); + WARN_ON(true); + error = -EBUSY; + } else { + list_add_tail(&dev->power.entry, &dpm_active); + } mutex_unlock(&dpm_list_mtx); + return error; } /** @@ -107,32 +122,6 @@ void device_pm_schedule_removal(struct d } EXPORT_SYMBOL_GPL(device_pm_schedule_removal); -/** - * pm_sleep_lock - mutual exclusion for registration and suspend - * - * Returns 0 if no suspend is underway and device registration - * may proceed, otherwise -EBUSY. - */ -int pm_sleep_lock(void) -{ - if (down_read_trylock(&pm_sleep_rwsem)) - return 0; - - return -EBUSY; -} - -/** - * pm_sleep_unlock - mutual exclusion for registration and suspend - * - * This routine undoes the effect of device_pm_add_lock - * when a device's registration is complete. - */ -void pm_sleep_unlock(void) -{ - up_read(&pm_sleep_rwsem); -} - - /*------------------------- Resume routines -------------------------*/ /** @@ -242,11 +231,13 @@ static int resume_device(struct device * static void dpm_resume(void) { mutex_lock(&dpm_list_mtx); + all_sleeping = false; while(!list_empty(&dpm_off)) { struct list_head *entry = dpm_off.next; struct device *dev = to_device(entry); list_move_tail(entry, &dpm_active); + dev->power.sleeping = false; mutex_unlock(&dpm_list_mtx); resume_device(dev); mutex_lock(&dpm_list_mtx); @@ -285,7 +276,6 @@ void device_resume(void) might_sleep(); dpm_resume(); unregister_dropped_devices(); - up_write(&pm_sleep_rwsem); } EXPORT_SYMBOL_GPL(device_resume); @@ -421,6 +411,9 @@ static int dpm_suspend(pm_message_t stat struct list_head *entry = dpm_active.prev; struct device *dev = to_device(entry); + WARN_ON(dev->parent && dev->parent->power.sleeping); + + dev->power.sleeping = true; mutex_unlock(&dpm_list_mtx); error = suspend_device(dev, state); mutex_lock(&dpm_list_mtx); @@ -432,11 +425,14 @@ static int dpm_suspend(pm_message_t stat (error == -EAGAIN ? " (please convert to suspend_late)" : "")); + dev->power.sleeping = false; break; } if (!list_empty(&dev->power.entry)) list_move(&dev->power.entry, &dpm_off); } + if (!error) + all_sleeping = true; mutex_unlock(&dpm_list_mtx); return error; @@ -454,7 +450,6 @@ int device_suspend(pm_message_t state) int error; might_sleep(); - down_write(&pm_sleep_rwsem); error = dpm_suspend(state); if (error) device_resume(); --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -11,30 +11,13 @@ static inline struct device *to_device(s return container_of(entry, struct device, power.entry); } -extern void device_pm_add(struct device *); +extern int device_pm_add(struct device *); extern void device_pm_remove(struct device *); -extern int pm_sleep_lock(void); -extern void pm_sleep_unlock(void); #else /* CONFIG_PM_SLEEP */ - -static inline void device_pm_add(struct device *dev) -{ -} - -static inline void device_pm_remove(struct device *dev) -{ -} - -static inline int pm_sleep_lock(void) -{ - return 0; -} - -static inline void pm_sleep_unlock(void) -{ -} +static inline int device_pm_add(struct device *dev) { return 0; } +static inline void device_pm_remove(struct device *dev) {} #endif --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -183,6 +183,7 @@ typedef struct pm_message { struct dev_pm_info { pm_message_t power_state; unsigned can_wakeup:1; + bool sleeping:1; /* Owned by the PM core */ #ifdef CONFIG_PM_SLEEP unsigned should_wakeup:1; struct list_head entry; Patches currently in gregkh-2.6 which might be from rjw@sisk.pl are driver-core/power_state-remove-it-from-driver-core.patch driver-core/pm-handle-device-registrations-during-suspend-resume.patch driver-core/pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch driver-core/driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <200803120059.39902.rjw@sisk.pl>]
* Re: [PATCH 2/3] Driver core: Call device_pm_add() after bus_add_device() in device_add() [not found] ` <200803120059.39902.rjw@sisk.pl> @ 2008-03-13 9:30 ` Pavel Machek 2008-03-13 20:54 ` patch driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch added to gregkh-2.6 tree gregkh 1 sibling, 0 replies; 9+ messages in thread From: Pavel Machek @ 2008-03-13 9:30 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: LKML, Andrew Morton, pm list On Wed 2008-03-12 00:59:38, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rjw@sisk.pl> > > Include dpm_sysfs_add() into device_pm_add(), in analogy with > device_pm_remove(), and modify device_add() to call the latter after > bus_add_device(), to avoid situations in which the PM core may > attempt to suspend a device the registration of which has not been > successful. > > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> ACK. -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 9+ messages in thread
* patch driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch added to gregkh-2.6 tree [not found] ` <200803120059.39902.rjw@sisk.pl> 2008-03-13 9:30 ` [PATCH 2/3] Driver core: Call device_pm_add() after bus_add_device() in device_add() Pavel Machek @ 2008-03-13 20:54 ` gregkh 1 sibling, 0 replies; 9+ messages in thread From: gregkh @ 2008-03-13 20:54 UTC (permalink / raw) To: rjw, akpm, david-b, greg, gregkh, linux-kernel, linux-pm, pavel This is a note to let you know that I've just added the patch titled Subject: Driver core: Call device_pm_add() after bus_add_device() in device_add() to my gregkh-2.6 tree. Its filename is driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch This tree can be found at http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/ >From rjw@sisk.pl Thu Mar 13 13:45:38 2008 From: "Rafael J. Wysocki" <rjw@sisk.pl> Date: Wed, 12 Mar 2008 00:59:38 +0100 Subject: Driver core: Call device_pm_add() after bus_add_device() in device_add() To: Greg KH <greg@kroah.com> Cc: Alan Stern <stern@rowland.harvard.edu>, Andrew Morton <akpm@linux-foundation.org>, David Brownell <david-b@pacbell.net>, LKML <linux-kernel@vger.kernel.org>, Pavel Machek <pavel@ucw.cz>, pm list <linux-pm@lists.linux-foundation.org> Message-ID: <200803120059.39902.rjw@sisk.pl> Content-Disposition: inline From: Rafael J. Wysocki <rjw@sisk.pl> Include dpm_sysfs_add() into device_pm_add(), in analogy with device_pm_remove(), and modify device_add() to call the latter after bus_add_device(), to avoid situations in which the PM core may attempt to suspend a device the registration of which has not been successful. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/base/core.c | 15 +++++---------- drivers/base/power/main.c | 4 +++- 2 files changed, 8 insertions(+), 11 deletions(-) --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -818,17 +818,12 @@ int device_add(struct device *dev) error = device_add_attrs(dev); if (error) goto AttrsError; - error = dpm_sysfs_add(dev); - if (error) - goto PMError; - error = device_pm_add(dev); - if (error) { - dpm_sysfs_remove(dev); - goto PMError; - } error = bus_add_device(dev); if (error) goto BusError; + error = device_pm_add(dev); + if (error) + goto PMError; kobject_uevent(&dev->kobj, KOBJ_ADD); bus_attach_device(dev); if (parent) @@ -848,9 +843,9 @@ int device_add(struct device *dev) Done: put_device(dev); return error; - BusError: - device_pm_remove(dev); PMError: + bus_remove_device(dev); + BusError: if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -81,7 +81,9 @@ int device_pm_add(struct device *dev) WARN_ON(true); error = -EBUSY; } else { - list_add_tail(&dev->power.entry, &dpm_active); + error = dpm_sysfs_add(dev); + if (!error) + list_add_tail(&dev->power.entry, &dpm_active); } mutex_unlock(&dpm_list_mtx); return error; Patches currently in gregkh-2.6 which might be from rjw@sisk.pl are driver-core/power_state-remove-it-from-driver-core.patch driver-core/pm-handle-device-registrations-during-suspend-resume.patch driver-core/pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch driver-core/driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch ^ permalink raw reply [flat|nested] 9+ messages in thread
[parent not found: <200803120101.48805.rjw@sisk.pl>]
* Re: [PATCH 3/3] PM: make wakeup flags available whenever CONFIG_PM is set [not found] ` <200803120101.48805.rjw@sisk.pl> @ 2008-03-13 9:31 ` Pavel Machek 2008-03-13 20:54 ` patch pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch added to gregkh-2.6 tree gregkh 1 sibling, 0 replies; 9+ messages in thread From: Pavel Machek @ 2008-03-13 9:31 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: LKML, Andrew Morton, pm list On Wed 2008-03-12 01:01:47, Rafael J. Wysocki wrote: > From: Alan Stern <stern@rowland.harvard.edu> > > The various wakeup flags and their accessor macros in struct > dev_pm_info should be available whenever CONFIG_PM is enabled, not > just when CONFIG_PM_SLEEP is on. Otherwise remote wakeup won't always > be configurable for runtime power management. This patch (as1056) > fixes the oversight. > > [rjw: rebased the patch on top of the previous two.] > > Signed-off-by: Alan Stern <stern@rowland.harvard.edu> > CC: David Brownell <david-b@pacbell.net> > Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> ACK. But I wonder if we should reduce ammount of config options we have in power management. All those combinations are hard to test... Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 9+ messages in thread
* patch pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch added to gregkh-2.6 tree [not found] ` <200803120101.48805.rjw@sisk.pl> 2008-03-13 9:31 ` [PATCH 3/3] PM: make wakeup flags available whenever CONFIG_PM is set Pavel Machek @ 2008-03-13 20:54 ` gregkh 1 sibling, 0 replies; 9+ messages in thread From: gregkh @ 2008-03-13 20:54 UTC (permalink / raw) To: stern, akpm, david-b, greg, gregkh, linux-kernel, linux-pm This is a note to let you know that I've just added the patch titled Subject: PM: make wakeup flags available whenever CONFIG_PM is set to my gregkh-2.6 tree. Its filename is pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch This tree can be found at http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/ >From rjw@sisk.pl Thu Mar 13 13:46:04 2008 From: Alan Stern <stern@rowland.harvard.edu> Date: Wed, 12 Mar 2008 01:01:47 +0100 Subject: PM: make wakeup flags available whenever CONFIG_PM is set To: Greg KH <greg@kroah.com> Cc: Alan Stern <stern@rowland.harvard.edu>, Andrew Morton <akpm@linux-foundation.org>, David Brownell <david-b@pacbell.net>, LKML <linux-kernel@vger.kernel.org>, Pavel Machek <pavel@ucw.cz>, pm list <linux-pm@lists.linux-foundation.org> Message-ID: <200803120101.48805.rjw@sisk.pl> Content-Disposition: inline From: Alan Stern <stern@rowland.harvard.edu> The various wakeup flags and their accessor macros in struct dev_pm_info should be available whenever CONFIG_PM is enabled, not just when CONFIG_PM_SLEEP is on. Otherwise remote wakeup won't always be configurable for runtime power management. This patch (as1056) fixes the oversight. [rjw: rebased the patch on top of the previous two.] Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: David Brownell <david-b@pacbell.net> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- drivers/base/power/main.c | 2 - drivers/base/power/sysfs.c | 2 + include/linux/pm.h | 64 +++++++++++++++++++++++++-------------------- 3 files changed, 38 insertions(+), 30 deletions(-) --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -57,8 +57,6 @@ static DEFINE_MUTEX(dpm_list_mtx); /* 'true' if all devices have been suspended, protected by dpm_list_mtx */ static bool all_sleeping; -int (*platform_enable_wakeup)(struct device *dev, int is_on); - /** * device_pm_add - add a device to the list of active devices * @dev: Device to be added to the list --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -6,6 +6,8 @@ #include <linux/string.h> #include "power.h" +int (*platform_enable_wakeup)(struct device *dev, int is_on); + /* * wakeup - Report/change current wakeup option for device --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -183,9 +183,9 @@ typedef struct pm_message { struct dev_pm_info { pm_message_t power_state; unsigned can_wakeup:1; + unsigned should_wakeup:1; bool sleeping:1; /* Owned by the PM core */ #ifdef CONFIG_PM_SLEEP - unsigned should_wakeup:1; struct list_head entry; #endif }; @@ -198,11 +198,6 @@ extern void device_resume(void); extern int device_suspend(pm_message_t state); extern int device_prepare_suspend(pm_message_t state); -#define device_set_wakeup_enable(dev,val) \ - ((dev)->power.should_wakeup = !!(val)) -#define device_may_wakeup(dev) \ - (device_can_wakeup(dev) && (dev)->power.should_wakeup) - extern void __suspend_report_result(const char *function, void *fn, int ret); #define suspend_report_result(fn, ret) \ @@ -210,6 +205,35 @@ extern void __suspend_report_result(cons __suspend_report_result(__FUNCTION__, fn, ret); \ } while (0) +#else /* !CONFIG_PM_SLEEP */ + +static inline int device_suspend(pm_message_t state) +{ + return 0; +} + +#define suspend_report_result(fn, ret) do {} while (0) + +#endif /* !CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM + +/* changes to device_may_wakeup take effect on the next pm state change. + * by default, devices should wakeup if they can. + */ +#define device_can_wakeup(dev) \ + ((dev)->power.can_wakeup) +#define device_init_wakeup(dev,val) \ + do { \ + device_can_wakeup(dev) = !!(val); \ + device_set_wakeup_enable(dev,val); \ + } while(0) + +#define device_set_wakeup_enable(dev,val) \ + ((dev)->power.should_wakeup = !!(val)) +#define device_may_wakeup(dev) \ + (device_can_wakeup(dev) && (dev)->power.should_wakeup) + /* * Platform hook to activate device wakeup capability, if that's not already * handled by enable_irq_wake() etc. @@ -224,35 +248,19 @@ static inline int call_platform_enable_w return 0; } -#else /* !CONFIG_PM_SLEEP */ - -static inline int device_suspend(pm_message_t state) -{ - return 0; -} - -#define device_set_wakeup_enable(dev,val) do{}while(0) -#define device_may_wakeup(dev) (0) +#else /* !CONFIG_PM */ -#define suspend_report_result(fn, ret) do { } while (0) +#define device_can_wakeup(dev) 0 +#define device_init_wakeup(dev,val) do {} while (0) +#define device_set_wakeup_enable(dev,val) do {} while (0) +#define device_may_wakeup(dev) 0 static inline int call_platform_enable_wakeup(struct device *dev, int is_on) { return 0; } -#endif /* !CONFIG_PM_SLEEP */ - -/* changes to device_may_wakeup take effect on the next pm state change. - * by default, devices should wakeup if they can. - */ -#define device_can_wakeup(dev) \ - ((dev)->power.can_wakeup) -#define device_init_wakeup(dev,val) \ - do { \ - device_can_wakeup(dev) = !!(val); \ - device_set_wakeup_enable(dev,val); \ - } while(0) +#endif /* !CONFIG_PM */ /* * Global Power Management flags Patches currently in gregkh-2.6 which might be from stern@rowland.harvard.edu are usb/usb-convert-usb.h-struct-usb_device-to-kernel-doc.patch usb/usb-make-usb_storage_onetouch-available-with-pm.patch usb/usb-usb-ohci-sm501-driver-use-the-conventional-convention-for-suspend-and-resume.patch usb/usb-reorganize-code-in-hub.c.patch usb/usb-ehci-carry-out-port-handover-during-each-root-hub-resume.patch usb/usb-new-quirk-flag-to-avoid-set-interface.patch usb/drivers-usb-core-devio.c-suppress-warning-with-64k-page_size.patch usb/usb-make-usb-persist-work-after-every-system-sleep.patch usb/usb-remove-config_usb_persist-setting.patch usb/usb-check-serial-number-string-after-device-reset.patch usb/usb-enable-usb-persist-by-default.patch usb/usb-remove-dev-power.power_state.patch driver-core/pm-handle-device-registrations-during-suspend-resume.patch driver-core/pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch driver-core/driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-03-13 20:54 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <200803120055.25885.rjw@sisk.pl>
2008-03-11 23:57 ` [PATCH 1/3] PM: Handle device registrations during suspend/resume Rafael J. Wysocki
2008-03-11 23:59 ` [PATCH 2/3] Driver core: Call device_pm_add() after bus_add_device() in device_add() Rafael J. Wysocki
2008-03-12 0:01 ` [PATCH 3/3] PM: make wakeup flags available whenever CONFIG_PM is set Rafael J. Wysocki
[not found] ` <200803120057.23101.rjw@sisk.pl>
2008-03-13 8:37 ` [PATCH 1/3] PM: Handle device registrations during suspend/resume Pavel Machek
2008-03-13 20:54 ` patch pm-handle-device-registrations-during-suspend-resume.patch added to gregkh-2.6 tree gregkh
[not found] ` <200803120059.39902.rjw@sisk.pl>
2008-03-13 9:30 ` [PATCH 2/3] Driver core: Call device_pm_add() after bus_add_device() in device_add() Pavel Machek
2008-03-13 20:54 ` patch driver-core-call-device_pm_add-after-bus_add_device-in-device_add.patch added to gregkh-2.6 tree gregkh
[not found] ` <200803120101.48805.rjw@sisk.pl>
2008-03-13 9:31 ` [PATCH 3/3] PM: make wakeup flags available whenever CONFIG_PM is set Pavel Machek
2008-03-13 20:54 ` patch pm-make-wakeup-flags-available-whenever-config_pm-is-set.patch added to gregkh-2.6 tree gregkh
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox