| From cc85b20780562d404e18a47b9b55b4a5102ae53e Mon Sep 17 00:00:00 2001 |
| From: "Rafael J. Wysocki" <rjw@sisk.pl> |
| Date: Tue, 13 Mar 2012 22:39:31 +0100 |
| Subject: PM / Domains: Fix handling of wakeup devices during system resume |
| |
| From: "Rafael J. Wysocki" <rjw@sisk.pl> |
| |
| commit cc85b20780562d404e18a47b9b55b4a5102ae53e upstream. |
| |
| During system suspend pm_genpd_suspend_noirq() checks if the given |
| device is in a wakeup path (i.e. it appears to be needed for one or |
| more wakeup devices to work or is a wakeup device itself) and if it |
| needs to be "active" for wakeup to work. If that is the case, the |
| function returns 0 without incrementing the device domain's counter |
| of suspended devices and without executing genpd_stop_dev() for the |
| device. In consequence, the device is not stopped (e.g. its clock |
| isn't disabled) and power is always supplied to its domain in the |
| resulting system sleep state. |
| |
| However, pm_genpd_resume_noirq() doesn't repeat that check and it |
| runs genpd_start_dev() and decrements the domain's counter of |
| suspended devices even for the wakeup device that weren't stopped by |
| pm_genpd_suspend_noirq(). As a result, the start callback may be run |
| unnecessarily for them and their domains' counters of suspended |
| devices may become negative. Both outcomes aren't desirable, so fix |
| pm_genpd_resume_noirq() to look for wakeup devices that might not be |
| stopped by during system suspend. |
| |
| Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> |
| Tested-by: Simon Horman <horms@verge.net.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/base/power/domain.c | 3 ++- |
| 1 file changed, 2 insertions(+), 1 deletion(-) |
| |
| --- a/drivers/base/power/domain.c |
| +++ b/drivers/base/power/domain.c |
| @@ -751,7 +751,8 @@ static int pm_genpd_resume_noirq(struct |
| if (IS_ERR(genpd)) |
| return -EINVAL; |
| |
| - if (genpd->suspend_power_off) |
| + if (genpd->suspend_power_off |
| + || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))) |
| return 0; |
| |
| /* |