All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions
@ 2014-02-13  9:01 Ulf Hansson
  2014-02-19 20:59 ` Alan Stern
  0 siblings, 1 reply; 6+ messages in thread
From: Ulf Hansson @ 2014-02-13  9:01 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Pavel Machek, linux-pm
  Cc: Ulf Hansson, Kevin Hilman, Alan Stern, Greg Kroah-Hartman,
	Mark Brown, Russell King, Linus Walleij

This patch provides two new runtime PM helper functions which intend to
be used from system suspend/resume callbacks, to make sure devices are
put into low power state during system suspend and brought back to full
power at system resume.

The prerequisite is to have all levels of a device's runtime PM
callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which
means these are available for CONFIG_PM.

By using the new runtime PM helper functions especially the two
scenarios below will be addressed.

1) The PM core prevents .runtime_suspend callbacks from being invoked
during system suspend. That means even for a runtime PM centric
subsystem and driver, the device needs to be put into low power state
from a system suspend callback. Otherwise it may very well be left in
full power state (runtime resumed) while the system is suspended. By
using the new helper functions, we make sure to walk the hierarchy of
a device's power domain, subsystem and driver.

2) Subsystems and drivers need to cope with all the combinations of
CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions
smothly addresses this.

Cc: Kevin Hilman <khilman@linaro.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Mark Brown <broonie@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---

Some relevant background to this patch:

Recent discussions on linux-pm mailing list regarding a similar patch, but which
added similar functionality as pm_generic* functions, which concluded to be
dropped.

http://marc.info/?t=138556666500004&r=1&w=2

Responses on recent sent patches, which are rejected from subsystem maintainers,
while trying to adopt suspend/resume callbacks when using SET_PM_RUNTIME_PM_OPS.

http://marc.info/?t=139152977000004&r=1&w=2
http://marc.info/?t=139152958400001&r=1&w=2

---
 drivers/base/power/Makefile  |    3 +-
 drivers/base/power/runtime.c |  110 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/pm_runtime.h   |    4 ++
 3 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 2e58ebb..1cb8544 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,5 @@
-obj-$(CONFIG_PM)	+= sysfs.o generic_ops.o common.o qos.o
+obj-$(CONFIG_PM)	+= sysfs.o generic_ops.o common.o qos.o runtime.o
 obj-$(CONFIG_PM_SLEEP)	+= main.o wakeup.o
-obj-$(CONFIG_PM_RUNTIME)	+= runtime.o
 obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
 obj-$(CONFIG_PM_OPP)	+= opp.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS)	+=  domain.o domain_governor.o
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 72e00e6..959c478 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -13,6 +13,7 @@
 #include <trace/events/rpm.h>
 #include "power.h"
 
+#ifdef CONFIG_PM_RUNTIME
 static int rpm_resume(struct device *dev, int rpmflags);
 static int rpm_suspend(struct device *dev, int rpmflags);
 
@@ -1401,3 +1402,112 @@ void pm_runtime_remove(struct device *dev)
 	if (dev->power.irq_safe && dev->parent)
 		pm_runtime_put(dev->parent);
 }
+#endif
+
+#ifdef CONFIG_PM
+/**
+ * pm_runtime_force_suspend - Force a device into suspend state if needed.
+ * @dev: Device to suspend.
+ *
+ * Disable runtime PM so we safely can check the device's runtime PM status and
+ * if it is active, invoke it's .runtime_suspend callback to bring it into
+ * suspend state. Keep runtime PM disabled to preserve the state unless we
+ * encounter errors.
+ *
+ * Typically this function may be invoked from a system suspend callback to make
+ * sure the device is put into low power state.
+ */
+int pm_runtime_force_suspend(struct device *dev)
+{
+	int (*callback)(struct device *);
+	int ret = 0;
+
+	pm_runtime_disable(dev);
+
+	/*
+	 * Note that pm_runtime_status_suspended() returns false while
+	 * !CONFIG_PM_RUNTIME, which means the device will be put into low
+	 * power state.
+	 */
+	if (pm_runtime_status_suspended(dev))
+		return 0;
+
+	if (dev->pm_domain)
+		callback = dev->pm_domain->ops.runtime_suspend;
+	else if (dev->type && dev->type->pm)
+		callback = dev->type->pm->runtime_suspend;
+	else if (dev->class && dev->class->pm)
+		callback = dev->class->pm->runtime_suspend;
+	else if (dev->bus && dev->bus->pm)
+		callback = dev->bus->pm->runtime_suspend;
+	else
+		callback = NULL;
+
+	if (!callback && dev->driver && dev->driver->pm)
+		callback = dev->driver->pm->runtime_suspend;
+
+	if (!callback) {
+		ret = -ENOSYS;
+		goto err;
+	}
+
+	ret = callback(dev);
+	if (ret)
+		goto err;
+
+	pm_runtime_set_suspended(dev);
+	return 0;
+err:
+	pm_runtime_enable(dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
+
+/**
+ * pm_runtime_force_resume - Force a device into resume state.
+ * @dev: Device to resume.
+ *
+ * Prior invoking this function we expect the user to have brought the device
+ * into low power state by a call to pm_runtime_force_suspend(). Here we reverse
+ * those actions and brings the device into full power. We update the runtime PM
+ * status and re-enables runtime PM.
+ *
+ * Typically this function may be invoked from a system resume callback to make
+ * sure the device is put into full power state.
+ */
+int pm_runtime_force_resume(struct device *dev)
+{
+	int (*callback)(struct device *);
+	int ret = 0;
+
+	if (dev->pm_domain)
+		callback = dev->pm_domain->ops.runtime_resume;
+	else if (dev->type && dev->type->pm)
+		callback = dev->type->pm->runtime_resume;
+	else if (dev->class && dev->class->pm)
+		callback = dev->class->pm->runtime_resume;
+	else if (dev->bus && dev->bus->pm)
+		callback = dev->bus->pm->runtime_resume;
+	else
+		callback = NULL;
+
+	if (!callback && dev->driver && dev->driver->pm)
+		callback = dev->driver->pm->runtime_resume;
+
+	if (!callback) {
+		ret = -ENOSYS;
+		goto out;
+	}
+
+	ret = callback(dev);
+	if (ret)
+		goto out;
+
+	pm_runtime_set_active(dev);
+	pm_runtime_mark_last_busy(dev);
+out:
+	pm_runtime_enable(dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
+#endif
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 16c9a62..2a5897a 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -26,9 +26,13 @@
 #ifdef CONFIG_PM
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
+extern int pm_runtime_force_suspend(struct device *dev);
+extern int pm_runtime_force_resume(struct device *dev);
 #else
 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
+static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
+static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions
  2014-02-13  9:01 [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions Ulf Hansson
@ 2014-02-19 20:59 ` Alan Stern
  2014-02-20  1:27   ` Rafael J. Wysocki
  0 siblings, 1 reply; 6+ messages in thread
From: Alan Stern @ 2014-02-19 20:59 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rafael J. Wysocki, Len Brown, Pavel Machek,
	Linux-pm mailing list, Kevin Hilman, Greg Kroah-Hartman,
	Mark Brown, Russell King, Linus Walleij

On Thu, 13 Feb 2014, Ulf Hansson wrote:

> This patch provides two new runtime PM helper functions which intend to
> be used from system suspend/resume callbacks, to make sure devices are
> put into low power state during system suspend and brought back to full
> power at system resume.
> 
> The prerequisite is to have all levels of a device's runtime PM
> callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which
> means these are available for CONFIG_PM.
> 
> By using the new runtime PM helper functions especially the two
> scenarios below will be addressed.
> 
> 1) The PM core prevents .runtime_suspend callbacks from being invoked
> during system suspend. That means even for a runtime PM centric
> subsystem and driver, the device needs to be put into low power state
> from a system suspend callback. Otherwise it may very well be left in
> full power state (runtime resumed) while the system is suspended. By
> using the new helper functions, we make sure to walk the hierarchy of
> a device's power domain, subsystem and driver.
> 
> 2) Subsystems and drivers need to cope with all the combinations of
> CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions
> smothly addresses this.

I don't know how Rafael feels about this proposal.  One aspect of it is 
striking, however...

> +#ifdef CONFIG_PM
> +/**
> + * pm_runtime_force_suspend - Force a device into suspend state if needed.
> + * @dev: Device to suspend.
> + *
> + * Disable runtime PM so we safely can check the device's runtime PM status and
> + * if it is active, invoke it's .runtime_suspend callback to bring it into
> + * suspend state. Keep runtime PM disabled to preserve the state unless we
> + * encounter errors.
> + *
> + * Typically this function may be invoked from a system suspend callback to make
> + * sure the device is put into low power state.
> + */
> +int pm_runtime_force_suspend(struct device *dev)
> +{
> +	int (*callback)(struct device *);
> +	int ret = 0;
> +
> +	pm_runtime_disable(dev);
> +
> +	/*
> +	 * Note that pm_runtime_status_suspended() returns false while
> +	 * !CONFIG_PM_RUNTIME, which means the device will be put into low
> +	 * power state.
> +	 */
> +	if (pm_runtime_status_suspended(dev))
> +		return 0;
> +
> +	if (dev->pm_domain)
> +		callback = dev->pm_domain->ops.runtime_suspend;
> +	else if (dev->type && dev->type->pm)
> +		callback = dev->type->pm->runtime_suspend;
> +	else if (dev->class && dev->class->pm)
> +		callback = dev->class->pm->runtime_suspend;
> +	else if (dev->bus && dev->bus->pm)
> +		callback = dev->bus->pm->runtime_suspend;
> +	else
> +		callback = NULL;
> +
> +	if (!callback && dev->driver && dev->driver->pm)
> +		callback = dev->driver->pm->runtime_suspend;
> +
> +	if (!callback) {
> +		ret = -ENOSYS;
> +		goto err;
> +	}
> +
> +	ret = callback(dev);
> +	if (ret)
> +		goto err;
> +
> +	pm_runtime_set_suspended(dev);
> +	return 0;
> +err:
> +	pm_runtime_enable(dev);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);

Most of this code is already present in rpm_suspend.  Instead of 
copying it, you should put it in a separate function that can be 
invoked from both places.

The same is true of your pm_runtime_force_resume routine.

Alan Stern


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions
  2014-02-19 20:59 ` Alan Stern
