Commit 4ca46ff3 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

PM / Sleep: Mark devices involved in wakeup signaling during suspend

The generic PM domains code in drivers/base/power/domain.c has
to avoid powering off domains that provide power to wakeup devices
during system suspend.  Currently, however, this only works for
wakeup devices directly belonging to the given domain and not for
their children (or the children of their children and so on).
Thus, if there's a wakeup device whose parent belongs to a power
domain handled by the generic PM domains code, the domain will be
powered off during system suspend preventing the device from
signaling wakeup.

To address this problem introduce a device flag, power.wakeup_path,
that will be set during system suspend for all wakeup devices,
their parents, the parents of their parents and so on.  This way,
all wakeup paths in the device hierarchy will be marked and the
generic PM domains code will only need to avoid powering off
domains containing devices whose power.wakeup_path is set.
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent cd0ea672
...@@ -714,7 +714,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) ...@@ -714,7 +714,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
if (ret) if (ret)
return ret; return ret;
if (device_may_wakeup(dev) if (dev->power.wakeup_path
&& genpd->active_wakeup && genpd->active_wakeup(dev)) && genpd->active_wakeup && genpd->active_wakeup(dev))
return 0; return 0;
...@@ -938,7 +938,7 @@ static int pm_genpd_dev_poweroff_noirq(struct device *dev) ...@@ -938,7 +938,7 @@ static int pm_genpd_dev_poweroff_noirq(struct device *dev)
if (ret) if (ret)
return ret; return ret;
if (device_may_wakeup(dev) if (dev->power.wakeup_path
&& genpd->active_wakeup && genpd->active_wakeup(dev)) && genpd->active_wakeup && genpd->active_wakeup(dev))
return 0; return 0;
......
...@@ -902,7 +902,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) ...@@ -902,7 +902,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
} }
End: End:
dev->power.is_suspended = !error; if (!error) {
dev->power.is_suspended = true;
if (dev->power.wakeup_path && dev->parent)
dev->parent->power.wakeup_path = true;
}
device_unlock(dev); device_unlock(dev);
complete_all(&dev->power.completion); complete_all(&dev->power.completion);
...@@ -999,6 +1003,8 @@ static int device_prepare(struct device *dev, pm_message_t state) ...@@ -999,6 +1003,8 @@ static int device_prepare(struct device *dev, pm_message_t state)
device_lock(dev); device_lock(dev);
dev->power.wakeup_path = device_may_wakeup(dev);
if (dev->pm_domain) { if (dev->pm_domain) {
pm_dev_dbg(dev, state, "preparing power domain "); pm_dev_dbg(dev, state, "preparing power domain ");
if (dev->pm_domain->ops.prepare) if (dev->pm_domain->ops.prepare)
......
...@@ -448,6 +448,7 @@ struct dev_pm_info { ...@@ -448,6 +448,7 @@ struct dev_pm_info {
struct list_head entry; struct list_head entry;
struct completion completion; struct completion completion;
struct wakeup_source *wakeup; struct wakeup_source *wakeup;
bool wakeup_path:1;
#else #else
unsigned int should_wakeup:1; unsigned int should_wakeup:1;
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment