* [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions
@ 2010-02-26 16:46 Alan Stern
2010-02-26 21:24 ` Rafael J. Wysocki
0 siblings, 1 reply; 21+ messages in thread
From: Alan Stern @ 2010-02-26 16:46 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: Linux-pm mailing list
This patch (as1345) adds utility routines pm_is_runtime_suspended(),
dpm_use_runtime_suspend(), and dpm_use_runtime_resume() to the PM
core. The first provides an API to access a device's runtime PM
status, and the other two give drivers an easy way to use the same
callback routines for both system PM and runtime PM. The new
functions can be used as ->suspend() and ->resume() methods; they will
invoke the device's ->runtime_suspend() and runtime_resume() callbacks
to do the work.
This facility was requested by people working on embedded systems.
It is a little awkward, because it means the runtime callbacks may be
invoked whenever either CONFIG_PM_SLEEP or CONFIG_PM_RUNTIME is
enabled. Since these settings are independent, the patch separates
out the code for invoking the callbacks into a new source file:
invoke_runtime.c. The new file gets built if either config option is
on.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
---
Note that this patch does introduce a small semantic change. -ENOSYS
is no longer available for use as a return value from the runtime
callbacks, because it is reserved to mean that there is no callback
function.
Index: usb-2.6/include/linux/pm.h
===================================================================
--- usb-2.6.orig/include/linux/pm.h
+++ usb-2.6/include/linux/pm.h
@@ -508,6 +508,9 @@ extern void __suspend_report_result(cons
__suspend_report_result(__func__, fn, ret); \
} while (0)
+extern int dpm_use_runtime_suspend(struct device *dev);
+extern int dpm_use_runtime_resume(struct device *dev);
+
#else /* !CONFIG_PM_SLEEP */
#define device_pm_lock() do {} while (0)
@@ -520,6 +523,9 @@ static inline int dpm_suspend_start(pm_m
#define suspend_report_result(fn, ret) do {} while (0)
+#define dpm_use_runtime_suspend NULL
+#define dpm_use_runtime_resume NULL
+
#endif /* !CONFIG_PM_SLEEP */
/* How to reorder dpm_list after device_move() */
Index: usb-2.6/include/linux/pm_runtime.h
===================================================================
--- usb-2.6.orig/include/linux/pm_runtime.h
+++ usb-2.6/include/linux/pm_runtime.h
@@ -60,6 +60,11 @@ static inline void device_set_run_wake(s
dev->power.run_wake = enable;
}
+static inline bool pm_is_runtime_suspended(struct device *dev)
+{
+ return dev->power.runtime_status == RPM_SUSPENDED;
+}
+
#else /* !CONFIG_PM_RUNTIME */
static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; }
@@ -86,6 +91,9 @@ static inline void pm_runtime_put_noidle
static inline bool device_run_wake(struct device *dev) { return false; }
static inline void device_set_run_wake(struct device *dev, bool enable) {}
+static inline bool pm_is_runtime_suspended(struct device *dev)
+ { return false; }
+
#endif /* !CONFIG_PM_RUNTIME */
static inline int pm_runtime_get(struct device *dev)
Index: usb-2.6/drivers/base/power/power.h
===================================================================
--- usb-2.6.orig/drivers/base/power/power.h
+++ usb-2.6/drivers/base/power/power.h
@@ -72,3 +72,14 @@ static inline void dpm_sysfs_remove(stru
}
#endif
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+
+/*
+ * invoke_runtime.c
+ */
+extern void dpm_invoke_runtime_idle(struct device *dev);
+extern int dpm_invoke_runtime_suspend(struct device *dev);
+extern int dpm_invoke_runtime_resume(struct device *dev);
+
+#endif
Index: usb-2.6/drivers/base/power/Makefile
===================================================================
--- usb-2.6.orig/drivers/base/power/Makefile
+++ usb-2.6/drivers/base/power/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_PM) += sysfs.o
-obj-$(CONFIG_PM_SLEEP) += main.o
-obj-$(CONFIG_PM_RUNTIME) += runtime.o
+obj-$(CONFIG_PM_SLEEP) += main.o invoke_runtime.o
+obj-$(CONFIG_PM_RUNTIME) += runtime.o invoke_runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
Index: usb-2.6/drivers/base/power/main.c
===================================================================
--- usb-2.6.orig/drivers/base/power/main.c
+++ usb-2.6/drivers/base/power/main.c
@@ -936,3 +936,51 @@ void __suspend_report_result(const char
printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
}
EXPORT_SYMBOL_GPL(__suspend_report_result);
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+
+/* Convenience routines for drivers that want to use the same functions
+ * for system suspend/resume and runtime suspend/resume:
+ * Set driver->pm_ops->suspend = dpm_use_runtime_suspend and
+ * driver->pm_ops->resume = dpm_use_runtime_resume.
+ */
+
+/**
+ * dpm_use_runtime_suspend - Perform system suspend via runtime_suspend method
+ * @dev: Device to suspend.
+ *
+ * This convenience routine implements a system suspend by invoking the
+ * runtime_suspend method. The method is invoked only if @dev isn't already
+ * runtime-suspended.
+ */
+int dpm_use_runtime_suspend(struct device *dev)
+{
+ if (pm_is_runtime_suspended(dev))
+ return 0;
+ return dpm_invoke_runtime_suspend(dev);
+}
+EXPORT_SYMBOL_GPL(dpm_use_runtime_suspend);
+
+/**
+ * dpm_use_runtime_resume - Perform system resume via runtime_resume method
+ * @dev: Device to resume.
+ *
+ * This convenience routine implements a system resume by invoking the
+ * runtime_resume method. If the method is successful then the device's
+ * runtime status is set to RPM_ACTIVE.
+ */
+int dpm_use_runtime_resume(struct device *dev)
+{
+ int retval;
+
+ retval = dpm_invoke_runtime_resume(dev);
+ if (retval == 0) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+ return retval;
+}
+EXPORT_SYMBOL_GPL(dpm_use_runtime_resume);
+
+#endif /* defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) */
Index: usb-2.6/drivers/base/power/runtime.c
===================================================================
--- usb-2.6.orig/drivers/base/power/runtime.c
+++ usb-2.6/drivers/base/power/runtime.c
@@ -10,6 +10,8 @@
#include <linux/pm_runtime.h>
#include <linux/jiffies.h>
+#include "power.h"
+
static int __pm_runtime_resume(struct device *dev, bool from_wq);
static int __pm_request_idle(struct device *dev);
static int __pm_request_resume(struct device *dev);
@@ -79,26 +81,9 @@ static int __pm_runtime_idle(struct devi
dev->power.idle_notification = true;
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
- spin_unlock_irq(&dev->power.lock);
-
- dev->bus->pm->runtime_idle(dev);
-
- spin_lock_irq(&dev->power.lock);
- } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
- spin_unlock_irq(&dev->power.lock);
-
- dev->type->pm->runtime_idle(dev);
-
- spin_lock_irq(&dev->power.lock);
- } else if (dev->class && dev->class->pm
- && dev->class->pm->runtime_idle) {
- spin_unlock_irq(&dev->power.lock);
-
- dev->class->pm->runtime_idle(dev);
-
- spin_lock_irq(&dev->power.lock);
- }
+ spin_unlock_irq(&dev->power.lock);
+ dpm_invoke_runtime_idle(dev);
+ spin_lock_irq(&dev->power.lock);
dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);
@@ -200,32 +185,11 @@ int __pm_runtime_suspend(struct device *
dev->power.runtime_status = RPM_SUSPENDING;
dev->power.deferred_resume = false;
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
- spin_unlock_irq(&dev->power.lock);
-
- retval = dev->bus->pm->runtime_suspend(dev);
-
- spin_lock_irq(&dev->power.lock);
- dev->power.runtime_error = retval;
- } else if (dev->type && dev->type->pm
- && dev->type->pm->runtime_suspend) {
- spin_unlock_irq(&dev->power.lock);
-
- retval = dev->type->pm->runtime_suspend(dev);
-
- spin_lock_irq(&dev->power.lock);
- dev->power.runtime_error = retval;
- } else if (dev->class && dev->class->pm
- && dev->class->pm->runtime_suspend) {
- spin_unlock_irq(&dev->power.lock);
-
- retval = dev->class->pm->runtime_suspend(dev);
-
- spin_lock_irq(&dev->power.lock);
+ spin_unlock_irq(&dev->power.lock);
+ retval = dpm_invoke_runtime_suspend(dev);
+ spin_lock_irq(&dev->power.lock);
+ if (retval != -ENOSYS)
dev->power.runtime_error = retval;
- } else {
- retval = -ENOSYS;
- }
if (retval) {
dev->power.runtime_status = RPM_ACTIVE;
@@ -381,32 +345,11 @@ int __pm_runtime_resume(struct device *d
dev->power.runtime_status = RPM_RESUMING;
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
- spin_unlock_irq(&dev->power.lock);
-
- retval = dev->bus->pm->runtime_resume(dev);
-
- spin_lock_irq(&dev->power.lock);
- dev->power.runtime_error = retval;
- } else if (dev->type && dev->type->pm
- && dev->type->pm->runtime_resume) {
- spin_unlock_irq(&dev->power.lock);
-
- retval = dev->type->pm->runtime_resume(dev);
-
- spin_lock_irq(&dev->power.lock);
- dev->power.runtime_error = retval;
- } else if (dev->class && dev->class->pm
- && dev->class->pm->runtime_resume) {
- spin_unlock_irq(&dev->power.lock);
-
- retval = dev->class->pm->runtime_resume(dev);
-
- spin_lock_irq(&dev->power.lock);
+ spin_unlock_irq(&dev->power.lock);
+ retval = dpm_invoke_runtime_resume(dev);
+ spin_lock_irq(&dev->power.lock);
+ if (retval != -ENOSYS)
dev->power.runtime_error = retval;
- } else {
- retval = -ENOSYS;
- }
if (retval) {
dev->power.runtime_status = RPM_SUSPENDED;
Index: usb-2.6/drivers/base/power/invoke_runtime.c
===================================================================
--- /dev/null
+++ usb-2.6/drivers/base/power/invoke_runtime.c
@@ -0,0 +1,80 @@
+/*
+ * drivers/base/power/invoke_runtime.c - Helper functions for device run-time PM
+ *
+ * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ * Copyright (c) 2010 Alan Stern <stern@rowland.harvard.edu>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/pm_runtime.h>
+
+/* The following functions are separated out from runtime.c so that they
+ * can be used even when CONFIG_PM_RUNTIME is disabled.
+ */
+
+/**
+ * dpm_invoke_runtime_idle - Invoke a device's runtime PM idle method(s)
+ * @dev: Device to handle.
+ */
+void dpm_invoke_runtime_idle(struct device *dev)
+{
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
+ dev->bus->pm->runtime_idle(dev);
+ } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
+ dev->type->pm->runtime_idle(dev);
+ } else if (dev->class && dev->class->pm
+ && dev->class->pm->runtime_idle) {
+ dev->class->pm->runtime_idle(dev);
+ }
+}
+
+/**
+ * dpm_invoke_runtime_suspend - Invoke a device's runtime PM suspend method(s)
+ * @dev: Device to handle.
+ */
+int dpm_invoke_runtime_suspend(struct device *dev)
+{
+ int retval;
+
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
+ retval = dev->bus->pm->runtime_suspend(dev);
+ dev->power.runtime_error = retval;
+ } else if (dev->type && dev->type->pm
+ && dev->type->pm->runtime_suspend) {
+ retval = dev->type->pm->runtime_suspend(dev);
+ dev->power.runtime_error = retval;
+ } else if (dev->class && dev->class->pm
+ && dev->class->pm->runtime_suspend) {
+ retval = dev->class->pm->runtime_suspend(dev);
+ dev->power.runtime_error = retval;
+ } else {
+ retval = -ENOSYS;
+ }
+ return retval;
+}
+
+/**
+ * dpm_invoke_runtime_resume - Invoke a device's runtime PM resume method(s)
+ * @dev: Device to handle.
+ */
+int dpm_invoke_runtime_resume(struct device *dev)
+{
+ int retval;
+
+ if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
+ retval = dev->bus->pm->runtime_resume(dev);
+ dev->power.runtime_error = retval;
+ } else if (dev->type && dev->type->pm
+ && dev->type->pm->runtime_resume) {
+ retval = dev->type->pm->runtime_resume(dev);
+ dev->power.runtime_error = retval;
+ } else if (dev->class && dev->class->pm
+ && dev->class->pm->runtime_resume) {
+ retval = dev->class->pm->runtime_resume(dev);
+ dev->power.runtime_error = retval;
+ } else {
+ retval = -ENOSYS;
+ }
+ return retval;
+}
Index: usb-2.6/Documentation/power/runtime_pm.txt
===================================================================
--- usb-2.6.orig/Documentation/power/runtime_pm.txt
+++ usb-2.6/Documentation/power/runtime_pm.txt
@@ -329,6 +329,11 @@ drivers/base/power/runtime.c and include
'power.runtime_error' is set or 'power.disable_depth' is greater than
zero)
+ bool pm_is_runtime_suspended(struct device *dev);
+ - returns 'true' if the device's run-time PM status is 'suspended'; the
+ status is constantly subject to change, hence this function should be
+ used only in contexts such as during a system sleep transition
+
It is safe to execute the following helper functions from interrupt context:
pm_request_idle()
@@ -342,6 +347,7 @@ pm_suspend_ignore_children()
pm_runtime_set_active()
pm_runtime_set_suspended()
pm_runtime_enable()
+pm_is_runtime_suspended()
5. Run-time PM Initialization, Device Probing and Removal
@@ -431,3 +437,21 @@ The PM core always increments the run-ti
->prepare() callback and decrements it after calling the ->complete() callback.
Hence disabling run-time PM temporarily like this will not cause any run-time
suspend callbacks to be lost.
+
+Subsystems may wish to conserve code space by using the same function as both a
+system suspend and run-time suspend callback, and similarly for system resume
+and run-time resume. The PM core provides two utility functions to help make
+this easier:
+
+ int dpm_use_runtime_suspend(struct device *dev);
+ - system suspend handler that invokes the ->runtime_suspend() callback for
+ this device if the device is not already run-time suspended
+
+ int dpm_use_runtime_resume(struct device *dev);
+ - system resume handler that invokes the ->runtime_resume() callback for
+ this device and sets the device's run-time PM status to 'active' if the
+ callback is successful
+
+These functions can be assigned to the ->suspend(), ->freeze(), ->poweroff(),
+->resume(), ->thaw(), or ->restore() callback pointers in the subsystem-level
+dev_pm_ops structures.
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-02-26 16:46 [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions Alan Stern @ 2010-02-26 21:24 ` Rafael J. Wysocki 2010-02-26 22:06 ` Alan Stern 0 siblings, 1 reply; 21+ messages in thread From: Rafael J. Wysocki @ 2010-02-26 21:24 UTC (permalink / raw) To: Alan Stern; +Cc: Linux-pm mailing list On Friday 26 February 2010, Alan Stern wrote: ... > Index: usb-2.6/drivers/base/power/power.h > =================================================================== > --- usb-2.6.orig/drivers/base/power/power.h > +++ usb-2.6/drivers/base/power/power.h > @@ -72,3 +72,14 @@ static inline void dpm_sysfs_remove(stru > } > > #endif > + > +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) CONFIG_PM_OPS can be used for that, it means exactly the above. > +/* > + * invoke_runtime.c > + */ > +extern void dpm_invoke_runtime_idle(struct device *dev); > +extern int dpm_invoke_runtime_suspend(struct device *dev); > +extern int dpm_invoke_runtime_resume(struct device *dev); > + > +#endif > Index: usb-2.6/drivers/base/power/Makefile > =================================================================== > --- usb-2.6.orig/drivers/base/power/Makefile > +++ usb-2.6/drivers/base/power/Makefile > @@ -1,6 +1,6 @@ > obj-$(CONFIG_PM) += sysfs.o > -obj-$(CONFIG_PM_SLEEP) += main.o > -obj-$(CONFIG_PM_RUNTIME) += runtime.o > +obj-$(CONFIG_PM_SLEEP) += main.o invoke_runtime.o > +obj-$(CONFIG_PM_RUNTIME) += runtime.o invoke_runtime.o And here I think. There seem to be a few more places where the comment applies. > obj-$(CONFIG_PM_TRACE_RTC) += trace.o > > ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG > Index: usb-2.6/drivers/base/power/main.c > =================================================================== > --- usb-2.6.orig/drivers/base/power/main.c > +++ usb-2.6/drivers/base/power/main.c > @@ -936,3 +936,51 @@ void __suspend_report_result(const char > printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret); > } > EXPORT_SYMBOL_GPL(__suspend_report_result); > + > +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) > + > +/* Convenience routines for drivers that want to use the same functions > + * for system suspend/resume and runtime suspend/resume: > + * Set driver->pm_ops->suspend = dpm_use_runtime_suspend and > + * driver->pm_ops->resume = dpm_use_runtime_resume. > + */ I have one problem with the design. Namely, dpm_invoke_runtime_*() can run a callback from another subsystem. Say you are a device class and you decide to use dpm_invoke_runtime_*(), but the device's bus type implements the runtime PM callbacks, so they will be run as device class suspend and resume callbacks. That doesn't look particularly clean to me. Rafael ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-02-26 21:24 ` Rafael J. Wysocki @ 2010-02-26 22:06 ` Alan Stern 2010-02-27 10:43 ` Mark Brown 0 siblings, 1 reply; 21+ messages in thread From: Alan Stern @ 2010-02-26 22:06 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: Linux-pm mailing list On Fri, 26 Feb 2010, Rafael J. Wysocki wrote: > I have one problem with the design. Namely, dpm_invoke_runtime_*() can > run a callback from another subsystem. Say you are a device class and you > decide to use dpm_invoke_runtime_*(), but the device's bus type implements > the runtime PM callbacks, so they will be run as device class suspend and > resume callbacks. That doesn't look particularly clean to me. That is a valid point. I suppose there could be separate bus-type, device-type, and device-class versions of these functions, but that seems like excessive complication with little real benefit. Mark and Kevin, do you have any thoughts on this? Alan Stern ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-02-26 22:06 ` Alan Stern @ 2010-02-27 10:43 ` Mark Brown 2010-02-27 22:50 ` Rafael J. Wysocki 0 siblings, 1 reply; 21+ messages in thread From: Mark Brown @ 2010-02-27 10:43 UTC (permalink / raw) To: Alan Stern; +Cc: Linux-pm mailing list On Fri, Feb 26, 2010 at 05:06:59PM -0500, Alan Stern wrote: > On Fri, 26 Feb 2010, Rafael J. Wysocki wrote: > > I have one problem with the design. Namely, dpm_invoke_runtime_*() can > > run a callback from another subsystem. Say you are a device class and you > > decide to use dpm_invoke_runtime_*(), but the device's bus type implements > > the runtime PM callbacks, so they will be run as device class suspend and > > resume callbacks. That doesn't look particularly clean to me. > That is a valid point. I suppose there could be separate bus-type, > device-type, and device-class versions of these functions, but that > seems like excessive complication with little real benefit. I do agree that it'd be good to avoid adding any further complexity here - the use case I have is devices that only really have one suspend type and don't want or need to know if it's a runtime, disk or memory suspend. > Mark and Kevin, do you have any thoughts on this? It seems to me that since people have to explicitly choose to invoke this behaviour any such cross calls shouldn't be an issue. There's a reasonable chance that class or bus callbacks are just straightforward pass throughs which don't actually add anything except moving the function from dev_pm_ops into the bus or class ops and changing the parameter to a more specific structure type. Having to decide which version of the functions to use wouldn't add anything for them. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-02-27 10:43 ` Mark Brown @ 2010-02-27 22:50 ` Rafael J. Wysocki 2010-03-01 13:31 ` Mark Brown ` (2 more replies) 0 siblings, 3 replies; 21+ messages in thread From: Rafael J. Wysocki @ 2010-02-27 22:50 UTC (permalink / raw) To: Mark Brown; +Cc: Linux-pm mailing list On Saturday 27 February 2010, Mark Brown wrote: > On Fri, Feb 26, 2010 at 05:06:59PM -0500, Alan Stern wrote: > > On Fri, 26 Feb 2010, Rafael J. Wysocki wrote: > > > > I have one problem with the design. Namely, dpm_invoke_runtime_*() can > > > run a callback from another subsystem. Say you are a device class and you > > > decide to use dpm_invoke_runtime_*(), but the device's bus type implements > > > the runtime PM callbacks, so they will be run as device class suspend and > > > resume callbacks. That doesn't look particularly clean to me. > > > That is a valid point. I suppose there could be separate bus-type, > > device-type, and device-class versions of these functions, but that > > seems like excessive complication with little real benefit. > > I do agree that it'd be good to avoid adding any further complexity here > - the use case I have is devices that only really have one suspend type > and don't want or need to know if it's a runtime, disk or memory suspend. What about the patch below, then (untested)? Use GENERIC_SUBSYS_PM_OPS for the subsystem and then UNIVERSAL_DEV_PM_OPS for drivers, possibly passing NULL as idle_fn. Rafael --- drivers/base/power/Makefile | 1 drivers/base/power/generic_ops.c | 119 +++++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 67 +++++++++++++++++++-- 3 files changed, 181 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/base/power/Makefile =================================================================== --- linux-2.6.orig/drivers/base/power/Makefile +++ linux-2.6/drivers/base/power/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_RUNTIME) += runtime.o +obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG Index: linux-2.6/drivers/base/power/generic_ops.c =================================================================== --- linux-2.6.orig/drivers/base/power/generic_ops.c +++ linux-2.6/drivers/base/power/generic_ops.c @@ -6,3 +6,122 @@ * This file is released under the GPLv2. */ +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#ifdef CONFIG_PM_RUNTIME +/** + * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. + * @dev: Device to handle. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_idle(), execute it and return the error code returned by it if + * nonzero. Otherwise, execute pm_runtime_suspend() for the device. + */ +int pm_generic_runtime_idle(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->runtime_idle) { + int ret = pm->runtime_idle(dev); + if (ret) + return ret; + } + + pm_runtime_suspend(dev); + return 0; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); + +/** + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. + * @dev: Device to suspend. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_suspend(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret = 0; + + if (pm && pm->runtime_suspend) + ret = pm->runtime_suspend(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); + +/** + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. + * @dev: Device to resume. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_resume(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret = 0; + + if (pm && pm->runtime_resume) + ret = pm->runtime_resume(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#define CONFIG_PM_SLEEP +/** + * pm_generic_suspend - Generic suspend callback for subsystems. + * @dev: Device to suspend. + * + * If the device has not been suspended at run time, execute the suspend + * callback provided by its driver, if defined, and return the error code + * returned by it. Otherwise, return zero. + */ +int pm_generic_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret = 0; + + if (dev->power.runtime_status == RPM_SUSPENDED) + return 0; + + if (pm && pm->suspend) + ret = pm->suspend(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_suspend); + +/** + * pm_generic_resume - Generic resume callback for subsystems. + * @dev: Device to resume. + * + * Execute the resume callback provided by the driver of @dev, if defined. + * If it returns 0, change the device's runtime PM status to 'active'. Return + * the error code returned by it. + */ +int pm_generic_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + if (!pm || !pm->resume) + return 0; + + ret = pm->resume(dev); + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_resume); +#endif /* CONFIG_PM_SLEEP */ Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/include/linux/pm.h @@ -215,18 +215,73 @@ struct dev_pm_ops { int (*runtime_idle)(struct device *dev); }; +#ifdef CONFIG_PM_SLEEP +#define 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 SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) +#endif + +#ifdef CONFIG_PM_RUNTIME +#define RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ + .runtime_suspend = suspend_fn, \ + .runtime_resume = resume_fn, \ + .runtime_idle = idle_fn, +#else +#define 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, \ +SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +} + +/* + * Use this for defining a set of PM operations to be used in all situations + * (system suspend, hibernation or runtime PM). + */ +#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ +const struct dev_pm_ops name = { \ +SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ +RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ +} + +#ifdef CONFIG_PM_SLEEP +#define GENERIC_SYSTEM_SLEEP_PM_OPS \ + .suspend = pm_generic_suspend, \ + .resume = pm_generic_resume, +#else +#define GENERIC_SYSTEM_SLEEP_PM_OPS + +#endif + +#ifdef CONFIG_PM_RUNTIME +#define GENERIC_RUNTIME_PM_OPS \ + .runtime_suspend = pm_generic_runtime_suspend, \ + .runtime_resume = pm_generic_runtime_resume, \ + .runtime_idle = pm_generic_runtime_idle, +#else +#define GENERIC_RUNTIME_PM_OPS +#endif + +/* + * Use this for subsystems (bus types, device types, device classes) that only + * need to invoke PM callbacks provided by device drivers supporting both the + * system sleep PM and runtime PM. + */ +#define GENERIC_SUBSYS_PM_OPS(name) \ +const struct dev_pm_ops name = { \ +GENERIC_SYSTEM_SLEEP_PM_OPS \ +GENERIC_RUNTIME_PM_OPS \ } /** ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-02-27 22:50 ` Rafael J. Wysocki @ 2010-03-01 13:31 ` Mark Brown 2010-03-01 18:40 ` Alan Stern 2010-03-01 22:25 ` Kevin Hilman 2 siblings, 0 replies; 21+ messages in thread From: Mark Brown @ 2010-03-01 13:31 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: Linux-pm mailing list On Sat, Feb 27, 2010 at 11:50:16PM +0100, Rafael J. Wysocki wrote: > What about the patch below, then (untested)? > Use GENERIC_SUBSYS_PM_OPS for the subsystem and then > UNIVERSAL_DEV_PM_OPS for drivers, possibly passing NULL as idle_fn. I've not tested but yes, this looks really helpful for my use cases. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-02-27 22:50 ` Rafael J. Wysocki 2010-03-01 13:31 ` Mark Brown @ 2010-03-01 18:40 ` Alan Stern 2010-03-01 22:06 ` Rafael J. Wysocki 2010-03-01 22:25 ` Kevin Hilman 2 siblings, 1 reply; 21+ messages in thread From: Alan Stern @ 2010-03-01 18:40 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: Linux-pm mailing list On Sat, 27 Feb 2010, Rafael J. Wysocki wrote: > What about the patch below, then (untested)? > > Use GENERIC_SUBSYS_PM_OPS for the subsystem and then > UNIVERSAL_DEV_PM_OPS for drivers, possibly passing NULL as idle_fn. > +#ifdef CONFIG_PM_SLEEP > +#define GENERIC_SYSTEM_SLEEP_PM_OPS \ > + .suspend = pm_generic_suspend, \ > + .resume = pm_generic_resume, > +#else > +#define GENERIC_SYSTEM_SLEEP_PM_OPS Wouldn't you want to have this work for hibernation as well as suspend? So the .freeze, .thaw, etc. members should be defined too. > +/* > + * Use this for subsystems (bus types, device types, device classes) that only > + * need to invoke PM callbacks provided by device drivers supporting both the > + * system sleep PM and runtime PM. > + */ > +#define GENERIC_SUBSYS_PM_OPS(name) \ > +const struct dev_pm_ops name = { \ > +GENERIC_SYSTEM_SLEEP_PM_OPS \ > +GENERIC_RUNTIME_PM_OPS \ > } There's no reason for this to have "name" as a parameter, since all instances of the structure will be identical. Instead you can put extern const struct dev_pm_ops generic_subsys_pm_ops; EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); in the header file and define the structure in generic_ops.c. Alan Stern ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-01 18:40 ` Alan Stern @ 2010-03-01 22:06 ` Rafael J. Wysocki 2010-03-02 16:12 ` Alan Stern 0 siblings, 1 reply; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-01 22:06 UTC (permalink / raw) To: Alan Stern; +Cc: Linux-pm mailing list On Monday 01 March 2010, Alan Stern wrote: > On Sat, 27 Feb 2010, Rafael J. Wysocki wrote: > > > What about the patch below, then (untested)? > > > > Use GENERIC_SUBSYS_PM_OPS for the subsystem and then > > UNIVERSAL_DEV_PM_OPS for drivers, possibly passing NULL as idle_fn. > > > > +#ifdef CONFIG_PM_SLEEP > > +#define GENERIC_SYSTEM_SLEEP_PM_OPS \ > > + .suspend = pm_generic_suspend, \ > > + .resume = pm_generic_resume, > > +#else > > +#define GENERIC_SYSTEM_SLEEP_PM_OPS > > Wouldn't you want to have this work for hibernation as well as suspend? > So the .freeze, .thaw, etc. members should be defined too. Right, thanks. > > +/* > > + * Use this for subsystems (bus types, device types, device classes) that only > > + * need to invoke PM callbacks provided by device drivers supporting both the > > + * system sleep PM and runtime PM. > > + */ > > +#define GENERIC_SUBSYS_PM_OPS(name) \ > > +const struct dev_pm_ops name = { \ > > +GENERIC_SYSTEM_SLEEP_PM_OPS \ > > +GENERIC_RUNTIME_PM_OPS \ > > } > > There's no reason for this to have "name" as a parameter, since all > instances of the structure will be identical. Instead you can put > > extern const struct dev_pm_ops generic_subsys_pm_ops; > EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); > > in the header file and define the structure in generic_ops.c. Right again, thanks a lot! Updated patch is appended. In the meantime I decided it would be better to return error code from pm_generic_runtime_[suspend|resume]() if the driver callback is not defined and I chose EINVAL (ie. shouldn't be called for a device whose driver has no corresponding runtime callback). Rafael --- drivers/base/power/Makefile | 1 drivers/base/power/generic_ops.c | 134 +++++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 54 +++++++++++++-- include/linux/pm_runtime.h | 6 + 4 files changed, 189 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/base/power/Makefile =================================================================== --- linux-2.6.orig/drivers/base/power/Makefile +++ linux-2.6/drivers/base/power/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_RUNTIME) += runtime.o +obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG Index: linux-2.6/drivers/base/power/generic_ops.c =================================================================== --- linux-2.6.orig/drivers/base/power/generic_ops.c +++ linux-2.6/drivers/base/power/generic_ops.c @@ -6,3 +6,137 @@ * This file is released under the GPLv2. */ +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#ifdef CONFIG_PM_RUNTIME +/** + * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. + * @dev: Device to handle. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_idle(), execute it and return the error code returned by it if + * nonzero. Otherwise, execute pm_runtime_suspend() for the device. + */ +int pm_generic_runtime_idle(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->runtime_idle) { + int ret = pm->runtime_idle(dev); + if (ret) + return ret; + } + + pm_runtime_suspend(dev); + return 0; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); + +/** + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. + * @dev: Device to suspend. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_suspend(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); + +/** + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. + * @dev: Device to resume. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_resume(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +/** + * pm_generic_suspend - Generic suspend callback for subsystems. + * @dev: Device to suspend. + * + * If the device has not been suspended at run time, execute the suspend + * callback provided by its driver, if defined, and return the error code + * returned by it. Otherwise, return zero. + */ +int pm_generic_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret = 0; + + if (pm_runtime_suspended(dev)) + return 0; + + if (pm && pm->suspend) + ret = pm->suspend(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_suspend); + +/** + * pm_generic_resume - Generic resume callback for subsystems. + * @dev: Device to resume. + * + * Execute the resume callback provided by the driver of @dev, if defined. + * If it returns 0, change the device's runtime PM status to 'active'. Return + * the error code returned by it. + */ +int pm_generic_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + if (!pm || !pm->resume) + return 0; + + ret = pm->resume(dev); + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_resume); +#endif /* CONFIG_PM_SLEEP */ + +struct dev_pm_ops generic_subsys_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_suspend, + .thaw = pm_generic_resume, + .poweroff = pm_generic_suspend, + .restore = pm_generic_resume, +#endif +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +}; +EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/include/linux/pm.h @@ -215,20 +215,62 @@ 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) \ } +#define SET_UNIVERSAL_PM_OPS(suspend_fn, resume_fn, idle_fn) \ + SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ + SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) + +/* + * Use this for defining a set of PM operations to be used in all situations + * (system suspend, hibernation or runtime PM). + */ +#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ +const struct dev_pm_ops name = { \ + SET_UNIVERSAL_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 * Index: linux-2.6/include/linux/pm_runtime.h =================================================================== --- linux-2.6.orig/include/linux/pm_runtime.h +++ linux-2.6/include/linux/pm_runtime.h @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s dev->power.run_wake = enable; } +static inline bool pm_runtime_suspended(struct device *dev) +{ + return dev->power.runtime_status == RPM_SUSPENDED; +} + #else /* !CONFIG_PM_RUNTIME */ static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } @@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresu static inline void pm_runtime_put_noidle(struct device *dev) {} static inline bool device_run_wake(struct device *dev) { return false; } static inline void device_set_run_wake(struct device *dev, bool enable) {} +static inline bool pm_runtime_suspended(struct device *dev) { return false; } #endif /* !CONFIG_PM_RUNTIME */ ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-01 22:06 ` Rafael J. Wysocki @ 2010-03-02 16:12 ` Alan Stern 2010-03-02 22:51 ` Rafael J. Wysocki 0 siblings, 1 reply; 21+ messages in thread From: Alan Stern @ 2010-03-02 16:12 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: Linux-pm mailing list On Mon, 1 Mar 2010, Rafael J. Wysocki wrote: > Updated patch is appended. In the meantime I decided it would be better > to return error code from pm_generic_runtime_[suspend|resume]() if the driver > callback is not defined and I chose EINVAL (ie. shouldn't be called for a > device whose driver has no corresponding runtime callback). Okay. > Index: linux-2.6/drivers/base/power/generic_ops.c > =================================================================== > --- linux-2.6.orig/drivers/base/power/generic_ops.c > +++ linux-2.6/drivers/base/power/generic_ops.c > @@ -6,3 +6,137 @@ > * This file is released under the GPLv2. > */ > > +#include <linux/pm.h> > +#include <linux/pm_runtime.h> > + There's something strange about this patch -- it doesn't start at the beginning. Do you already have an 8-line file named generic_ops.c? I don't. > +struct dev_pm_ops generic_subsys_pm_ops = { > +#ifdef CONFIG_PM_SLEEP > + .suspend = pm_generic_suspend, > + .resume = pm_generic_resume, > + .freeze = pm_generic_suspend, > + .thaw = pm_generic_resume, > + .poweroff = pm_generic_suspend, > + .restore = pm_generic_resume, > +#endif > +#ifdef CONFIG_PM_RUNTIME > + .runtime_suspend = pm_generic_runtime_suspend, > + .runtime_resume = pm_generic_runtime_resume, > + .runtime_idle = pm_generic_runtime_idle, > +#endif > +}; > +EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); Heh, you could use the UNIVERSAL_DEV_PM_OPS macro here. > Index: linux-2.6/include/linux/pm.h > =================================================================== > --- linux-2.6.orig/include/linux/pm.h > +++ linux-2.6/include/linux/pm.h > #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) \ > } > > +#define SET_UNIVERSAL_PM_OPS(suspend_fn, resume_fn, idle_fn) \ > + SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ > + SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) > + > +/* > + * Use this for defining a set of PM operations to be used in all situations > + * (system suspend, hibernation or runtime PM). > + */ > +#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ > +const struct dev_pm_ops name = { \ > + SET_UNIVERSAL_PM_OPS(suspend_fn, resume_fn, idle_fn) \ > +} Personally, I would avoid defining SET_UNIVERSAL_PM_OPS (it doesn't seem likely to be used anywhere else) and just put SET_SYSTEM_SLEEP_PM_OPS followed by SET_RUNTIME_PM_OPS here. > Index: linux-2.6/include/linux/pm_runtime.h > =================================================================== > --- linux-2.6.orig/include/linux/pm_runtime.h > +++ linux-2.6/include/linux/pm_runtime.h > @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s > dev->power.run_wake = enable; > } > > +static inline bool pm_runtime_suspended(struct device *dev) > +{ > + return dev->power.runtime_status == RPM_SUSPENDED; > +} > + > #else /* !CONFIG_PM_RUNTIME */ > > static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } > @@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresu > static inline void pm_runtime_put_noidle(struct device *dev) {} > static inline bool device_run_wake(struct device *dev) { return false; } > static inline void device_set_run_wake(struct device *dev, bool enable) {} > +static inline bool pm_runtime_suspended(struct device *dev) { return false; } > > #endif /* !CONFIG_PM_RUNTIME */ The documentation should be updated as well. You can use some of the text from my patch submission if you want. Alan Stern ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-02 16:12 ` Alan Stern @ 2010-03-02 22:51 ` Rafael J. Wysocki 2010-03-03 16:46 ` Alan Stern 0 siblings, 1 reply; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-02 22:51 UTC (permalink / raw) To: Alan Stern; +Cc: Linux-pm mailing list On Tuesday 02 March 2010, Alan Stern wrote: > On Mon, 1 Mar 2010, Rafael J. Wysocki wrote: > > > Updated patch is appended. In the meantime I decided it would be better > > to return error code from pm_generic_runtime_[suspend|resume]() if the driver > > callback is not defined and I chose EINVAL (ie. shouldn't be called for a > > device whose driver has no corresponding runtime callback). > > Okay. > > > Index: linux-2.6/drivers/base/power/generic_ops.c > > =================================================================== > > --- linux-2.6.orig/drivers/base/power/generic_ops.c > > +++ linux-2.6/drivers/base/power/generic_ops.c > > @@ -6,3 +6,137 @@ > > * This file is released under the GPLv2. > > */ > > > > +#include <linux/pm.h> > > +#include <linux/pm_runtime.h> > > + > > There's something strange about this patch -- it doesn't start at the > beginning. Do you already have an 8-line file named generic_ops.c? I > don't. Unfortunately I had one, by mistake. > > +struct dev_pm_ops generic_subsys_pm_ops = { > > +#ifdef CONFIG_PM_SLEEP > > + .suspend = pm_generic_suspend, > > + .resume = pm_generic_resume, > > + .freeze = pm_generic_suspend, > > + .thaw = pm_generic_resume, > > + .poweroff = pm_generic_suspend, > > + .restore = pm_generic_resume, > > +#endif > > +#ifdef CONFIG_PM_RUNTIME > > + .runtime_suspend = pm_generic_runtime_suspend, > > + .runtime_resume = pm_generic_runtime_resume, > > + .runtime_idle = pm_generic_runtime_idle, > > +#endif > > +}; > > +EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); > > Heh, you could use the UNIVERSAL_DEV_PM_OPS macro here. Well, I would, if I didn't make a mistake. Namely, I think at the subsystem level we need to define all of the suspend, freeze, poweroff, resume, thaw, restore callbacks, because, for example, thaw and resume should behave differently (see the appended patch). Also, IMO they should work with drivers that actually define different freeze/thaw and suspend/resume, in general. > > Index: linux-2.6/include/linux/pm.h > > =================================================================== > > --- linux-2.6.orig/include/linux/pm.h > > +++ linux-2.6/include/linux/pm.h > > > #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) \ > > } > > > > +#define SET_UNIVERSAL_PM_OPS(suspend_fn, resume_fn, idle_fn) \ > > + SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ > > + SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) > > + > > +/* > > + * Use this for defining a set of PM operations to be used in all situations > > + * (system suspend, hibernation or runtime PM). > > + */ > > +#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ > > +const struct dev_pm_ops name = { \ > > + SET_UNIVERSAL_PM_OPS(suspend_fn, resume_fn, idle_fn) \ > > +} > > Personally, I would avoid defining SET_UNIVERSAL_PM_OPS (it doesn't > seem likely to be used anywhere else) and just put > SET_SYSTEM_SLEEP_PM_OPS followed by SET_RUNTIME_PM_OPS here. OK > > Index: linux-2.6/include/linux/pm_runtime.h > > =================================================================== > > --- linux-2.6.orig/include/linux/pm_runtime.h > > +++ linux-2.6/include/linux/pm_runtime.h > > @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s > > dev->power.run_wake = enable; > > } > > > > +static inline bool pm_runtime_suspended(struct device *dev) > > +{ > > + return dev->power.runtime_status == RPM_SUSPENDED; > > +} > > + > > #else /* !CONFIG_PM_RUNTIME */ > > > > static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } > > @@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresu > > static inline void pm_runtime_put_noidle(struct device *dev) {} > > static inline bool device_run_wake(struct device *dev) { return false; } > > static inline void device_set_run_wake(struct device *dev, bool enable) {} > > +static inline bool pm_runtime_suspended(struct device *dev) { return false; } > > > > #endif /* !CONFIG_PM_RUNTIME */ > > The documentation should be updated as well. You can use some of the > text from my patch submission if you want. Thanks, I added it to the patch (below). Rafael --- Documentation/power/runtime_pm.txt | 60 +++++++++ drivers/base/power/Makefile | 1 drivers/base/power/generic_ops.c | 233 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 51 +++++++- include/linux/pm_runtime.h | 6 5 files changed, 345 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/base/power/generic_ops.c =================================================================== --- /dev/null +++ linux-2.6/drivers/base/power/generic_ops.c @@ -0,0 +1,233 @@ +/* + * drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems + * + * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#ifdef CONFIG_PM_RUNTIME +/** + * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. + * @dev: Device to handle. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_idle(), execute it and return the error code returned by it if + * nonzero. Otherwise, execute pm_runtime_suspend() for the device. + */ +int pm_generic_runtime_idle(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->runtime_idle) { + int ret = pm->runtime_idle(dev); + if (ret) + return ret; + } + + pm_runtime_suspend(dev); + return 0; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); + +/** + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. + * @dev: Device to suspend. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_suspend(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); + +/** + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. + * @dev: Device to resume. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_resume(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +/** + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * If the device has not been suspended at run time, execute the + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and + * return the error code returned by it. Otherwise, return zero. + */ +static int __pm_generic_call(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + + if (!pm || pm_runtime_suspended(dev)) + return 0; + + switch (event) { + case PM_EVENT_SUSPEND: + callback = pm->suspend; + break; + case PM_EVENT_FREEZE: + callback = pm->freeze; + break; + case PM_EVENT_HIBERNATE: + callback = pm->poweroff; + break; + case PM_EVENT_THAW: + callback = pm->thaw; + break; + default: + callback = NULL; + break; + } + + return callback ? callback(dev) : 0; +} + +/** + * pm_generic_suspend - Generic suspend callback for subsystems. + * @dev: Device to suspend. + */ +int pm_generic_suspend(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_SUSPEND); +} +EXPORT_SYMBOL_GPL(pm_generic_suspend); + +/** + * pm_generic_freeze - Generic freeze callback for subsystems. + * @dev: Device to freeze. + */ +int pm_generic_freeze(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_FREEZE); +} +EXPORT_SYMBOL_GPL(pm_generic_freeze); + +/** + * pm_generic_poweroff - Generic poweroff callback for subsystems. + * @dev: Device to handle. + */ +int pm_generic_poweroff(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_HIBERNATE); +} +EXPORT_SYMBOL_GPL(pm_generic_poweroff); + +/** + * pm_generic_thaw - Generic thaw callback for subsystems. + * @dev: Device to thaw. + */ +int pm_generic_thaw(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_THAW); +} +EXPORT_SYMBOL_GPL(pm_generic_thaw); + +/** + * __pm_generic_resume - Generic resume/restore callback for subsystems. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * Execute the resume/resotre callback provided by the driver of @dev, if + * defined. If it returns 0, change the device's runtime PM status to 'active'. + * Return the error code returned by it. + */ +static int __pm_generic_resume(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + int ret; + + if (!pm) + return 0; + + switch (event) { + case PM_EVENT_RESUME: + callback = pm->resume; + break; + case PM_EVENT_RESTORE: + callback = pm->restore; + break; + default: + callback = NULL; + break; + } + + if (!callback) + return 0; + + ret = callback(dev); + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; +} + +/** + * pm_generic_resume - Generic resume callback for subsystems. + * @dev: Device to resume. + */ +int pm_generic_resume(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESUME); +} +EXPORT_SYMBOL_GPL(pm_generic_resume); + +/** + * pm_generic_restore - Generic restore callback for subsystems. + * @dev: Device to restore. + */ +int pm_generic_restore(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESTORE); +} +EXPORT_SYMBOL_GPL(pm_generic_restore); +#endif /* CONFIG_PM_SLEEP */ + +struct dev_pm_ops generic_subsys_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, +#endif +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +}; +EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); Index: linux-2.6/drivers/base/power/Makefile =================================================================== --- linux-2.6.orig/drivers/base/power/Makefile +++ linux-2.6/drivers/base/power/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_RUNTIME) += runtime.o +obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/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 * Index: linux-2.6/include/linux/pm_runtime.h =================================================================== --- linux-2.6.orig/include/linux/pm_runtime.h +++ linux-2.6/include/linux/pm_runtime.h @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s dev->power.run_wake = enable; } +static inline bool pm_runtime_suspended(struct device *dev) +{ + return dev->power.runtime_status == RPM_SUSPENDED; +} + #else /* !CONFIG_PM_RUNTIME */ static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } @@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresu static inline void pm_runtime_put_noidle(struct device *dev) {} static inline bool device_run_wake(struct device *dev) { return false; } static inline void device_set_run_wake(struct device *dev, bool enable) {} +static inline bool pm_runtime_suspended(struct device *dev) { return false; } #endif /* !CONFIG_PM_RUNTIME */ Index: linux-2.6/Documentation/power/runtime_pm.txt =================================================================== --- linux-2.6.orig/Documentation/power/runtime_pm.txt +++ linux-2.6/Documentation/power/runtime_pm.txt @@ -459,3 +459,63 @@ The PM core always increments the run-ti ->prepare() callback and decrements it after calling the ->complete() callback. Hence disabling run-time PM temporarily like this will not cause any run-time suspend callbacks to be lost. + +7. Generic subsystem callbacks + +Subsystems may wish to conserve code space by using the set of generic power +management callbacks provided by the PM core, defined in +driver/base/power/generic_ops.c: + + int pm_generic_runtime_idle(struct device *dev); + - invoke the ->runtime_idle() callback provided by the driver of this + device, if defined, and execute pm_runtime_suspend() for it + + int pm_generic_runtime_suspend(struct device *dev); + - invoke the ->runtime_suspend() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_runtime_resume(struct device *dev); + - invoke the ->runtime_resume() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_suspend(struct device *dev); + - if the device has not been suspended at run time, invoke the ->suspend() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_resume(struct device *dev); + - invoke the ->resume() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + + int pm_generic_freeze(struct device *dev); + - if the device has not been suspended at run time, invoke the ->freeze() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_thaw(struct device *dev); + - if the device has not been suspended at run time, invoke the ->thaw() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_poweroff(struct device *dev); + - if the device has not been suspended at run time, invoke the ->poweroff() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_restore(struct device *dev); + - invoke the ->restore() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + +These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), +->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(), +or ->restore() callback pointers in the subsystem-level dev_pm_ops structures. + +If a subsystem wishes to use all of them at the same time, it can simply assign +the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its +dev_pm_ops structure pointer. + +Device drivers that wish to use the same function as a system suspend, freeze, +poweroff and run-time suspend callback, and similarly for system resume, thaw, +restore, and run-time resume, can achieve this with the help of the +UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h, possibly passing NULL +as the last argument of it. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-02 22:51 ` Rafael J. Wysocki @ 2010-03-03 16:46 ` Alan Stern 2010-03-03 21:33 ` Rafael J. Wysocki 0 siblings, 1 reply; 21+ messages in thread From: Alan Stern @ 2010-03-03 16:46 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: Linux-pm mailing list On Tue, 2 Mar 2010, Rafael J. Wysocki wrote: > +/** > + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. > + * @dev: Device to handle. > + * @event: PM transition of the system under way. > + * > + * If the device has not been suspended at run time, execute the > + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and > + * return the error code returned by it. Otherwise, return zero. > + */ > +static int __pm_generic_call(struct device *dev, int event) > +{ > + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; > + int (*callback)(struct device *); > + > + if (!pm || pm_runtime_suspended(dev)) > + return 0; > + > + switch (event) { > + case PM_EVENT_SUSPEND: > + callback = pm->suspend; > + break; > + case PM_EVENT_FREEZE: > + callback = pm->freeze; > + break; > + case PM_EVENT_HIBERNATE: > + callback = pm->poweroff; > + break; > + case PM_EVENT_THAW: > + callback = pm->thaw; > + break; > + default: > + callback = NULL; > + break; > + } > + > + return callback ? callback(dev) : 0; > +} Are you sure you want to avoid calling pm->thaw if the device is runtime-suspended? Maybe it would be better to treat thaw like resume or restore. > --- linux-2.6.orig/include/linux/pm_runtime.h > +++ linux-2.6/include/linux/pm_runtime.h > @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s > dev->power.run_wake = enable; > } > > +static inline bool pm_runtime_suspended(struct device *dev) > +{ > + return dev->power.runtime_status == RPM_SUSPENDED; > +} > + You didn't add this to the documentation file. Alan Stern ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-03 16:46 ` Alan Stern @ 2010-03-03 21:33 ` Rafael J. Wysocki 2010-03-04 0:56 ` Rafael J. Wysocki 0 siblings, 1 reply; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-03 21:33 UTC (permalink / raw) To: Alan Stern; +Cc: Linux-pm mailing list On Wednesday 03 March 2010, Alan Stern wrote: > On Tue, 2 Mar 2010, Rafael J. Wysocki wrote: > > > +/** > > + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. > > + * @dev: Device to handle. > > + * @event: PM transition of the system under way. > > + * > > + * If the device has not been suspended at run time, execute the > > + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and > > + * return the error code returned by it. Otherwise, return zero. > > + */ > > +static int __pm_generic_call(struct device *dev, int event) > > +{ > > + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; > > + int (*callback)(struct device *); > > + > > + if (!pm || pm_runtime_suspended(dev)) > > + return 0; > > + > > + switch (event) { > > + case PM_EVENT_SUSPEND: > > + callback = pm->suspend; > > + break; > > + case PM_EVENT_FREEZE: > > + callback = pm->freeze; > > + break; > > + case PM_EVENT_HIBERNATE: > > + callback = pm->poweroff; > > + break; > > + case PM_EVENT_THAW: > > + callback = pm->thaw; > > + break; > > + default: > > + callback = NULL; > > + break; > > + } > > + > > + return callback ? callback(dev) : 0; > > +} > > Are you sure you want to avoid calling pm->thaw if the device is > runtime-suspended? Maybe it would be better to treat thaw like resume > or restore. In .freeze() we check if the device is runtime suspended and skip the driver's .freeze() in that case, so the device is still suspended. I don't think .thaw() should call the driver's .thaw() in that case and change the runtime suspended status (that won't serve any practical purpose IMO). > > --- linux-2.6.orig/include/linux/pm_runtime.h > > +++ linux-2.6/include/linux/pm_runtime.h > > @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s > > dev->power.run_wake = enable; > > } > > > > +static inline bool pm_runtime_suspended(struct device *dev) > > +{ > > + return dev->power.runtime_status == RPM_SUSPENDED; > > +} > > + > > You didn't add this to the documentation file. Yes, I realized that after sending the patch, sorry. Rafael ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-03 21:33 ` Rafael J. Wysocki @ 2010-03-04 0:56 ` Rafael J. Wysocki 0 siblings, 0 replies; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-04 0:56 UTC (permalink / raw) To: Alan Stern; +Cc: linux-pm, LKML On Wednesday 03 March 2010, Rafael J. Wysocki wrote: > On Wednesday 03 March 2010, Alan Stern wrote: > > On Tue, 2 Mar 2010, Rafael J. Wysocki wrote: ... > > > > You didn't add this to the documentation file. Added that and a changelog. Updated patch is appended. Rafael --- From: Rafael J. Wysocki <rjw@sisk.pl> 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 <rjw@sisk.pl> --- Documentation/power/runtime_pm.txt | 64 ++++++++++ drivers/base/power/Makefile | 1 drivers/base/power/generic_ops.c | 233 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 51 +++++++- include/linux/pm_runtime.h | 6 5 files changed, 349 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/base/power/generic_ops.c =================================================================== --- /dev/null +++ linux-2.6/drivers/base/power/generic_ops.c @@ -0,0 +1,233 @@ +/* + * drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems + * + * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#ifdef CONFIG_PM_RUNTIME +/** + * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. + * @dev: Device to handle. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_idle(), execute it and return the error code returned by it if + * nonzero. Otherwise, execute pm_runtime_suspend() for the device. + */ +int pm_generic_runtime_idle(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->runtime_idle) { + int ret = pm->runtime_idle(dev); + if (ret) + return ret; + } + + pm_runtime_suspend(dev); + return 0; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); + +/** + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. + * @dev: Device to suspend. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_suspend(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); + +/** + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. + * @dev: Device to resume. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_resume(), execute it and return the error code returned by it. + * Otherwise, return zero. + */ +int pm_generic_runtime_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +/** + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * If the device has not been suspended at run time, execute the + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and + * return the error code returned by it. Otherwise, return zero. + */ +static int __pm_generic_call(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + + if (!pm || pm_runtime_suspended(dev)) + return 0; + + switch (event) { + case PM_EVENT_SUSPEND: + callback = pm->suspend; + break; + case PM_EVENT_FREEZE: + callback = pm->freeze; + break; + case PM_EVENT_HIBERNATE: + callback = pm->poweroff; + break; + case PM_EVENT_THAW: + callback = pm->thaw; + break; + default: + callback = NULL; + break; + } + + return callback ? callback(dev) : 0; +} + +/** + * pm_generic_suspend - Generic suspend callback for subsystems. + * @dev: Device to suspend. + */ +int pm_generic_suspend(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_SUSPEND); +} +EXPORT_SYMBOL_GPL(pm_generic_suspend); + +/** + * pm_generic_freeze - Generic freeze callback for subsystems. + * @dev: Device to freeze. + */ +int pm_generic_freeze(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_FREEZE); +} +EXPORT_SYMBOL_GPL(pm_generic_freeze); + +/** + * pm_generic_poweroff - Generic poweroff callback for subsystems. + * @dev: Device to handle. + */ +int pm_generic_poweroff(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_HIBERNATE); +} +EXPORT_SYMBOL_GPL(pm_generic_poweroff); + +/** + * pm_generic_thaw - Generic thaw callback for subsystems. + * @dev: Device to thaw. + */ +int pm_generic_thaw(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_THAW); +} +EXPORT_SYMBOL_GPL(pm_generic_thaw); + +/** + * __pm_generic_resume - Generic resume/restore callback for subsystems. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * Execute the resume/resotre callback provided by the driver of @dev, if + * defined. If it returns 0, change the device's runtime PM status to 'active'. + * Return the error code returned by it. + */ +static int __pm_generic_resume(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + int ret; + + if (!pm) + return 0; + + switch (event) { + case PM_EVENT_RESUME: + callback = pm->resume; + break; + case PM_EVENT_RESTORE: + callback = pm->restore; + break; + default: + callback = NULL; + break; + } + + if (!callback) + return 0; + + ret = callback(dev); + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; +} + +/** + * pm_generic_resume - Generic resume callback for subsystems. + * @dev: Device to resume. + */ +int pm_generic_resume(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESUME); +} +EXPORT_SYMBOL_GPL(pm_generic_resume); + +/** + * pm_generic_restore - Generic restore callback for subsystems. + * @dev: Device to restore. + */ +int pm_generic_restore(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESTORE); +} +EXPORT_SYMBOL_GPL(pm_generic_restore); +#endif /* CONFIG_PM_SLEEP */ + +struct dev_pm_ops generic_subsys_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, +#endif +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +}; +EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); Index: linux-2.6/drivers/base/power/Makefile =================================================================== --- linux-2.6.orig/drivers/base/power/Makefile +++ linux-2.6/drivers/base/power/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_RUNTIME) += runtime.o +obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/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 * Index: linux-2.6/include/linux/pm_runtime.h =================================================================== --- linux-2.6.orig/include/linux/pm_runtime.h +++ linux-2.6/include/linux/pm_runtime.h @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s dev->power.run_wake = enable; } +static inline bool pm_runtime_suspended(struct device *dev) +{ + return dev->power.runtime_status == RPM_SUSPENDED; +} + #else /* !CONFIG_PM_RUNTIME */ static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } @@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresu static inline void pm_runtime_put_noidle(struct device *dev) {} static inline bool device_run_wake(struct device *dev) { return false; } static inline void device_set_run_wake(struct device *dev, bool enable) {} +static inline bool pm_runtime_suspended(struct device *dev) { return false; } #endif /* !CONFIG_PM_RUNTIME */ Index: linux-2.6/Documentation/power/runtime_pm.txt =================================================================== --- linux-2.6.orig/Documentation/power/runtime_pm.txt +++ linux-2.6/Documentation/power/runtime_pm.txt @@ -335,6 +335,10 @@ drivers/base/power/runtime.c and include 'power.runtime_error' is set or 'power.disable_depth' is greater than zero) + bool pm_runtime_suspended(struct device *dev); + - return true if the devices runtime PM status is 'suspended' or false + otherwise + void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to @@ -459,3 +463,63 @@ The PM core always increments the run-ti ->prepare() callback and decrements it after calling the ->complete() callback. Hence disabling run-time PM temporarily like this will not cause any run-time suspend callbacks to be lost. + +7. Generic subsystem callbacks + +Subsystems may wish to conserve code space by using the set of generic power +management callbacks provided by the PM core, defined in +driver/base/power/generic_ops.c: + + int pm_generic_runtime_idle(struct device *dev); + - invoke the ->runtime_idle() callback provided by the driver of this + device, if defined, and execute pm_runtime_suspend() for it + + int pm_generic_runtime_suspend(struct device *dev); + - invoke the ->runtime_suspend() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_runtime_resume(struct device *dev); + - invoke the ->runtime_resume() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_suspend(struct device *dev); + - if the device has not been suspended at run time, invoke the ->suspend() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_resume(struct device *dev); + - invoke the ->resume() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + + int pm_generic_freeze(struct device *dev); + - if the device has not been suspended at run time, invoke the ->freeze() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_thaw(struct device *dev); + - if the device has not been suspended at run time, invoke the ->thaw() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_poweroff(struct device *dev); + - if the device has not been suspended at run time, invoke the ->poweroff() + callback provided by its driver and return the result returned by it, or + return 0 if not defined + + int pm_generic_restore(struct device *dev); + - invoke the ->restore() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + +These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), +->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(), +or ->restore() callback pointers in the subsystem-level dev_pm_ops structures. + +If a subsystem wishes to use all of them at the same time, it can simply assign +the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its +dev_pm_ops structure pointer. + +Device drivers that wish to use the same function as a system suspend, freeze, +poweroff and run-time suspend callback, and similarly for system resume, thaw, +restore, and run-time resume, can achieve this with the help of the +UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h, possibly passing NULL +as the last argument of it. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-02-27 22:50 ` Rafael J. Wysocki 2010-03-01 13:31 ` Mark Brown 2010-03-01 18:40 ` Alan Stern @ 2010-03-01 22:25 ` Kevin Hilman 2010-03-02 0:12 ` Rafael J. Wysocki 2 siblings, 1 reply; 21+ messages in thread From: Kevin Hilman @ 2010-03-01 22:25 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: Linux-pm mailing list "Rafael J. Wysocki" <rjw@sisk.pl> writes: > On Saturday 27 February 2010, Mark Brown wrote: >> On Fri, Feb 26, 2010 at 05:06:59PM -0500, Alan Stern wrote: >> > On Fri, 26 Feb 2010, Rafael J. Wysocki wrote: >> >> > > I have one problem with the design. Namely, dpm_invoke_runtime_*() can >> > > run a callback from another subsystem. Say you are a device class and you >> > > decide to use dpm_invoke_runtime_*(), but the device's bus type implements >> > > the runtime PM callbacks, so they will be run as device class suspend and >> > > resume callbacks. That doesn't look particularly clean to me. >> >> > That is a valid point. I suppose there could be separate bus-type, >> > device-type, and device-class versions of these functions, but that >> > seems like excessive complication with little real benefit. >> >> I do agree that it'd be good to avoid adding any further complexity here >> - the use case I have is devices that only really have one suspend type >> and don't want or need to know if it's a runtime, disk or memory suspend. > > What about the patch below, then (untested)? > > Use GENERIC_SUBSYS_PM_OPS for the subsystem and then > UNIVERSAL_DEV_PM_OPS for drivers, possibly passing NULL as idle_fn. This looks good to me for what I'm tinkering with too, but have not tested it. One thing missing from the orignal patch is a publicly availble version of pm_is_runtime_suspended(). I found this useful in at least one driver where I needed a slightly different suspend hook from he runtime hook. Kevin > > --- > drivers/base/power/Makefile | 1 > drivers/base/power/generic_ops.c | 119 +++++++++++++++++++++++++++++++++++++++ > include/linux/pm.h | 67 +++++++++++++++++++-- > 3 files changed, 181 insertions(+), 6 deletions(-) > > Index: linux-2.6/drivers/base/power/Makefile > =================================================================== > --- linux-2.6.orig/drivers/base/power/Makefile > +++ linux-2.6/drivers/base/power/Makefile > @@ -1,6 +1,7 @@ > obj-$(CONFIG_PM) += sysfs.o > obj-$(CONFIG_PM_SLEEP) += main.o > obj-$(CONFIG_PM_RUNTIME) += runtime.o > +obj-$(CONFIG_PM_OPS) += generic_ops.o > obj-$(CONFIG_PM_TRACE_RTC) += trace.o > > ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG > Index: linux-2.6/drivers/base/power/generic_ops.c > =================================================================== > --- linux-2.6.orig/drivers/base/power/generic_ops.c > +++ linux-2.6/drivers/base/power/generic_ops.c > @@ -6,3 +6,122 @@ > * This file is released under the GPLv2. > */ > > +#include <linux/pm.h> > +#include <linux/pm_runtime.h> > + > +#ifdef CONFIG_PM_RUNTIME > +/** > + * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. > + * @dev: Device to handle. > + * > + * If PM operations are defined for the driver of @dev and they include > + * ->runtime_idle(), execute it and return the error code returned by it if > + * nonzero. Otherwise, execute pm_runtime_suspend() for the device. > + */ > +int pm_generic_runtime_idle(struct device *dev) > +{ > + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; > + > + if (pm && pm->runtime_idle) { > + int ret = pm->runtime_idle(dev); > + if (ret) > + return ret; > + } > + > + pm_runtime_suspend(dev); > + return 0; > +} > +EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); > + > +/** > + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. > + * @dev: Device to suspend. > + * > + * If PM operations are defined for the driver of @dev and they include > + * ->runtime_suspend(), execute it and return the error code returned by it. > + * Otherwise, return zero. > + */ > +int pm_generic_runtime_suspend(struct device *dev) > +{ > + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; > + int ret = 0; > + > + if (pm && pm->runtime_suspend) > + ret = pm->runtime_suspend(dev); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); > + > +/** > + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. > + * @dev: Device to resume. > + * > + * If PM operations are defined for the driver of @dev and they include > + * ->runtime_resume(), execute it and return the error code returned by it. > + * Otherwise, return zero. > + */ > +int pm_generic_runtime_resume(struct device *dev) > +{ > + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; > + int ret = 0; > + > + if (pm && pm->runtime_resume) > + ret = pm->runtime_resume(dev); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); > +#endif /* CONFIG_PM_RUNTIME */ > + > +#define CONFIG_PM_SLEEP > +/** > + * pm_generic_suspend - Generic suspend callback for subsystems. > + * @dev: Device to suspend. > + * > + * If the device has not been suspended at run time, execute the suspend > + * callback provided by its driver, if defined, and return the error code > + * returned by it. Otherwise, return zero. > + */ > +int pm_generic_suspend(struct device *dev) > +{ > + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; > + int ret = 0; > + > + if (dev->power.runtime_status == RPM_SUSPENDED) > + return 0; > + > + if (pm && pm->suspend) > + ret = pm->suspend(dev); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pm_generic_suspend); > + > +/** > + * pm_generic_resume - Generic resume callback for subsystems. > + * @dev: Device to resume. > + * > + * Execute the resume callback provided by the driver of @dev, if defined. > + * If it returns 0, change the device's runtime PM status to 'active'. Return > + * the error code returned by it. > + */ > +int pm_generic_resume(struct device *dev) > +{ > + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; > + int ret; > + > + if (!pm || !pm->resume) > + return 0; > + > + ret = pm->resume(dev); > + if (!ret) { > + pm_runtime_disable(dev); > + pm_runtime_set_active(dev); > + pm_runtime_enable(dev); > + } > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pm_generic_resume); > +#endif /* CONFIG_PM_SLEEP */ > Index: linux-2.6/include/linux/pm.h > =================================================================== > --- linux-2.6.orig/include/linux/pm.h > +++ linux-2.6/include/linux/pm.h > @@ -215,18 +215,73 @@ struct dev_pm_ops { > int (*runtime_idle)(struct device *dev); > }; > > +#ifdef CONFIG_PM_SLEEP > +#define 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 SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) > +#endif > + > +#ifdef CONFIG_PM_RUNTIME > +#define RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ > + .runtime_suspend = suspend_fn, \ > + .runtime_resume = resume_fn, \ > + .runtime_idle = idle_fn, > +#else > +#define 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, \ > +SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ > +} > + > +/* > + * Use this for defining a set of PM operations to be used in all situations > + * (system suspend, hibernation or runtime PM). > + */ > +#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ > +const struct dev_pm_ops name = { \ > +SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ > +RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ > +} > + > +#ifdef CONFIG_PM_SLEEP > +#define GENERIC_SYSTEM_SLEEP_PM_OPS \ > + .suspend = pm_generic_suspend, \ > + .resume = pm_generic_resume, > +#else > +#define GENERIC_SYSTEM_SLEEP_PM_OPS > + > +#endif > + > +#ifdef CONFIG_PM_RUNTIME > +#define GENERIC_RUNTIME_PM_OPS \ > + .runtime_suspend = pm_generic_runtime_suspend, \ > + .runtime_resume = pm_generic_runtime_resume, \ > + .runtime_idle = pm_generic_runtime_idle, > +#else > +#define GENERIC_RUNTIME_PM_OPS > +#endif > + > +/* > + * Use this for subsystems (bus types, device types, device classes) that only > + * need to invoke PM callbacks provided by device drivers supporting both the > + * system sleep PM and runtime PM. > + */ > +#define GENERIC_SUBSYS_PM_OPS(name) \ > +const struct dev_pm_ops name = { \ > +GENERIC_SYSTEM_SLEEP_PM_OPS \ > +GENERIC_RUNTIME_PM_OPS \ > } > > /** ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-01 22:25 ` Kevin Hilman @ 2010-03-02 0:12 ` Rafael J. Wysocki 0 siblings, 0 replies; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-02 0:12 UTC (permalink / raw) To: Kevin Hilman; +Cc: Linux-pm mailing list On Monday 01 March 2010, Kevin Hilman wrote: > "Rafael J. Wysocki" <rjw@sisk.pl> writes: > > > On Saturday 27 February 2010, Mark Brown wrote: > >> On Fri, Feb 26, 2010 at 05:06:59PM -0500, Alan Stern wrote: > >> > On Fri, 26 Feb 2010, Rafael J. Wysocki wrote: > >> > >> > > I have one problem with the design. Namely, dpm_invoke_runtime_*() can > >> > > run a callback from another subsystem. Say you are a device class and you > >> > > decide to use dpm_invoke_runtime_*(), but the device's bus type implements > >> > > the runtime PM callbacks, so they will be run as device class suspend and > >> > > resume callbacks. That doesn't look particularly clean to me. > >> > >> > That is a valid point. I suppose there could be separate bus-type, > >> > device-type, and device-class versions of these functions, but that > >> > seems like excessive complication with little real benefit. > >> > >> I do agree that it'd be good to avoid adding any further complexity here > >> - the use case I have is devices that only really have one suspend type > >> and don't want or need to know if it's a runtime, disk or memory suspend. > > > > What about the patch below, then (untested)? > > > > Use GENERIC_SUBSYS_PM_OPS for the subsystem and then > > UNIVERSAL_DEV_PM_OPS for drivers, possibly passing NULL as idle_fn. > > This looks good to me for what I'm tinkering with too, but have not > tested it. > > One thing missing from the orignal patch is a publicly availble > version of pm_is_runtime_suspended(). I found this useful in at least > one driver where I needed a slightly different suspend hook from he > runtime hook. It is present, but called pm_runtime_suspended(), in the updated patch I sent a while ago: https://lists.linux-foundation.org/pipermail/linux-pm/2010-March/024535.html I'd appreciate it if someone could test that patch. I only could verify that it built correctly with various combinations of .config options. Rafael ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <201003040156.58763.rjw@sisk.pl>]
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions [not found] <201003040156.58763.rjw@sisk.pl> @ 2010-03-04 3:11 ` Alan Stern 0 siblings, 0 replies; 21+ messages in thread From: Alan Stern @ 2010-03-04 3:11 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: linux-pm, LKML On Thu, 4 Mar 2010, Rafael J. Wysocki wrote: > From: Rafael J. Wysocki <rjw@sisk.pl> > 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. This looks pretty good, just a few minor typos and things that could be worded better. > +/** > + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. > + * @dev: Device to suspend. > + * > + * If PM operations are defined for the driver of @dev and they include for @dev's driver > + * ->runtime_suspend(), execute it and return the error code returned by it. and return its error code. > + * Otherwise, return zero. Otherwise, return -EINVAL. > +/** > + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. > + * @dev: Device to resume. > + * > + * If PM operations are defined for the driver of @dev and they include > + * ->runtime_resume(), execute it and return the error code returned by it. > + * Otherwise, return zero. Same as above. > +/** > + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. > + * @dev: Device to handle. > + * @event: PM transition of the system under way. > + * > + * If the device has not been suspended at run time, execute the > + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and > + * return the error code returned by it. Otherwise, return zero. return its error code. > +/** > + * __pm_generic_resume - Generic resume/restore callback for subsystems. > + * @dev: Device to handle. > + * @event: PM transition of the system under way. > + * > + * Execute the resume/resotre callback provided by the driver of @dev, if restore, @dev's driver > + * defined. If it returns 0, change the device's runtime PM status to 'active'. > + * Return the error code returned by it. Return the callback's error code. > --- linux-2.6.orig/Documentation/power/runtime_pm.txt > +++ linux-2.6/Documentation/power/runtime_pm.txt > @@ -335,6 +335,10 @@ drivers/base/power/runtime.c and include > 'power.runtime_error' is set or 'power.disable_depth' is greater than > zero) > > + bool pm_runtime_suspended(struct device *dev); > + - return true if the devices runtime PM status is 'suspended' or false > + otherwise device's run-time, comma before "or" > +7. Generic subsystem callbacks > + > +Subsystems may wish to conserve code space by using the set of generic power > +management callbacks provided by the PM core, defined in > +driver/base/power/generic_ops.c: > + > + int pm_generic_runtime_idle(struct device *dev); > + - invoke the ->runtime_idle() callback provided by the driver of this > + device, if defined, and execute pm_runtime_suspend() for it and call pm_runtime_suspend() for this device if the return value is 0 or the callback isn't defined > + int pm_generic_runtime_suspend(struct device *dev); > + - invoke the ->runtime_suspend() callback provided by the driver of this > + device and return its result, or return -EINVAL if not defined > + > + int pm_generic_runtime_resume(struct device *dev); > + - invoke the ->runtime_resume() callback provided by the driver of this > + device and return its result, or return -EINVAL if not defined > + > + int pm_generic_suspend(struct device *dev); > + - if the device has not been suspended at run time, invoke the ->suspend() > + callback provided by its driver and return the result returned by it, or return its result (same change for the other functions below) > +Device drivers that wish to use the same function as a system suspend, freeze, > +poweroff and run-time suspend callback, and similarly for system resume, thaw, > +restore, and run-time resume, can achieve this with the help of the > +UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h, possibly passing NULL > +as the last argument of it. (possibly setting its last argument to NULL). Alan Stern ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <Pine.LNX.4.44L0.1003032151581.6963-100000@netrider.rowland.org>]
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions [not found] <Pine.LNX.4.44L0.1003032151581.6963-100000@netrider.rowland.org> @ 2010-03-04 21:19 ` Rafael J. Wysocki 2010-03-05 14:55 ` Alan Stern 0 siblings, 1 reply; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-04 21:19 UTC (permalink / raw) To: Alan Stern; +Cc: linux-pm, LKML On Thursday 04 March 2010, Alan Stern wrote: > On Thu, 4 Mar 2010, Rafael J. Wysocki wrote: > > > From: Rafael J. Wysocki <rjw@sisk.pl> > > 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. > > This looks pretty good, just a few minor typos and things that could be > worded better. > > > +/** > > + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. > > + * @dev: Device to suspend. > > + * > > + * If PM operations are defined for the driver of @dev and they include > > for @dev's driver > > > + * ->runtime_suspend(), execute it and return the error code returned by it. > > and return its error code. > > > + * Otherwise, return zero. > > Otherwise, return -EINVAL. > > > +/** > > + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. > > + * @dev: Device to resume. > > + * > > + * If PM operations are defined for the driver of @dev and they include > > + * ->runtime_resume(), execute it and return the error code returned by it. > > + * Otherwise, return zero. > > Same as above. > > > +/** > > + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. > > + * @dev: Device to handle. > > + * @event: PM transition of the system under way. > > + * > > + * If the device has not been suspended at run time, execute the > > + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and > > + * return the error code returned by it. Otherwise, return zero. > > return its error code. > > > +/** > > + * __pm_generic_resume - Generic resume/restore callback for subsystems. > > + * @dev: Device to handle. > > + * @event: PM transition of the system under way. > > + * > > + * Execute the resume/resotre callback provided by the driver of @dev, if > > restore, @dev's driver > > > + * defined. If it returns 0, change the device's runtime PM status to 'active'. > > + * Return the error code returned by it. > > Return the callback's error code. > > > --- linux-2.6.orig/Documentation/power/runtime_pm.txt > > +++ linux-2.6/Documentation/power/runtime_pm.txt > > @@ -335,6 +335,10 @@ drivers/base/power/runtime.c and include > > 'power.runtime_error' is set or 'power.disable_depth' is greater than > > zero) > > > > + bool pm_runtime_suspended(struct device *dev); > > + - return true if the devices runtime PM status is 'suspended' or false > > + otherwise > > device's run-time, comma before "or" > > > +7. Generic subsystem callbacks > > + > > +Subsystems may wish to conserve code space by using the set of generic power > > +management callbacks provided by the PM core, defined in > > +driver/base/power/generic_ops.c: > > + > > + int pm_generic_runtime_idle(struct device *dev); > > + - invoke the ->runtime_idle() callback provided by the driver of this > > + device, if defined, and execute pm_runtime_suspend() for it > > and call pm_runtime_suspend() for this device if the return value is 0 > or the callback isn't defined > > > + int pm_generic_runtime_suspend(struct device *dev); > > + - invoke the ->runtime_suspend() callback provided by the driver of this > > + device and return its result, or return -EINVAL if not defined > > + > > + int pm_generic_runtime_resume(struct device *dev); > > + - invoke the ->runtime_resume() callback provided by the driver of this > > + device and return its result, or return -EINVAL if not defined > > + > > + int pm_generic_suspend(struct device *dev); > > + - if the device has not been suspended at run time, invoke the ->suspend() > > + callback provided by its driver and return the result returned by it, or > > return its result (same change for the other functions below) > > > +Device drivers that wish to use the same function as a system suspend, freeze, > > +poweroff and run-time suspend callback, and similarly for system resume, thaw, > > +restore, and run-time resume, can achieve this with the help of the > > +UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h, possibly passing NULL > > +as the last argument of it. > > (possibly setting its last argument to NULL). I agree with all of the comments above, hopefully addessed them in the new patch below. Thanks! Rafael --- From: Rafael J. Wysocki <rjw@sisk.pl> 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 <rjw@sisk.pl> --- Documentation/power/runtime_pm.txt | 65 ++++++++++ drivers/base/power/Makefile | 1 drivers/base/power/generic_ops.c | 233 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 51 +++++++- include/linux/pm_runtime.h | 6 5 files changed, 350 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/base/power/generic_ops.c =================================================================== --- /dev/null +++ linux-2.6/drivers/base/power/generic_ops.c @@ -0,0 +1,233 @@ +/* + * drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems + * + * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#ifdef CONFIG_PM_RUNTIME +/** + * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. + * @dev: Device to handle. + * + * If PM operations are defined for the driver of @dev and they include + * ->runtime_idle(), execute it and return the error code returned by it if + * nonzero. Otherwise, execute pm_runtime_suspend() for the device. + */ +int pm_generic_runtime_idle(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->runtime_idle) { + int ret = pm->runtime_idle(dev); + if (ret) + return ret; + } + + pm_runtime_suspend(dev); + return 0; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); + +/** + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. + * @dev: Device to suspend. + * + * If PM operations are defined for the @dev's driver and they include + * ->runtime_suspend(), execute it and return its error code. Otherwise, + * return -EINVAL. + */ +int pm_generic_runtime_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); + +/** + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. + * @dev: Device to resume. + * + * If PM operations are defined for the @dev's driver and they include + * ->runtime_resume(), execute it and return its error code. Otherwise, + * return -EINVAL. + */ +int pm_generic_runtime_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +/** + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * If the device has not been suspended at run time, execute the + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and + * return its error code. Otherwise, return zero. + */ +static int __pm_generic_call(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + + if (!pm || pm_runtime_suspended(dev)) + return 0; + + switch (event) { + case PM_EVENT_SUSPEND: + callback = pm->suspend; + break; + case PM_EVENT_FREEZE: + callback = pm->freeze; + break; + case PM_EVENT_HIBERNATE: + callback = pm->poweroff; + break; + case PM_EVENT_THAW: + callback = pm->thaw; + break; + default: + callback = NULL; + break; + } + + return callback ? callback(dev) : 0; +} + +/** + * pm_generic_suspend - Generic suspend callback for subsystems. + * @dev: Device to suspend. + */ +int pm_generic_suspend(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_SUSPEND); +} +EXPORT_SYMBOL_GPL(pm_generic_suspend); + +/** + * pm_generic_freeze - Generic freeze callback for subsystems. + * @dev: Device to freeze. + */ +int pm_generic_freeze(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_FREEZE); +} +EXPORT_SYMBOL_GPL(pm_generic_freeze); + +/** + * pm_generic_poweroff - Generic poweroff callback for subsystems. + * @dev: Device to handle. + */ +int pm_generic_poweroff(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_HIBERNATE); +} +EXPORT_SYMBOL_GPL(pm_generic_poweroff); + +/** + * pm_generic_thaw - Generic thaw callback for subsystems. + * @dev: Device to thaw. + */ +int pm_generic_thaw(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_THAW); +} +EXPORT_SYMBOL_GPL(pm_generic_thaw); + +/** + * __pm_generic_resume - Generic resume/restore callback for subsystems. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * Execute the resume/resotre callback provided by the @dev's driver, if + * defined. If it returns 0, change the device's runtime PM status to 'active'. + * Return the callback's error code. + */ +static int __pm_generic_resume(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + int ret; + + if (!pm) + return 0; + + switch (event) { + case PM_EVENT_RESUME: + callback = pm->resume; + break; + case PM_EVENT_RESTORE: + callback = pm->restore; + break; + default: + callback = NULL; + break; + } + + if (!callback) + return 0; + + ret = callback(dev); + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; +} + +/** + * pm_generic_resume - Generic resume callback for subsystems. + * @dev: Device to resume. + */ +int pm_generic_resume(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESUME); +} +EXPORT_SYMBOL_GPL(pm_generic_resume); + +/** + * pm_generic_restore - Generic restore callback for subsystems. + * @dev: Device to restore. + */ +int pm_generic_restore(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESTORE); +} +EXPORT_SYMBOL_GPL(pm_generic_restore); +#endif /* CONFIG_PM_SLEEP */ + +struct dev_pm_ops generic_subsys_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, +#endif +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +}; +EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); Index: linux-2.6/drivers/base/power/Makefile =================================================================== --- linux-2.6.orig/drivers/base/power/Makefile +++ linux-2.6/drivers/base/power/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_RUNTIME) += runtime.o +obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/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 * Index: linux-2.6/include/linux/pm_runtime.h =================================================================== --- linux-2.6.orig/include/linux/pm_runtime.h +++ linux-2.6/include/linux/pm_runtime.h @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s dev->power.run_wake = enable; } +static inline bool pm_runtime_suspended(struct device *dev) +{ + return dev->power.runtime_status == RPM_SUSPENDED; +} + #else /* !CONFIG_PM_RUNTIME */ static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } @@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresu static inline void pm_runtime_put_noidle(struct device *dev) {} static inline bool device_run_wake(struct device *dev) { return false; } static inline void device_set_run_wake(struct device *dev, bool enable) {} +static inline bool pm_runtime_suspended(struct device *dev) { return false; } #endif /* !CONFIG_PM_RUNTIME */ Index: linux-2.6/Documentation/power/runtime_pm.txt =================================================================== --- linux-2.6.orig/Documentation/power/runtime_pm.txt +++ linux-2.6/Documentation/power/runtime_pm.txt @@ -335,6 +335,10 @@ drivers/base/power/runtime.c and include 'power.runtime_error' is set or 'power.disable_depth' is greater than zero) + bool pm_runtime_suspended(struct device *dev); + - return true if the device's runtime PM status is 'suspended', or false + otherwise + void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to @@ -459,3 +463,64 @@ The PM core always increments the run-ti ->prepare() callback and decrements it after calling the ->complete() callback. Hence disabling run-time PM temporarily like this will not cause any run-time suspend callbacks to be lost. + +7. Generic subsystem callbacks + +Subsystems may wish to conserve code space by using the set of generic power +management callbacks provided by the PM core, defined in +driver/base/power/generic_ops.c: + + int pm_generic_runtime_idle(struct device *dev); + - invoke the ->runtime_idle() callback provided by the driver of this + device, if defined, and call pm_runtime_suspend() for this device if the + return value is 0 or the callback is not defined + + int pm_generic_runtime_suspend(struct device *dev); + - invoke the ->runtime_suspend() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_runtime_resume(struct device *dev); + - invoke the ->runtime_resume() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_suspend(struct device *dev); + - if the device has not been suspended at run time, invoke the ->suspend() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_resume(struct device *dev); + - invoke the ->resume() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + + int pm_generic_freeze(struct device *dev); + - if the device has not been suspended at run time, invoke the ->freeze() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_thaw(struct device *dev); + - if the device has not been suspended at run time, invoke the ->thaw() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_poweroff(struct device *dev); + - if the device has not been suspended at run time, invoke the ->poweroff() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_restore(struct device *dev); + - invoke the ->restore() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + +These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), +->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(), +or ->restore() callback pointers in the subsystem-level dev_pm_ops structures. + +If a subsystem wishes to use all of them at the same time, it can simply assign +the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its +dev_pm_ops structure pointer. + +Device drivers that wish to use the same function as a system suspend, freeze, +poweroff and run-time suspend callback, and similarly for system resume, thaw, +restore, and run-time resume, can achieve this with the help of the +UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its +last argument to NULL). ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions 2010-03-04 21:19 ` Rafael J. Wysocki @ 2010-03-05 14:55 ` Alan Stern 0 siblings, 0 replies; 21+ messages in thread From: Alan Stern @ 2010-03-05 14:55 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: linux-pm, LKML On Thu, 4 Mar 2010, Rafael J. Wysocki wrote: > I agree with all of the comments above, hopefully addessed them in the new > patch below. It looks good. One small thing: You probably should change the kerneldoc for pm_generic_runtime_idle to match the changes in pm_generic_runtime_{suspend,resume}. I must have missed that one. Alan Stern ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <Pine.LNX.4.44L0.1003050954160.1677-100000@iolanthe.rowland.org>]
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions [not found] <Pine.LNX.4.44L0.1003050954160.1677-100000@iolanthe.rowland.org> @ 2010-03-05 20:40 ` Rafael J. Wysocki 0 siblings, 0 replies; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-05 20:40 UTC (permalink / raw) To: Alan Stern; +Cc: linux-pm, LKML On Friday 05 March 2010, Alan Stern wrote: > On Thu, 4 Mar 2010, Rafael J. Wysocki wrote: > > > I agree with all of the comments above, hopefully addessed them in the new > > patch below. > > It looks good. One small thing: You probably should change the > kerneldoc for pm_generic_runtime_idle to match the changes in > pm_generic_runtime_{suspend,resume}. I must have missed that one. Yeah, I missed that too. Should be better now. Rafael --- From: Rafael J. Wysocki <rjw@sisk.pl> 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 <rjw@sisk.pl> --- Documentation/power/runtime_pm.txt | 65 ++++++++++ drivers/base/power/Makefile | 1 drivers/base/power/generic_ops.c | 233 +++++++++++++++++++++++++++++++++++++ include/linux/pm.h | 51 +++++++- include/linux/pm_runtime.h | 6 5 files changed, 350 insertions(+), 6 deletions(-) Index: linux-2.6/drivers/base/power/generic_ops.c =================================================================== --- /dev/null +++ linux-2.6/drivers/base/power/generic_ops.c @@ -0,0 +1,233 @@ +/* + * drivers/base/power/generic_ops.c - Generic PM callbacks for subsystems + * + * Copyright (c) 2010 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. + * + * This file is released under the GPLv2. + */ + +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#ifdef CONFIG_PM_RUNTIME +/** + * pm_generic_runtime_idle - Generic runtime idle callback for subsystems. + * @dev: Device to handle. + * + * If PM operations are defined for the @dev's driver and they include + * ->runtime_idle(), execute it and return its error code, if nonzero. + * Otherwise, execute pm_runtime_suspend() for the device and return 0. + */ +int pm_generic_runtime_idle(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + + if (pm && pm->runtime_idle) { + int ret = pm->runtime_idle(dev); + if (ret) + return ret; + } + + pm_runtime_suspend(dev); + return 0; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_idle); + +/** + * pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems. + * @dev: Device to suspend. + * + * If PM operations are defined for the @dev's driver and they include + * ->runtime_suspend(), execute it and return its error code. Otherwise, + * return -EINVAL. + */ +int pm_generic_runtime_suspend(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_suspend); + +/** + * pm_generic_runtime_resume - Generic runtime resume callback for subsystems. + * @dev: Device to resume. + * + * If PM operations are defined for the @dev's driver and they include + * ->runtime_resume(), execute it and return its error code. Otherwise, + * return -EINVAL. + */ +int pm_generic_runtime_resume(struct device *dev) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int ret; + + ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(pm_generic_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +/** + * __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * If the device has not been suspended at run time, execute the + * suspend/freeze/poweroff/thaw callback provided by its driver, if defined, and + * return its error code. Otherwise, return zero. + */ +static int __pm_generic_call(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + + if (!pm || pm_runtime_suspended(dev)) + return 0; + + switch (event) { + case PM_EVENT_SUSPEND: + callback = pm->suspend; + break; + case PM_EVENT_FREEZE: + callback = pm->freeze; + break; + case PM_EVENT_HIBERNATE: + callback = pm->poweroff; + break; + case PM_EVENT_THAW: + callback = pm->thaw; + break; + default: + callback = NULL; + break; + } + + return callback ? callback(dev) : 0; +} + +/** + * pm_generic_suspend - Generic suspend callback for subsystems. + * @dev: Device to suspend. + */ +int pm_generic_suspend(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_SUSPEND); +} +EXPORT_SYMBOL_GPL(pm_generic_suspend); + +/** + * pm_generic_freeze - Generic freeze callback for subsystems. + * @dev: Device to freeze. + */ +int pm_generic_freeze(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_FREEZE); +} +EXPORT_SYMBOL_GPL(pm_generic_freeze); + +/** + * pm_generic_poweroff - Generic poweroff callback for subsystems. + * @dev: Device to handle. + */ +int pm_generic_poweroff(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_HIBERNATE); +} +EXPORT_SYMBOL_GPL(pm_generic_poweroff); + +/** + * pm_generic_thaw - Generic thaw callback for subsystems. + * @dev: Device to thaw. + */ +int pm_generic_thaw(struct device *dev) +{ + return __pm_generic_call(dev, PM_EVENT_THAW); +} +EXPORT_SYMBOL_GPL(pm_generic_thaw); + +/** + * __pm_generic_resume - Generic resume/restore callback for subsystems. + * @dev: Device to handle. + * @event: PM transition of the system under way. + * + * Execute the resume/resotre callback provided by the @dev's driver, if + * defined. If it returns 0, change the device's runtime PM status to 'active'. + * Return the callback's error code. + */ +static int __pm_generic_resume(struct device *dev, int event) +{ + const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; + int (*callback)(struct device *); + int ret; + + if (!pm) + return 0; + + switch (event) { + case PM_EVENT_RESUME: + callback = pm->resume; + break; + case PM_EVENT_RESTORE: + callback = pm->restore; + break; + default: + callback = NULL; + break; + } + + if (!callback) + return 0; + + ret = callback(dev); + if (!ret) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return ret; +} + +/** + * pm_generic_resume - Generic resume callback for subsystems. + * @dev: Device to resume. + */ +int pm_generic_resume(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESUME); +} +EXPORT_SYMBOL_GPL(pm_generic_resume); + +/** + * pm_generic_restore - Generic restore callback for subsystems. + * @dev: Device to restore. + */ +int pm_generic_restore(struct device *dev) +{ + return __pm_generic_resume(dev, PM_EVENT_RESTORE); +} +EXPORT_SYMBOL_GPL(pm_generic_restore); +#endif /* CONFIG_PM_SLEEP */ + +struct dev_pm_ops generic_subsys_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, +#endif +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +}; +EXPORT_SYMBOL_GPL(generic_subsys_pm_ops); Index: linux-2.6/drivers/base/power/Makefile =================================================================== --- linux-2.6.orig/drivers/base/power/Makefile +++ linux-2.6/drivers/base/power/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_RUNTIME) += runtime.o +obj-$(CONFIG_PM_OPS) += generic_ops.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG Index: linux-2.6/include/linux/pm.h =================================================================== --- linux-2.6.orig/include/linux/pm.h +++ linux-2.6/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 * Index: linux-2.6/include/linux/pm_runtime.h =================================================================== --- linux-2.6.orig/include/linux/pm_runtime.h +++ linux-2.6/include/linux/pm_runtime.h @@ -62,6 +62,11 @@ static inline void device_set_run_wake(s dev->power.run_wake = enable; } +static inline bool pm_runtime_suspended(struct device *dev) +{ + return dev->power.runtime_status == RPM_SUSPENDED; +} + #else /* !CONFIG_PM_RUNTIME */ static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; } @@ -89,6 +94,7 @@ static inline void pm_runtime_get_noresu static inline void pm_runtime_put_noidle(struct device *dev) {} static inline bool device_run_wake(struct device *dev) { return false; } static inline void device_set_run_wake(struct device *dev, bool enable) {} +static inline bool pm_runtime_suspended(struct device *dev) { return false; } #endif /* !CONFIG_PM_RUNTIME */ Index: linux-2.6/Documentation/power/runtime_pm.txt =================================================================== --- linux-2.6.orig/Documentation/power/runtime_pm.txt +++ linux-2.6/Documentation/power/runtime_pm.txt @@ -335,6 +335,10 @@ drivers/base/power/runtime.c and include 'power.runtime_error' is set or 'power.disable_depth' is greater than zero) + bool pm_runtime_suspended(struct device *dev); + - return true if the device's runtime PM status is 'suspended', or false + otherwise + void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to @@ -459,3 +463,64 @@ The PM core always increments the run-ti ->prepare() callback and decrements it after calling the ->complete() callback. Hence disabling run-time PM temporarily like this will not cause any run-time suspend callbacks to be lost. + +7. Generic subsystem callbacks + +Subsystems may wish to conserve code space by using the set of generic power +management callbacks provided by the PM core, defined in +driver/base/power/generic_ops.c: + + int pm_generic_runtime_idle(struct device *dev); + - invoke the ->runtime_idle() callback provided by the driver of this + device, if defined, and call pm_runtime_suspend() for this device if the + return value is 0 or the callback is not defined + + int pm_generic_runtime_suspend(struct device *dev); + - invoke the ->runtime_suspend() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_runtime_resume(struct device *dev); + - invoke the ->runtime_resume() callback provided by the driver of this + device and return its result, or return -EINVAL if not defined + + int pm_generic_suspend(struct device *dev); + - if the device has not been suspended at run time, invoke the ->suspend() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_resume(struct device *dev); + - invoke the ->resume() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + + int pm_generic_freeze(struct device *dev); + - if the device has not been suspended at run time, invoke the ->freeze() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_thaw(struct device *dev); + - if the device has not been suspended at run time, invoke the ->thaw() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_poweroff(struct device *dev); + - if the device has not been suspended at run time, invoke the ->poweroff() + callback provided by its driver and return its result, or return 0 if not + defined + + int pm_generic_restore(struct device *dev); + - invoke the ->restore() callback provided by the driver of this device and, + if successful, change the device's runtime PM status to 'active' + +These functions can be assigned to the ->runtime_idle(), ->runtime_suspend(), +->runtime_resume(), ->suspend(), ->resume(), ->freeze(), ->thaw(), ->poweroff(), +or ->restore() callback pointers in the subsystem-level dev_pm_ops structures. + +If a subsystem wishes to use all of them at the same time, it can simply assign +the GENERIC_SUBSYS_PM_OPS macro, defined in include/linux/pm.h, to its +dev_pm_ops structure pointer. + +Device drivers that wish to use the same function as a system suspend, freeze, +poweroff and run-time suspend callback, and similarly for system resume, thaw, +restore, and run-time resume, can achieve this with the help of the +UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its +last argument to NULL). ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <201003052140.16948.rjw@sisk.pl>]
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions [not found] <201003052140.16948.rjw@sisk.pl> @ 2010-03-05 21:00 ` Alan Stern 0 siblings, 0 replies; 21+ messages in thread From: Alan Stern @ 2010-03-05 21:00 UTC (permalink / raw) To: Rafael J. Wysocki; +Cc: linux-pm, LKML On Fri, 5 Mar 2010, Rafael J. Wysocki wrote: > On Friday 05 March 2010, Alan Stern wrote: > > On Thu, 4 Mar 2010, Rafael J. Wysocki wrote: > > > > > I agree with all of the comments above, hopefully addessed them in the new > > > patch below. > > > > It looks good. One small thing: You probably should change the > > kerneldoc for pm_generic_runtime_idle to match the changes in > > pm_generic_runtime_{suspend,resume}. I must have missed that one. > > Yeah, I missed that too. Should be better now. So it is. Alan Stern ^ permalink raw reply [flat|nested] 21+ messages in thread
[parent not found: <Pine.LNX.4.44L0.1003051559410.1384-100000@iolanthe.rowland.org>]
* Re: [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions [not found] <Pine.LNX.4.44L0.1003051559410.1384-100000@iolanthe.rowland.org> @ 2010-03-05 21:09 ` Rafael J. Wysocki 0 siblings, 0 replies; 21+ messages in thread From: Rafael J. Wysocki @ 2010-03-05 21:09 UTC (permalink / raw) To: Alan Stern; +Cc: linux-pm, LKML On Friday 05 March 2010, Alan Stern wrote: > On Fri, 5 Mar 2010, Rafael J. Wysocki wrote: > > > On Friday 05 March 2010, Alan Stern wrote: > > > On Thu, 4 Mar 2010, Rafael J. Wysocki wrote: > > > > > > > I agree with all of the comments above, hopefully addessed them in the new > > > > patch below. > > > > > > It looks good. One small thing: You probably should change the > > > kerneldoc for pm_generic_runtime_idle to match the changes in > > > pm_generic_runtime_{suspend,resume}. I must have missed that one. > > > > Yeah, I missed that too. Should be better now. > > So it is. Thanks! I'll try to send it to Linus during this merge window along with a missing runtime PM documentation update. Then, I'm going to start updating the old device PM documentation, because it's hopelessly outdated. Rafael ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2010-03-05 21:09 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-26 16:46 [PATCH] PM: add dpm_use_runtime_{suspend, resume} helper functions Alan Stern
2010-02-26 21:24 ` Rafael J. Wysocki
2010-02-26 22:06 ` Alan Stern
2010-02-27 10:43 ` Mark Brown
2010-02-27 22:50 ` Rafael J. Wysocki
2010-03-01 13:31 ` Mark Brown
2010-03-01 18:40 ` Alan Stern
2010-03-01 22:06 ` Rafael J. Wysocki
2010-03-02 16:12 ` Alan Stern
2010-03-02 22:51 ` Rafael J. Wysocki
2010-03-03 16:46 ` Alan Stern
2010-03-03 21:33 ` Rafael J. Wysocki
2010-03-04 0:56 ` Rafael J. Wysocki
2010-03-01 22:25 ` Kevin Hilman
2010-03-02 0:12 ` Rafael J. Wysocki
[not found] <201003040156.58763.rjw@sisk.pl>
2010-03-04 3:11 ` Alan Stern
[not found] <Pine.LNX.4.44L0.1003032151581.6963-100000@netrider.rowland.org>
2010-03-04 21:19 ` Rafael J. Wysocki
2010-03-05 14:55 ` Alan Stern
[not found] <Pine.LNX.4.44L0.1003050954160.1677-100000@iolanthe.rowland.org>
2010-03-05 20:40 ` Rafael J. Wysocki
[not found] <201003052140.16948.rjw@sisk.pl>
2010-03-05 21:00 ` Alan Stern
[not found] <Pine.LNX.4.44L0.1003051559410.1384-100000@iolanthe.rowland.org>
2010-03-05 21:09 ` Rafael J. Wysocki
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox