@@ -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;
@@ -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.
@@ -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;
@@ -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) {}