@ 2014-02-20  1:27   ` Rafael J. Wysocki
  2014-02-20  9:28     ` Ulf Hansson
  0 siblings, 1 reply; 6+ messages in thread
From: Rafael J. Wysocki @ 2014-02-20  1:27 UTC (permalink / raw)
  To: Alan Stern
  Cc: Ulf Hansson, Len Brown, Pavel Machek, Linux-pm mailing list,
	Kevin Hilman, Greg Kroah-Hartman, Mark Brown, Russell King,
	Linus Walleij

On Wednesday, February 19, 2014 03:59:13 PM Alan Stern wrote:
> On Thu, 13 Feb 2014, Ulf Hansson wrote:
> 
> > This patch provides two new runtime PM helper functions which intend to
> > be used from system suspend/resume callbacks, to make sure devices are
> > put into low power state during system suspend and brought back to full
> > power at system resume.
> > 
> > The prerequisite is to have all levels of a device's runtime PM
> > callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which
> > means these are available for CONFIG_PM.
> > 
> > By using the new runtime PM helper functions especially the two
> > scenarios below will be addressed.
> > 
> > 1) The PM core prevents .runtime_suspend callbacks from being invoked
> > during system suspend. That means even for a runtime PM centric
> > subsystem and driver, the device needs to be put into low power state
> > from a system suspend callback. Otherwise it may very well be left in
> > full power state (runtime resumed) while the system is suspended. By
> > using the new helper functions, we make sure to walk the hierarchy of
> > a device's power domain, subsystem and driver.
> > 
> > 2) Subsystems and drivers need to cope with all the combinations of
> > CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions
> > smothly addresses this.
> 
> I don't know how Rafael feels about this proposal.

Quite frankly, I don't see much point in adding helpers without any users.

> One aspect of it is striking, however...
> 
> > +#ifdef CONFIG_PM
> > +/**
> > + * pm_runtime_force_suspend - Force a device into suspend state if needed.
> > + * @dev: Device to suspend.
> > + *
> > + * Disable runtime PM so we safely can check the device's runtime PM status and
> > + * if it is active, invoke it's .runtime_suspend callback to bring it into
> > + * suspend state. Keep runtime PM disabled to preserve the state unless we
> > + * encounter errors.
> > + *
> > + * Typically this function may be invoked from a system suspend callback to make
> > + * sure the device is put into low power state.
> > + */
> > +int pm_runtime_force_suspend(struct device *dev)
> > +{
> > +	int (*callback)(struct device *);
> > +	int ret = 0;
> > +
> > +	pm_runtime_disable(dev);
> > +
> > +	/*
> > +	 * Note that pm_runtime_status_suspended() returns false while
> > +	 * !CONFIG_PM_RUNTIME, which means the device will be put into low
> > +	 * power state.
> > +	 */
> > +	if (pm_runtime_status_suspended(dev))
> > +		return 0;
> > +
> > +	if (dev->pm_domain)
> > +		callback = dev->pm_domain->ops.runtime_suspend;
> > +	else if (dev->type && dev->type->pm)
> > +		callback = dev->type->pm->runtime_suspend;
> > +	else if (dev->class && dev->class->pm)
> > +		callback = dev->class->pm->runtime_suspend;
> > +	else if (dev->bus && dev->bus->pm)
> > +		callback = dev->bus->pm->runtime_suspend;
> > +	else
> > +		callback = NULL;
> > +
> > +	if (!callback && dev->driver && dev->driver->pm)
> > +		callback = dev->driver->pm->runtime_suspend;
> > +
> > +	if (!callback) {
> > +		ret = -ENOSYS;
> > +		goto err;
> > +	}
> > +
> > +	ret = callback(dev);
> > +	if (ret)
> > +		goto err;
> > +
> > +	pm_runtime_set_suspended(dev);
> > +	return 0;
> > +err:
> > +	pm_runtime_enable(dev);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
> 
> Most of this code is already present in rpm_suspend.  Instead of 
> copying it, you should put it in a separate function that can be 
> invoked from both places.
> 
> The same is true of your pm_runtime_force_resume routine.

Agreed.

Thanks,
Rafael


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions
  2014-02-20  1:27   ` Rafael J. Wysocki
@ 2014-02-20  9:28     ` Ulf Hansson
  0 siblings, 0 replies; 6+ messages in thread
From: Ulf Hansson @ 2014-02-20  9:28 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Alan Stern, Len Brown, Pavel Machek, Linux-pm mailing list,
	Kevin Hilman, Greg Kroah-Hartman, Mark Brown, Russell King,
	Linus Walleij

On 20 February 2014 02:27, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Wednesday, February 19, 2014 03:59:13 PM Alan Stern wrote:
>> On Thu, 13 Feb 2014, Ulf Hansson wrote:
>>
>> > This patch provides two new runtime PM helper functions which intend to
>> > be used from system suspend/resume callbacks, to make sure devices are
>> > put into low power state during system suspend and brought back to full
>> > power at system resume.
>> >
>> > The prerequisite is to have all levels of a device's runtime PM
>> > callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which
>> > means these are available for CONFIG_PM.
>> >
>> > By using the new runtime PM helper functions especially the two
>> > scenarios below will be addressed.
>> >
>> > 1) The PM core prevents .runtime_suspend callbacks from being invoked
>> > during system suspend. That means even for a runtime PM centric
>> > subsystem and driver, the device needs to be put into low power state
>> > from a system suspend callback. Otherwise it may very well be left in
>> > full power state (runtime resumed) while the system is suspended. By
>> > using the new helper functions, we make sure to walk the hierarchy of
>> > a device's power domain, subsystem and driver.
>> >
>> > 2) Subsystems and drivers need to cope with all the combinations of
>> > CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions
>> > smothly addresses this.
>>
>> I don't know how Rafael feels about this proposal.
>
> Quite frankly, I don't see much point in adding helpers without any users.

Then, let me post some patches were you can see some examples. :-)

Do note, I have already posted patches to fixup three amba drivers and
the amba bus, though these implemented similar code as the new helper
functions by themselves, which obviously caused subsystem maintainers
to complain about open coding.

SPI: PL022 driver:
http://marc.info/?t=139152977000004&r=1&w=2

MMC: MMCI driver:
http://marc.info/?t=139152958400001&r=1&w=2

I2C: Nomadik driver:
http://marc.info/?t=139281301800011&r=1&w=2

>
>> One aspect of it is striking, however...
>>
>> > +#ifdef CONFIG_PM
>> > +/**
>> > + * pm_runtime_force_suspend - Force a device into suspend state if needed.
>> > + * @dev: Device to suspend.
>> > + *
>> > + * Disable runtime PM so we safely can check the device's runtime PM status and
>> > + * if it is active, invoke it's .runtime_suspend callback to bring it into
>> > + * suspend state. Keep runtime PM disabled to preserve the state unless we
>> > + * encounter errors.
>> > + *
>> > + * Typically this function may be invoked from a system suspend callback to make
>> > + * sure the device is put into low power state.
>> > + */
>> > +int pm_runtime_force_suspend(struct device *dev)
>> > +{
>> > +   int (*callback)(struct device *);
>> > +   int ret = 0;
>> > +
>> > +   pm_runtime_disable(dev);
>> > +
>> > +   /*
>> > +    * Note that pm_runtime_status_suspended() returns false while
>> > +    * !CONFIG_PM_RUNTIME, which means the device will be put into low
>> > +    * power state.
>> > +    */
>> > +   if (pm_runtime_status_suspended(dev))
>> > +           return 0;
>> > +
>> > +   if (dev->pm_domain)
>> > +           callback = dev->pm_domain->ops.runtime_suspend;
>> > +   else if (dev->type && dev->type->pm)
>> > +           callback = dev->type->pm->runtime_suspend;
>> > +   else if (dev->class && dev->class->pm)
>> > +           callback = dev->class->pm->runtime_suspend;
>> > +   else if (dev->bus && dev->bus->pm)
>> > +           callback = dev->bus->pm->runtime_suspend;
>> > +   else
>> > +           callback = NULL;
>> > +
>> > +   if (!callback && dev->driver && dev->driver->pm)
>> > +           callback = dev->driver->pm->runtime_suspend;
>> > +
>> > +   if (!callback) {
>> > +           ret = -ENOSYS;
>> > +           goto err;
>> > +   }
>> > +
>> > +   ret = callback(dev);
>> > +   if (ret)
>> > +           goto err;
>> > +
>> > +   pm_runtime_set_suspended(dev);
>> > +   return 0;
>> > +err:
>> > +   pm_runtime_enable(dev);
>> > +   return ret;
>> > +}
>> > +EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
>>
>> Most of this code is already present in rpm_suspend.  Instead of
>> copying it, you should put it in a separate function that can be
>> invoked from both places.
>>
>> The same is true of your pm_runtime_force_resume routine.
>
> Agreed.

