From 53823639173cc9e9a261f68f4abefe62364b86c6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 23 Jan 2010 22:02:51 +0100 Subject: PM / Runtime: Add sysfs switch for disabling device run-time PM Add new device sysfs attribute, power/control, allowing the user space to block the run-time power management of the devices. If this attribute is set to "on", the driver of the device won't be able to power manage it at run time (without breaking the rules) and the device will always be in the full power state (except when the entire system goes into a sleep state). Signed-off-by: Rafael J. Wysocki Acked-by: Alan Stern --- include/linux/pm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/pm.h') diff --git a/include/linux/pm.h b/include/linux/pm.h index 198b8f9fe05e..25b1eca8049d 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -430,6 +430,7 @@ struct dev_pm_info { unsigned int request_pending:1; unsigned int deferred_resume:1; unsigned int run_wake:1; + unsigned int runtime_auto:1; enum rpm_request request; enum rpm_status runtime_status; int runtime_error; -- cgit v1.2.2 From 5af84b82701a96be4b033aaa51d86c72e2ded061 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 23 Jan 2010 22:23:32 +0100 Subject: PM: Asynchronous suspend and resume of devices Theoretically, the total time of system sleep transitions (suspend to RAM, hibernation) can be reduced by running suspend and resume callbacks of device drivers in parallel with each other. However, there are dependencies between devices such that we're not allowed to suspend the parent of a device before suspending the device itself. Analogously, we're not allowed to resume a device before resuming its parent. The most straightforward way to take these dependencies into accout is to start the async threads used for suspending and resuming devices at the core level, so that async_schedule() is called for each suspend and resume callback supposed to be executed asynchronously. For this purpose, introduce a new device flag, power.async_suspend, used to mark the devices whose suspend and resume callbacks are to be executed asynchronously (ie. in parallel with the main suspend/resume thread and possibly in parallel with each other) and helper function device_enable_async_suspend() allowing one to set power.async_suspend for given device (power.async_suspend is unset by default for all devices). For each device with the power.async_suspend flag set the PM core will use async_schedule() to execute its suspend and resume callbacks. The async threads started for different devices as a result of calling async_schedule() are synchronized with each other and with the main suspend/resume thread with the help of completions, in the following way: (1) There is a completion, power.completion, for each device object. (2) Each device's completion is reset before calling async_schedule() for the device or, in the case of devices with the power.async_suspend flags unset, before executing the device's suspend and resume callbacks. (3) During suspend, right before running the bus type, device type and device class suspend callbacks for the device, the PM core waits for the completions of all the device's children to be completed. (4) During resume, right before running the bus type, device type and device class resume callbacks for the device, the PM core waits for the completion of the device's parent to be completed. (5) The PM core completes power.completion for each device right after the bus type, device type and device class suspend (or resume) callbacks executed for the device have returned. Signed-off-by: Rafael J. Wysocki --- include/linux/pm.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux/pm.h') diff --git a/include/linux/pm.h b/include/linux/pm.h index 25b1eca8049d..9c16cd20fc96 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -26,6 +26,7 @@ #include #include #include +#include /* * Callbacks for platform drivers to implement. @@ -412,9 +413,11 @@ struct dev_pm_info { pm_message_t power_state; unsigned int can_wakeup:1; unsigned int should_wakeup:1; + unsigned async_suspend:1; enum dpm_state status; /* Owned by the PM core */ #ifdef CONFIG_PM_SLEEP struct list_head entry; + struct completion completion; #endif #ifdef CONFIG_PM_RUNTIME struct timer_list suspend_timer; -- cgit v1.2.2 From f8824cee405c62ba465b85365201166d9cf86a14 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 27 Jan 2010 23:47:38 +0100 Subject: PM: Allow device drivers to use dpm_wait() There are some dependencies between devices (in particular, between EHCI USB controllers and their OHCI/UHCI siblings) which are not reflected by the structure of the device tree. With synchronous suspend and resume these dependencies are taken into accout automatically, because the devices in question are always registered in the right order, but to meet these constraints with asynchronous suspend and resume the drivers of these devices will need to use dpm_wait() in their suspend/resume routines, so introduce a helper function allowing them to do that. Signed-off-by: Rafael J. Wysocki --- include/linux/pm.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux/pm.h') diff --git a/include/linux/pm.h b/include/linux/pm.h index 9c16cd20fc96..e80df06ad22a 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -512,6 +512,7 @@ extern void __suspend_report_result(const char *function, void *fn, int ret); __suspend_report_result(__func__, fn, ret); \ } while (0) +extern void device_pm_wait_for_dev(struct device *sub, struct device *dev); #else /* !CONFIG_PM_SLEEP */ #define device_pm_lock() do {} while (0) @@ -524,6 +525,7 @@ static inline int dpm_suspend_start(pm_message_t state) #define suspend_report_result(fn, ret) do {} while (0) +static inline void device_pm_wait_for_dev(struct device *a, struct device *b) {} #endif /* !CONFIG_PM_SLEEP */ /* How to reorder dpm_list after device_move() */ -- cgit v1.2.2 From d690b2cd222afc75320b9b8e9da7df02e9e630ca Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 6 Mar 2010 21:28:37 +0100 Subject: PM: Provide generic subsystem-level callbacks There are subsystems whose power management callbacks only need to invoke the callbacks provided by device drivers. Still, their system sleep PM callbacks should play well with the runtime PM callbacks, so that devices suspended at run time can be left in that state for a system sleep transition. Provide a set of generic PM callbacks for such subsystems and define convenience macros for populating dev_pm_ops structures. Signed-off-by: Rafael J. Wysocki --- include/linux/pm.h | 51 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) (limited to 'include/linux/pm.h') diff --git a/include/linux/pm.h b/include/linux/pm.h index e80df06ad22a..8e258c727971 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -215,20 +215,59 @@ struct dev_pm_ops { int (*runtime_idle)(struct device *dev); }; +#ifdef CONFIG_PM_SLEEP +#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ + .suspend = suspend_fn, \ + .resume = resume_fn, \ + .freeze = suspend_fn, \ + .thaw = resume_fn, \ + .poweroff = suspend_fn, \ + .restore = resume_fn, +#else +#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) +#endif + +#ifdef CONFIG_PM_RUNTIME +#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ + .runtime_suspend = suspend_fn, \ + .runtime_resume = resume_fn, \ + .runtime_idle = idle_fn, +#else +#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) +#endif + /* * Use this if you want to use the same suspend and resume callbacks for suspend * to RAM and hibernation. */ #define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ const struct dev_pm_ops name = { \ - .suspend = suspend_fn, \ - .resume = resume_fn, \ - .freeze = suspend_fn, \ - .thaw = resume_fn, \ - .poweroff = suspend_fn, \ - .restore = resume_fn, \ + SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +} + +/* + * Use this for defining a set of PM operations to be used in all situations + * (sustem suspend, hibernation or runtime PM). + */ +#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ +const struct dev_pm_ops name = { \ + SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ + SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ } +/* + * Use this for subsystems (bus types, device types, device classes) that don't + * need any special suspend/resume handling in addition to invoking the PM + * callbacks provided by device drivers supporting both the system sleep PM and + * runtime PM, make the pm member point to generic_subsys_pm_ops. + */ +#ifdef CONFIG_PM_OPS +extern struct dev_pm_ops generic_subsys_pm_ops; +#define GENERIC_SUBSYS_PM_OPS (&generic_subsys_pm_ops) +#else +#define GENERIC_SUBSYS_PM_OPS NULL +#endif + /** * PM_EVENT_ messages * -- cgit v1.2.2