===================================================================
@@ -574,6 +574,7 @@ struct dev_pm_info {
unsigned int use_autosuspend:1;
unsigned int timer_autosuspends:1;
unsigned int memalloc_noio:1;
+ bool direct_resume:1; /* For system suspend */
enum rpm_request request;
enum rpm_status runtime_status;
int runtime_error;
===================================================================
@@ -57,6 +57,7 @@ extern unsigned long pm_runtime_autosusp
extern void pm_runtime_update_max_time_suspended(struct device *dev,
s64 delta_ns);
extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable);
+extern void pm_set_direct_resume(struct device *dev, bool val);
static inline bool pm_children_suspended(struct device *dev)
{
@@ -116,6 +117,15 @@ static inline void pm_runtime_mark_last_
ACCESS_ONCE(dev->power.last_busy) = jiffies;
}
+static inline void __set_direct_resume(struct device *dev, bool val)
+{
+ dev->power.direct_resume = val;
+}
+
+static inline bool pm_direct_resume_is_set(struct device *dev)
+{
+ return dev->power.direct_resume;
+}
#else /* !CONFIG_PM_RUNTIME */
static inline int __pm_runtime_idle(struct device *dev, int rpmflags)
@@ -165,6 +175,9 @@ static inline unsigned long pm_runtime_a
struct device *dev) { return 0; }
static inline void pm_runtime_set_memalloc_noio(struct device *dev,
bool enable){}
+static inline void __set_direct_resume(struct device *dev, bool val) {}
+static inline void pm_set_direct_resume(struct device *dev, bool val) {}
+static inline bool pm_direct_resume_is_set(struct device *dev) { return false; }
#endif /* !CONFIG_PM_RUNTIME */
===================================================================
@@ -732,6 +732,7 @@ static int rpm_resume(struct device *dev
}
skip_parent:
+ __set_direct_resume(dev, false);
if (dev->power.no_callbacks)
goto no_callback; /* Assume success. */
@@ -1485,3 +1486,10 @@ out:
return ret;
}
EXPORT_SYMBOL_GPL(pm_runtime_force_resume);
+
+void pm_set_direct_resume(struct device *dev, bool val)
+{
+ spin_lock_irq(&dev->power.lock);
+ __set_direct_resume(dev, val);
+ spin_unlock_irq(&dev->power.lock);
+}
===================================================================
@@ -479,7 +479,7 @@ static int device_resume_noirq(struct de
TRACE_DEVICE(dev);
TRACE_RESUME(0);
- if (dev->power.syscore)
+ if (dev->power.syscore || pm_direct_resume_is_set(dev))
goto Out;
if (!dev->power.is_noirq_suspended)
@@ -605,7 +605,7 @@ static int device_resume_early(struct de
TRACE_DEVICE(dev);
TRACE_RESUME(0);
- if (dev->power.syscore)
+ if (dev->power.syscore || pm_direct_resume_is_set(dev))
goto Out;
if (!dev->power.is_late_suspended)
@@ -1007,7 +1007,7 @@ static int __device_suspend_noirq(struct
goto Complete;
}
- if (dev->power.syscore)
+ if (dev->power.syscore || pm_direct_resume_is_set(dev))
goto Complete;
dpm_wait_for_children(dev, async);
@@ -1146,7 +1146,7 @@ static int __device_suspend_late(struct
goto Complete;
}
- if (dev->power.syscore)
+ if (dev->power.syscore || pm_direct_resume_is_set(dev))
goto Complete;
dpm_wait_for_children(dev, async);
@@ -1382,10 +1382,21 @@ static int __device_suspend(struct devic
End:
if (!error) {
+ struct device *parent = dev->parent;
+
dev->power.is_suspended = true;
- if (dev->power.wakeup_path
- && dev->parent && !dev->parent->power.ignore_children)
- dev->parent->power.wakeup_path = true;
+ if (parent) {
+ spin_lock_irq(&parent->power.lock);
+
+ if (dev->power.wakeup_path
+ && !parent->power.ignore_children)
+ parent->power.wakeup_path = true;
+
+ if (!pm_direct_resume_is_set(dev))
+ __set_direct_resume(parent, false);
+
+ spin_unlock_irq(&parent->power.lock);
+ }
}
device_unlock(dev);
@@ -1553,6 +1564,7 @@ int dpm_prepare(pm_message_t state)
struct device *dev = to_device(dpm_list.next);
get_device(dev);
+ pm_set_direct_resume(dev, false);
mutex_unlock(&dpm_list_mtx);
error = device_prepare(dev, state);