PM / Sleep: Mark devices involved in wakeup signaling during suspend
authorRafael J. Wysocki <rjw@sisk.pl>
Sun, 16 Oct 2011 21:34:36 +0000 (23:34 +0200)
committerRafael J. Wysocki <rjw@sisk.pl>
Fri, 21 Oct 2011 22:19:29 +0000 (00:19 +0200)
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>
drivers/base/power/domain.c
drivers/base/power/main.c
include/linux/pm.h

index 22fe029ca212dba76dc0fb45471a41dcd73f1626..6790cf7eba5a697a12b81454a27fb811a5695ec3 100644 (file)
@@ -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;
 
index a85459126bc6a5ef9cdb737140353084d0bd8c3e..1e15732c12c49b5f62c2b9a7cdef81be803d01e5 100644 (file)
@@ -902,7 +902,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);
@@ -999,6 +1003,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)
index f25682477f087fad80cb3acd000cc4127e493cbc..74711a9c2f6995b7b260eac16d413b1882d479c3 100644 (file)
@@ -448,6 +448,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