| From 435d910aeaf727d5b6c73cc242c9c3a59f7b8917 Mon Sep 17 00:00:00 2001 |
| From: "Rafael J. Wysocki" <rjw@sisk.pl> |
| Date: Sun, 16 Oct 2011 23:34:36 +0200 |
| Subject: 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: Rafael J. Wysocki <rjw@sisk.pl> |
| (cherry picked from commit 4ca46ff3e0d8c234cb40ebb6457653b59584426c) |
| |
| Signed-off-by: Simon Horman <horms@verge.net.au> |
| --- |
| drivers/base/power/domain.c | 4 ++-- |
| drivers/base/power/main.c | 8 +++++++- |
| include/linux/pm.h | 1 + |
| 3 files changed, 10 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c |
| index 22fe029..6790cf7 100644 |
| --- a/drivers/base/power/domain.c |
| +++ b/drivers/base/power/domain.c |
| @@ -714,7 +714,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) |
| if (ret) |
| return ret; |
| |
| - if (device_may_wakeup(dev) |
| + if (dev->power.wakeup_path |
| && genpd->active_wakeup && genpd->active_wakeup(dev)) |
| return 0; |
| |
| @@ -938,7 +938,7 @@ static int pm_genpd_dev_poweroff_noirq(struct device *dev) |
| if (ret) |
| return ret; |
| |
| - if (device_may_wakeup(dev) |
| + if (dev->power.wakeup_path |
| && genpd->active_wakeup && genpd->active_wakeup(dev)) |
| return 0; |
| |
| diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c |
| index b1b5826..59f8ab2 100644 |
| --- a/drivers/base/power/main.c |
| +++ b/drivers/base/power/main.c |
| @@ -917,7 +917,11 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) |
| } |
| |
| 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); |
| complete_all(&dev->power.completion); |
| @@ -1020,6 +1024,8 @@ static int device_prepare(struct device *dev, pm_message_t state) |
| |
| device_lock(dev); |
| |
| + dev->power.wakeup_path = device_may_wakeup(dev); |
| + |
| if (dev->pm_domain) { |
| pm_dev_dbg(dev, state, "preparing power domain "); |
| if (dev->pm_domain->ops.prepare) |
| diff --git a/include/linux/pm.h b/include/linux/pm.h |
| index 91f248b..f15acb6 100644 |
| --- a/include/linux/pm.h |
| +++ b/include/linux/pm.h |
| @@ -452,6 +452,7 @@ struct dev_pm_info { |
| struct list_head entry; |
| struct completion completion; |
| struct wakeup_source *wakeup; |
| + bool wakeup_path:1; |
| #else |
| unsigned int should_wakeup:1; |
| #endif |
| -- |
| 1.7.10.1.362.g242cab3 |
| |