Thanks for your input, I will update in v2.

Kind regards
Uffe

>
> Thanks,
> Rafael
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions
  2014-02-12 17:16 Ulf Hansson
@ 2014-02-24 13:19 ` Linus Walleij
  0 siblings, 0 replies; 6+ messages in thread
From: Linus Walleij @ 2014-02-24 13:19 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Rafael J. Wysocki, Len Brown, Pavel Machek, linux-pm,
	Kevin Hilman, Alan Stern, Greg Kroah-Hartman, Mark Brown,
	Russell King

On Wed, Feb 12, 2014 at 6:16 PM, Ulf Hansson <ulf.hansson@linaro.org> wrote:

> This patch provides two new runtime PM helper functions which intend to
> be used from system suspend/resume callbacks, to make sure devices are
> put into low power state during system suspend and brought back to full
> power at system resume.
>
> The prerequisite is to have all levels of a device's runtime PM
> callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which
> means these are available for CONFIG_PM.
>
> By using the new runtime PM helper functions especially the two
> scenarios below will be addressed.
>
> 1) The PM core prevents .runtime_suspend callbacks from being invoked
> during system suspend. That means even for a runtime PM centric
> subsystem and driver, the device needs to be put into low power state
> from a system suspend callback. Otherwise it may very well be left in
> full power state (runtime resumed) while the system is suspended. By
> using the new helper functions, we make sure to walk the hierarchy of
> a device's power domain, subsystem and driver.
>
> 2) Subsystems and drivers need to cope with all the combinations of
> CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions
> smothly addresses this.
>
> Cc: Kevin Hilman <khilman@linaro.org>
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: Mark Brown <broonie@linaro.org>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

This looks to my amateurish eyes like a piece of the puzzle that
was always missing - there was simply no way for walking
the ladder for drivers, so FWIW:
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions
@ 2014-02-12 17:16 Ulf Hansson
  2014-02-24 13:19 ` Linus Walleij
  0 siblings, 1 reply; 6+ messages in thread
From: Ulf Hansson @ 2014-02-12 17:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Len Brown, Pavel Machek, linux-pm
  Cc: Ulf Hansson, Kevin Hilman, Alan Stern, Greg Kroah-Hartman,
	Mark Brown, Russell King, Linus Walleij

This patch provides two new runtime PM helper functions which intend to
be used from system suspend/resume callbacks, to make sure devices are
put into low power state during system suspend and brought back to full
power at system resume.

The prerequisite is to have all levels of a device's runtime PM
callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which
means these are available for CONFIG_PM.

By using the new runtime PM helper functions especially the two
scenarios below will be addressed.

1) The PM core prevents .runtime_suspend callbacks from being invoked
during system suspend. That means even for a runtime PM centric
subsystem and driver, the device needs to be put into low power state
from a system suspend callback. Otherwise it may very well be left in
full power state (runtime resumed) while the system is suspended. By
using the new helper functions, we make sure to walk the hierarchy of
a device's power domain, subsystem and driver.

2) Subsystems and drivers need to cope with all the combinations of
CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions
smothly addresses this.

Cc: Kevin Hilman <khilman@linaro.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Mark Brown <broonie@linaro.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/base/power/Makefile  |    3 +-
 drivers/base/power/runtime.c |  110 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/pm_runtime.h   |    4 ++
 3 files changed, 115 insertions(+), 2 deletions(-)

diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 2e58ebb..1cb8544 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,6 +1,5 @@
-obj-$(CONFIG_PM)	+= sysfs.o generic_ops.o common.o qos.o
+obj-$(CONFIG_PM)	+= sysfs.o generic_ops.o common.o qos.o runtime.o
 obj-$(CONFIG_PM_SLEEP)	+= main.o wakeup.o
-obj-$(CONFIG_PM_RUNTIME)	+= runtime.o
 obj-$(CONFIG_PM_TRACE_RTC)	+= trace.o
 obj-$(CONFIG_PM_OPP)	+= opp.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS)	+=  domain.o domain_governor.o
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 72e00e6..959c478 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -13,6 +13,7 @@
 #include <trace/events/rpm.h>
 #include "power.h"
 
+#ifdef CONFIG_PM_RUNTIME
 static int rpm_resume(struct device *dev, int rpmflags);
 static int rpm_suspend(struct device *dev, int rpmflags);
 
@@ -1401,3 +1402,112 @@ void pm_runtime_remove(struct device *dev)
 	if (dev->power.irq_safe && dev->parent)
 		pm_runtime_put(dev->parent);
 }
+#endif
+
+#ifdef CONFIG_PM
+/**
+ * pm_runtime_force_suspend - Force a device into suspend state if needed.
+ * @dev: Device to suspend.
+ *
+ * Disable runtime PM so we safely can check the device's runtime PM status and
+ * if it is active, invoke it's .runtime_suspend callback to bring it into
+ * suspend state. Keep runtime PM disabled to preserve the state unless we
+ * encounter errors.
+ *
+ * Typically this function may be invoked from a system suspend callback to make
+ * sure the device is put into low power state.
+ */
+int pm_runtime_force_suspend(struct device *dev)
+{
+	int (*callback)(struct device *);
+	int ret = 0;
+
+	pm_runtime_disable(dev);
+
+	/*
+	 * Note that pm_runtime_status_suspended() returns false while
+	 * !CONFIG_PM_RUNTIME, which means the device will be put into low
+	 * power state.
+	 */
+	if (pm_runtime_status_suspended(dev))
+		return 0;
+
+	if (dev->pm_domain)
+		callback = dev->pm_domain->ops.runtime_suspend;
+	else if (dev->type && dev->type->pm)
+		callback = dev->type->pm->runtime_suspend;
+	else if (dev->class && dev->class->pm)
+		callback = dev->class->pm->runtime_suspend;
+	else if (dev->bus && dev->bus->pm)
+		callback = dev->bus->pm->runtime_suspend;
+	else
+		callback = NULL;
+
+	if (!callback && dev->driver && dev->driver->pm)
+		callback = dev->driver->pm->runtime_suspend;
+
+	if (!callback) {
+		ret = -ENOSYS;
+		goto err;
+	}
+
+	ret = callback(dev);
+	if (ret)
+		goto err;
+
+	pm_runtime_set_suspended(dev);
+	return 0;
+err:
+	pm_runtime_enable(dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
+
+/**
+ * pm_runtime_force_resume - Force a device into resume state.
+ * @dev: Device to resume.
+ *
+ * Prior invoking this function we expect the user to have brought the device
+ * into low power state by a call to pm_runtime_force_suspend(). Here we reverse
+ * those actions and brings the device into full power. We update the runtime PM
+ * status and re-enables runtime PM.
+ *
+ * Typically this function may be invoked from a system resume callback to make
+ * sure the device is put into full power state.
+ */
+int pm_runtime_force_resume(struct device *dev)
+{
+	int (*callback)(struct device *);
+	int ret = 0;
+
+	if (dev->pm_domain)
+		callback = dev->pm_domain->ops.runtime_resume;
+	else if (dev->type && dev->type->pm)
+		callback = dev->type->pm->runtime_resume;
+	else if (dev->class && dev->class->pm)
+		callback = dev->class->pm->runtime_resume;
+	else if (dev->bus && dev->bus->pm)
+		callback = dev->bus->pm->runtime_resume;
+	else
+		callback = NULL;
+
+	if (!callback && dev->driver && dev->driver->pm)
+		callback = dev->driver->pm->runtime_resume;
+
+	if (!callback) {
+		ret = -ENOSYS;
+		goto out;
+	}
+
+	ret = callback(dev);
+	if (ret)
+		goto out;
+
+	pm_runtime_set_active(dev);
+	pm_runtime_mark_last_busy(dev);
+out:
+	pm_runtime_enable(dev);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
+#endif
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 16c9a62..2a5897a 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -26,9 +26,13 @@
 #ifdef CONFIG_PM
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
+extern int pm_runtime_force_suspend(struct device *dev);
+extern int pm_runtime_force_resume(struct device *dev);
 #else
 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
+static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
+static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
 #endif
 
 #ifdef CONFIG_PM_RUNTIME
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-02-24 13:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-13  9:01 [PATCH] PM / Sleep / Runtime: Add pm_runtime_suspend|resume_force functions Ulf Hansson
2014-02-19 20:59 ` Alan Stern
2014-02-20  1:27   ` Rafael J. Wysocki
2014-02-20  9:28     ` Ulf Hansson
  -- strict thread matches above, loose matches on Subject: below --
2014-02-12 17:16 Ulf Hansson
2014-02-24 13:19 ` Linus Walleij

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.