===================================================================
@@ -521,6 +521,9 @@ static int device_resume(struct device *
if (!dev->power.is_suspended)
goto Unlock;
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+
if (dev->pwr_domain) {
pm_dev_dbg(dev, state, "power domain ");
error = pm_op(dev, &dev->pwr_domain->ops, state);
@@ -557,6 +560,7 @@ static int device_resume(struct device *
End:
dev->power.is_suspended = false;
+ pm_runtime_put_noidle(dev);
Unlock:
device_unlock(dev);
@@ -888,7 +892,10 @@ static int __device_suspend(struct devic
}
End:
- dev->power.is_suspended = !error;
+ if (!error) {
+ dev->power.is_suspended = true;
+ __pm_runtime_disable(dev, PRD_DEPTH);
+ }
Unlock:
device_unlock(dev);
===================================================================
@@ -455,12 +455,14 @@ static int rpm_resume(struct device *dev
dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
repeat:
- if (dev->power.runtime_error)
+ if (dev->power.runtime_error) {
retval = -EINVAL;
- else if (dev->power.disable_depth > 0)
- retval = -EAGAIN;
- if (retval)
goto out;
+ } else if (dev->power.disable_depth > 0) {
+ if (!(rpmflags & RPM_GET_PUT))
+ retval = -EAGAIN;
+ goto out;
+ }
/*
* Other scheduled or pending requests need to be canceled. Small
@@ -965,18 +967,23 @@ EXPORT_SYMBOL_GPL(pm_runtime_barrier);
/**
* __pm_runtime_disable - Disable run-time PM of a device.
* @dev: Device to handle.
- * @check_resume: If set, check if there's a resume request for the device.
+ * @level: How much to do.
+ *
+ * Increment power.disable_depth for the device and if was zero previously.
+ *
+ * If @level is at least PRD_BARRIER, additionally cancel all pending run-time
+ * PM requests for the device and wait for all operations in progress to
+ * complete.
+ *
+ * If @level is at least PRD_CHECK_RESUME and there's a resume request pending
+ * when this function is called, and power.disable_depth is zero, the device
+ * will be woken up before disabling its run-time PM.
+ *
+ * The device can be either active or suspended after its run-time PM has been
+ * disabled.
*
- * Increment power.disable_depth for the device and if was zero previously,
- * cancel all pending run-time PM requests for the device and wait for all
- * operations in progress to complete. The device can be either active or
- * suspended after its run-time PM has been disabled.
- *
- * If @check_resume is set and there's a resume request pending when
- * __pm_runtime_disable() is called and power.disable_depth is zero, the
- * function will wake up the device before disabling its run-time PM.
*/
-void __pm_runtime_disable(struct device *dev, bool check_resume)
+void __pm_runtime_disable(struct device *dev, enum prd_level level)
{
spin_lock_irq(&dev->power.lock);
@@ -990,7 +997,7 @@ void __pm_runtime_disable(struct device
* means there probably is some I/O to process and disabling run-time PM
* shouldn't prevent the device from processing the I/O.
*/
- if (check_resume && dev->power.request_pending
+ if (level >= PRD_CHECK_RESUME && dev->power.request_pending
&& dev->power.request == RPM_REQ_RESUME) {
/*
* Prevent suspends and idle notifications from being carried
@@ -1003,7 +1010,7 @@ void __pm_runtime_disable(struct device
pm_runtime_put_noidle(dev);
}
- if (!dev->power.disable_depth++)
+ if (!dev->power.disable_depth++ && level >= PRD_BARRIER)
__pm_runtime_barrier(dev);
out:
@@ -1230,7 +1237,7 @@ void pm_runtime_init(struct device *dev)
*/
void pm_runtime_remove(struct device *dev)
{
- __pm_runtime_disable(dev, false);
+ __pm_runtime_disable(dev, PRD_BARRIER);
/* Change the status back to 'suspended' to match the initial status. */
if (dev->power.runtime_status == RPM_ACTIVE)
===================================================================
@@ -22,6 +22,13 @@
usage_count */
#define RPM_AUTO 0x08 /* Use autosuspend_delay */
+/* Runtime PM disable levels */
+enum prd_level {
+ PRD_DEPTH = 0, /* Only increment disable depth */
+ PRD_BARRIER, /* Additionally, act as a runtime PM barrier */
+ PRD_CHECK_RESUME, /* Additionally, check if resume is pending */
+};
+
#ifdef CONFIG_PM_RUNTIME
extern struct workqueue_struct *pm_wq;
@@ -33,7 +40,7 @@ extern int pm_schedule_suspend(struct de
extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
extern int pm_runtime_barrier(struct device *dev);
extern void pm_runtime_enable(struct device *dev);
-extern void __pm_runtime_disable(struct device *dev, bool check_resume);
+extern void __pm_runtime_disable(struct device *dev, enum prd_level level);
extern void pm_runtime_allow(struct device *dev);
extern void pm_runtime_forbid(struct device *dev);
extern int pm_generic_runtime_idle(struct device *dev);
@@ -119,7 +126,7 @@ static inline int __pm_runtime_set_statu
unsigned int status) { return 0; }
static inline int pm_runtime_barrier(struct device *dev) { return 0; }
static inline void pm_runtime_enable(struct device *dev) {}
-static inline void __pm_runtime_disable(struct device *dev, bool c) {}
+static inline void __pm_runtime_disable(struct device *dev, enum prd_level l) {}
static inline void pm_runtime_allow(struct device *dev) {}
static inline void pm_runtime_forbid(struct device *dev) {}
@@ -232,7 +239,7 @@ static inline void pm_runtime_set_suspen
static inline void pm_runtime_disable(struct device *dev)
{
- __pm_runtime_disable(dev, true);
+ __pm_runtime_disable(dev, PRD_CHECK_RESUME);
}
static inline void pm_runtime_use_autosuspend(struct device *dev)