aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-06 20:23:18 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-08 06:13:13 -0500
commit704d2ce6603f7e40bb607ae9452ff18a4cec701f (patch)
tree134d75b247848b052f99fd5553a4bcf613de651b
parentd0af45f1f6528949e05385976eb61c5ebd31854e (diff)
PM / domains: Rework governor code to be more consistent
The genpd governor currently uses negative PM QoS values to indicate the "no suspend" condition and 0 as "no restriction", but it doesn't use them consistently. Moreover, it tries to refresh QoS values for already suspended devices in a quite questionable way. For the above reasons, rework it to be a bit more consistent. First off, note that dev_pm_qos_read_value() in dev_update_qos_constraint() and __default_power_down_ok() is evaluated for devices in suspend. Moreover, that only happens if the effective_constraint_ns value for them is negative (meaning "no suspend"). It is not evaluated in any other cases, so effectively the QoS values are only updated for devices in suspend that should not have been suspended in the first place. In all of the other cases, the QoS values taken into account are the effective ones from the time before the device has been suspended, so generally devices need to be resumed and suspended again for new QoS values to take effect anyway. Thus evaluating dev_update_qos_constraint() in those two places doesn't make sense at all, so drop it. Second, initialize effective_constraint_ns to 0 ("no constraint") rather than to (-1) ("no suspend"), which makes more sense in general and in case effective_constraint_ns is never updated (the device is in suspend all the time or it is never suspended) it doesn't affect the device's parent and so on. Finally, rework default_suspend_ok() to explicitly handle the "no restriction" and "no suspend" special cases. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Tested-by: Tero Kristo <t-kristo@ti.com> Reviewed-by: Ramesh Thomas <ramesh.thomas@intel.com>
-rw-r--r--drivers/base/power/domain.c2
-rw-r--r--drivers/base/power/domain_governor.c71
2 files changed, 50 insertions, 23 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 65bb40c240fb..b914e373a478 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1328,7 +1328,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
1328 1328
1329 gpd_data->base.dev = dev; 1329 gpd_data->base.dev = dev;
1330 gpd_data->td.constraint_changed = true; 1330 gpd_data->td.constraint_changed = true;
1331 gpd_data->td.effective_constraint_ns = -1; 1331 gpd_data->td.effective_constraint_ns = 0;
1332 gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; 1332 gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
1333 1333
1334 spin_lock_irq(&dev->power.lock); 1334 spin_lock_irq(&dev->power.lock);
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 281f949c5ffe..e4cca8adab32 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -14,22 +14,33 @@
14static int dev_update_qos_constraint(struct device *dev, void *data) 14static int dev_update_qos_constraint(struct device *dev, void *data)
15{ 15{
16 s64 *constraint_ns_p = data; 16 s64 *constraint_ns_p = data;
17 s32 constraint_ns = -1; 17 s64 constraint_ns;
18 18
19 if (dev->power.subsys_data && dev->power.subsys_data->domain_data) 19 if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
20 /*
21 * Only take suspend-time QoS constraints of devices into
22 * account, because constraints updated after the device has
23 * been suspended are not guaranteed to be taken into account
24 * anyway. In order for them to take effect, the device has to
25 * be resumed and suspended again.
26 */
20 constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns; 27 constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
21 28 } else {
22 if (constraint_ns < 0) { 29 /*
30 * The child is not in a domain and there's no info on its
31 * suspend/resume latencies, so assume them to be negligible and
32 * take its current PM QoS constraint (that's the only thing
33 * known at this point anyway).
34 */
23 constraint_ns = dev_pm_qos_read_value(dev); 35 constraint_ns = dev_pm_qos_read_value(dev);
24 constraint_ns *= NSEC_PER_USEC; 36 if (constraint_ns > 0)
37 constraint_ns *= NSEC_PER_USEC;
25 } 38 }
39
40 /* 0 means "no constraint" */
26 if (constraint_ns == 0) 41 if (constraint_ns == 0)
27 return 0; 42 return 0;
28 43
29 /*
30 * constraint_ns cannot be negative here, because the device has been
31 * suspended.
32 */
33 if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0) 44 if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
34 *constraint_ns_p = constraint_ns; 45 *constraint_ns_p = constraint_ns;
35 46
@@ -76,14 +87,32 @@ static bool default_suspend_ok(struct device *dev)
76 device_for_each_child(dev, &constraint_ns, 87 device_for_each_child(dev, &constraint_ns,
77 dev_update_qos_constraint); 88 dev_update_qos_constraint);
78 89
79 if (constraint_ns > 0) { 90 if (constraint_ns == 0) {
91 /* "No restriction", so the device is allowed to suspend. */
92 td->effective_constraint_ns = 0;
93 td->cached_suspend_ok = true;
94 } else if (constraint_ns < 0) {
95 /*
96 * This triggers if one of the children that don't belong to a
97 * domain has a negative PM QoS constraint and it's better not
98 * to suspend then. effective_constraint_ns is negative already
99 * and cached_suspend_ok is false, so bail out.
100 */
101 return false;
102 } else {
80 constraint_ns -= td->suspend_latency_ns + 103 constraint_ns -= td->suspend_latency_ns +
81 td->resume_latency_ns; 104 td->resume_latency_ns;
82 if (constraint_ns == 0) 105 /*
106 * effective_constraint_ns is negative already and
107 * cached_suspend_ok is false, so if the computed value is not
108 * positive, return right away.
109 */
110 if (constraint_ns <= 0)
83 return false; 111 return false;
112
113 td->effective_constraint_ns = constraint_ns;
114 td->cached_suspend_ok = true;
84 } 115 }
85 td->effective_constraint_ns = constraint_ns;
86 td->cached_suspend_ok = constraint_ns >= 0;
87 116
88 /* 117 /*
89 * The children have been suspended already, so we don't need to take 118 * The children have been suspended already, so we don't need to take
@@ -144,18 +173,16 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
144 */ 173 */
145 td = &to_gpd_data(pdd)->td; 174 td = &to_gpd_data(pdd)->td;
146 constraint_ns = td->effective_constraint_ns; 175 constraint_ns = td->effective_constraint_ns;
147 /* default_suspend_ok() need not be called before us. */ 176 /*
148 if (constraint_ns < 0) { 177 * Negative values mean "no suspend at all" and this runs only
149 constraint_ns = dev_pm_qos_read_value(pdd->dev); 178 * when all devices in the domain are suspended, so it must be
150 constraint_ns *= NSEC_PER_USEC; 179 * 0 at least.
151 } 180 *
181 * 0 means "no constraint"
182 */
152 if (constraint_ns == 0) 183 if (constraint_ns == 0)
153 continue; 184 continue;
154 185
155 /*
156 * constraint_ns cannot be negative here, because the device has
157 * been suspended.
158 */
159 if (constraint_ns <= off_on_time_ns) 186 if (constraint_ns <= off_on_time_ns)
160 return false; 187 return false;
161 188