Re: runtime PM: common hooks for static and runtime PM

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 6 Feb 2010, Alan Stern wrote:

> On Sat, 6 Feb 2010, Mark Brown wrote:
> 
> > On Fri, Feb 05, 2010 at 09:57:46PM -0500, Alan Stern wrote:
> > > On Fri, 5 Feb 2010, Mark Brown wrote:
> > 
> > > > It's not that it's hard per se, it's that it feels like it's peering
> > > > inside the implementation of the API.  Having the PM core provide
> > 
> > > You mean like providing an is_runtime_suspended() test?  Then you could 
> > > write:
> > 
> > > 	int my_suspend(struct device *dev)
> > > 	{
> > > 		if (is_runtime_suspended(dev))
> > > 			return 0;
> > > 		return my_runtime_suspend(dev);
> > > 	}
> > 
> > > Or maybe you'd prefer to see a convenient pm_use_runtime_suspend() 
> > > function that you could use for your dev_pm_ops.suspend pointer, which 
> > > would do essentially the same as the above?  (Along with a 
> > > corresponding pm_use_runtime_resume() function, of course.)
> > 
> > Either (or both, of course - implementing the second would probably
> > imply the former).  The ops that can be assigned would be the clearest
> > option but the accessor function should be enough to make it clear that
> > this is something drivers are supposed to be doing.
> 
> Providing the new ops would be a little awkward because 
> CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME are independent: Either can be 
> enabled without the other.  This means the code to call the 
> runtime_suspend and runtime_resume methods would have to be split out 
> into a separate source file that would get built whenever either config 
> option is enabled.  It's doable, just somewhat awkward.
> 
> I'll give it a try and we'll see how it turns out...

And here it is.  You can see that the patch isn't ideal.

Anyway, it should do what you want -- I haven't tested it.

Alan Stern


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,8 +523,15 @@ 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 */
 
+void rpm_invoke_runtime_idle(struct device *dev);
+int rpm_invoke_runtime_suspend(struct device *dev);
+int rpm_invoke_runtime_resume(struct device *dev);
+
 /* How to reorder dpm_list after device_move() */
 enum dpm_order {
 	DPM_ORDER_NONE,
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/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,52 @@ void __suspend_report_result(const char 
 		printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
 }
 EXPORT_SYMBOL_GPL(__suspend_report_result);
+
+/* 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)
+{
+	int retval;
+
+	if (pm_is_runtime_suspended(dev))
+		return 0;
+	retval = rpm_invoke_runtime_suspend(dev);
+	if (retval == -ENOSYS)
+		retval = 0;
+	return retval;
+}
+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 = rpm_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);
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
@@ -79,26 +79,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);
+	rpm_invoke_runtime_idle(dev);
+	spin_lock_irq(&dev->power.lock);
 
 	dev->power.idle_notification = false;
 	wake_up_all(&dev->power.wait_queue);
@@ -200,32 +183,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 = rpm_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 +343,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 = rpm_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/runtime.c - Helper functions for device run-time PM
+ *
+ * Copyright (c) 2009 Rafael J. Wysocki <rjw@xxxxxxx>, Novell Inc.
+ * Copyright (c) 2010 Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
+ *
+ * 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.
+ */
+
+/**
+ * rpm_invoke_runtime_idle - Invoke a device's runtime PM idle method(s)
+ * @dev: Device to handle.
+ */
+void rpm_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);
+	}
+}
+
+/**
+ * rpm_invoke_runtime_suspend - Invoke a device's runtime PM suspend method(s)
+ * @dev: Device to handle.
+ */
+int rpm_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;
+}
+
+/**
+ * rpm_invoke_runtime_resume - Invoke a device's runtime PM resume method(s)
+ * @dev: Device to handle.
+ */
+int rpm_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
 

_______________________________________________
linux-pm mailing list
linux-pm@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/linux-pm

[Index of Archives]     [Linux ACPI]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [CPU Freq]     [Kernel Newbies]     [Fedora Kernel]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux