diff mbox

[linux-pm] subtle pm_runtime_put_sync race and sdio functions

Message ID AANLkTi=32bqipN5U00La-B7JSgTC1bHgMev=xUSF6kRN@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ohad Ben Cohen Dec. 18, 2010, 1:29 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 31b5266..84e9263 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -694,7 +694,8 @@  static void dpm_complete(pm_message_t state)
 			mutex_unlock(&dpm_list_mtx);

 			device_complete(dev, state);
-			pm_runtime_put_sync(dev);
+			if (!dev->power.autonomous_pm)
+				pm_runtime_put_sync(dev);

 			mutex_lock(&dpm_list_mtx);
 		}
@@ -1025,8 +1026,10 @@  static int dpm_prepare(pm_message_t state)
 		dev->power.status = DPM_PREPARING;
 		mutex_unlock(&dpm_list_mtx);

-		pm_runtime_get_noresume(dev);
-		if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) {
+		if (!dev->power.autonomous_pm)
+			pm_runtime_get_noresume(dev);
+		if (!dev->power.autonomous_pm && pm_runtime_barrier(dev) &&
+						device_may_wakeup(dev)) {
 			/* Wake-up requested during system sleep transition. */
 			pm_runtime_put_sync(dev);
 			error = -EBUSY;
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 9719811..1efd528 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1078,6 +1078,23 @@  void pm_runtime_no_callbacks(struct device *dev)
 EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);

 /**
+ * pm_runtime_autonomous_pm - Don't mask runtime PM calls during system suspend
+ * @dev: Device to handle.
+ *
+ * Set the power.autonomous_pm flag, which tells PM core not to mask
+ * runtime PM calls for this device during system suspend/resume. This is
+ * generally unsafe, so it should be set only if a driver is using runtime PM
+ * very accurately, synchronously and usually with ignore_children set.
+ */
+void pm_runtime_autonomous_pm(struct device *dev)
+{
+	spin_lock_irq(&dev->power.lock);
+	dev->power.autonomous_pm = 1;
+	spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_autonomous_pm);
+
+/**
  * update_autosuspend - Handle a change to a device's autosuspend settings.
  * @dev: Device to handle.
  * @old_delay: The former autosuspend_delay value.
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 40f3f45..e550775 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -488,6 +488,7 @@  struct dev_pm_info {
 	unsigned int		no_callbacks:1;
 	unsigned int		use_autosuspend:1;
 	unsigned int		timer_autosuspends:1;
+	unsigned int		autonomous_pm:1;
 	enum rpm_request	request;
 	enum rpm_status		runtime_status;
 	int			runtime_error;
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 3ec2358..4130e54 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -43,6 +43,7 @@  extern void pm_runtime_no_callbacks(struct device *dev);
 extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
 extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
 extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
+extern void pm_runtime_autonomous_pm(struct device *dev);

 static inline bool pm_children_suspended(struct device *dev)
 {
@@ -123,6 +124,7 @@  static inline int pm_generic_runtime_idle(struct
device *dev) { return 0; }
 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 void pm_runtime_no_callbacks(struct device *dev) {}
+static inline void pm_runtime_autonomous_pm(struct device *dev) {}

 static inline void pm_runtime_mark_last_busy(struct device *dev) {}