aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-07 05:33:49 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-11-08 06:14:51 -0500
commit0759e80b84e34a84e7e46e2b1adb528c83d84a47 (patch)
treeffd28668a079d909242da53cdd4cc71855a0bb3e
parent31f18230e480d6224e71910e9ab43a097d811fb0 (diff)
PM / QoS: Fix device resume latency framework
The special value of 0 for device resume latency PM QoS means "no restriction", but there are two problems with that. First, device resume latency PM QoS requests with 0 as the value are always put in front of requests with positive values in the priority lists used internally by the PM QoS framework, causing 0 to be chosen as an effective constraint value. However, that 0 is then interpreted as "no restriction" effectively overriding the other requests with specific restrictions which is incorrect. Second, the users of device resume latency PM QoS have no way to specify that *any* resume latency at all should be avoided, which is an artificial limitation in general. To address these issues, modify device resume latency PM QoS to use S32_MAX as the "no constraint" value and 0 as the "no latency at all" one and rework its users (the cpuidle menu governor, the genpd QoS governor and the runtime PM framework) to follow these changes. Also add a special "n/a" value to the corresponding user space I/F to allow user space to indicate that it cannot accept any resume latencies at all for the given device. Fixes: 85dc0b8a4019 (PM / QoS: Make it possible to expose PM QoS latency constraints) Link: https://bugzilla.kernel.org/show_bug.cgi?id=197323 Reported-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Tested-by: Reinette Chatre <reinette.chatre@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--Documentation/ABI/testing/sysfs-devices-power4
-rw-r--r--drivers/base/cpu.c3
-rw-r--r--drivers/base/power/domain.c2
-rw-r--r--drivers/base/power/domain_governor.c40
-rw-r--r--drivers/base/power/qos.c5
-rw-r--r--drivers/base/power/runtime.c2
-rw-r--r--drivers/base/power/sysfs.c25
-rw-r--r--drivers/cpuidle/governors/menu.c4
-rw-r--r--include/linux/pm_qos.h26
9 files changed, 68 insertions, 43 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index f4b24c327665..80a00f7b6667 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -211,7 +211,9 @@ Description:
211 device, after it has been suspended at run time, from a resume 211 device, after it has been suspended at run time, from a resume
212 request to the moment the device will be ready to process I/O, 212 request to the moment the device will be ready to process I/O,
213 in microseconds. If it is equal to 0, however, this means that 213 in microseconds. If it is equal to 0, however, this means that
214 the PM QoS resume latency may be arbitrary. 214 the PM QoS resume latency may be arbitrary and the special value
215 "n/a" means that user space cannot accept any resume latency at
216 all for the given device.
215 217
216 Not all drivers support this attribute. If it isn't supported, 218 Not all drivers support this attribute. If it isn't supported,
217 it is not present. 219 it is not present.
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 321cd7b4d817..227bac5f1191 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -377,7 +377,8 @@ int register_cpu(struct cpu *cpu, int num)
377 377
378 per_cpu(cpu_sys_devices, num) = &cpu->dev; 378 per_cpu(cpu_sys_devices, num) = &cpu->dev;
379 register_cpu_under_node(num, cpu_to_node(num)); 379 register_cpu_under_node(num, cpu_to_node(num));
380 dev_pm_qos_expose_latency_limit(&cpu->dev, 0); 380 dev_pm_qos_expose_latency_limit(&cpu->dev,
381 PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
381 382
382 return 0; 383 return 0;
383} 384}
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 679c79545e42..24e39ce27bd8 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1326,7 +1326,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
1326 1326
1327 gpd_data->base.dev = dev; 1327 gpd_data->base.dev = dev;
1328 gpd_data->td.constraint_changed = true; 1328 gpd_data->td.constraint_changed = true;
1329 gpd_data->td.effective_constraint_ns = 0; 1329 gpd_data->td.effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
1330 gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; 1330 gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
1331 1331
1332 spin_lock_irq(&dev->power.lock); 1332 spin_lock_irq(&dev->power.lock);
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index e4cca8adab32..99896fbf18e4 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -33,15 +33,10 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
33 * known at this point anyway). 33 * known at this point anyway).
34 */ 34 */
35 constraint_ns = dev_pm_qos_read_value(dev); 35 constraint_ns = dev_pm_qos_read_value(dev);
36 if (constraint_ns > 0) 36 constraint_ns *= NSEC_PER_USEC;
37 constraint_ns *= NSEC_PER_USEC;
38 } 37 }
39 38
40 /* 0 means "no constraint" */ 39 if (constraint_ns < *constraint_ns_p)
41 if (constraint_ns == 0)
42 return 0;
43
44 if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
45 *constraint_ns_p = constraint_ns; 40 *constraint_ns_p = constraint_ns;
46 41
47 return 0; 42 return 0;
@@ -69,12 +64,12 @@ static bool default_suspend_ok(struct device *dev)
69 } 64 }
70 td->constraint_changed = false; 65 td->constraint_changed = false;
71 td->cached_suspend_ok = false; 66 td->cached_suspend_ok = false;
72 td->effective_constraint_ns = -1; 67 td->effective_constraint_ns = 0;
73 constraint_ns = __dev_pm_qos_read_value(dev); 68 constraint_ns = __dev_pm_qos_read_value(dev);
74 69
75 spin_unlock_irqrestore(&dev->power.lock, flags); 70 spin_unlock_irqrestore(&dev->power.lock, flags);
76 71
77 if (constraint_ns < 0) 72 if (constraint_ns == 0)
78 return false; 73 return false;
79 74
80 constraint_ns *= NSEC_PER_USEC; 75 constraint_ns *= NSEC_PER_USEC;
@@ -87,25 +82,25 @@ static bool default_suspend_ok(struct device *dev)
87 device_for_each_child(dev, &constraint_ns, 82 device_for_each_child(dev, &constraint_ns,
88 dev_update_qos_constraint); 83 dev_update_qos_constraint);
89 84
90 if (constraint_ns == 0) { 85 if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) {
91 /* "No restriction", so the device is allowed to suspend. */ 86 /* "No restriction", so the device is allowed to suspend. */
92 td->effective_constraint_ns = 0; 87 td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS;
93 td->cached_suspend_ok = true; 88 td->cached_suspend_ok = true;
94 } else if (constraint_ns < 0) { 89 } else if (constraint_ns == 0) {
95 /* 90 /*
96 * This triggers if one of the children that don't belong to a 91 * 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 92 * domain has a zero PM QoS constraint and it's better not to
98 * to suspend then. effective_constraint_ns is negative already 93 * suspend then. effective_constraint_ns is zero already and
99 * and cached_suspend_ok is false, so bail out. 94 * cached_suspend_ok is false, so bail out.
100 */ 95 */
101 return false; 96 return false;
102 } else { 97 } else {
103 constraint_ns -= td->suspend_latency_ns + 98 constraint_ns -= td->suspend_latency_ns +
104 td->resume_latency_ns; 99 td->resume_latency_ns;
105 /* 100 /*
106 * effective_constraint_ns is negative already and 101 * effective_constraint_ns is zero already and cached_suspend_ok
107 * cached_suspend_ok is false, so if the computed value is not 102 * is false, so if the computed value is not positive, return
108 * positive, return right away. 103 * right away.
109 */ 104 */
110 if (constraint_ns <= 0) 105 if (constraint_ns <= 0)
111 return false; 106 return false;
@@ -174,13 +169,10 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
174 td = &to_gpd_data(pdd)->td; 169 td = &to_gpd_data(pdd)->td;
175 constraint_ns = td->effective_constraint_ns; 170 constraint_ns = td->effective_constraint_ns;
176 /* 171 /*
177 * Negative values mean "no suspend at all" and this runs only 172 * Zero means "no suspend at all" and this runs only when all
178 * when all devices in the domain are suspended, so it must be 173 * devices in the domain are suspended, so it must be positive.
179 * 0 at least.
180 *
181 * 0 means "no constraint"
182 */ 174 */
183 if (constraint_ns == 0) 175 if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS)
184 continue; 176 continue;
185 177
186 if (constraint_ns <= off_on_time_ns) 178 if (constraint_ns <= off_on_time_ns)
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 277d43a83f53..3382542b39b7 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -139,6 +139,9 @@ static int apply_constraint(struct dev_pm_qos_request *req,
139 139
140 switch(req->type) { 140 switch(req->type) {
141 case DEV_PM_QOS_RESUME_LATENCY: 141 case DEV_PM_QOS_RESUME_LATENCY:
142 if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
143 value = 0;
144
142 ret = pm_qos_update_target(&qos->resume_latency, 145 ret = pm_qos_update_target(&qos->resume_latency,
143 &req->data.pnode, action, value); 146 &req->data.pnode, action, value);
144 break; 147 break;
@@ -189,7 +192,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
189 plist_head_init(&c->list); 192 plist_head_init(&c->list);
190 c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; 193 c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
191 c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; 194 c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
192 c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; 195 c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
193 c->type = PM_QOS_MIN; 196 c->type = PM_QOS_MIN;
194 c->notifiers = n; 197 c->notifiers = n;
195 198
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 7bcf80fa9ada..13e015905543 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -253,7 +253,7 @@ static int rpm_check_suspend_allowed(struct device *dev)
253 || (dev->power.request_pending 253 || (dev->power.request_pending
254 && dev->power.request == RPM_REQ_RESUME)) 254 && dev->power.request == RPM_REQ_RESUME))
255 retval = -EAGAIN; 255 retval = -EAGAIN;
256 else if (__dev_pm_qos_read_value(dev) < 0) 256 else if (__dev_pm_qos_read_value(dev) == 0)
257 retval = -EPERM; 257 retval = -EPERM;
258 else if (dev->power.runtime_status == RPM_SUSPENDED) 258 else if (dev->power.runtime_status == RPM_SUSPENDED)
259 retval = 1; 259 retval = 1;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 29bf28fef136..e153e28b1857 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -218,7 +218,14 @@ static ssize_t pm_qos_resume_latency_show(struct device *dev,
218 struct device_attribute *attr, 218 struct device_attribute *attr,
219 char *buf) 219 char *buf)
220{ 220{
221 return sprintf(buf, "%d\n", dev_pm_qos_requested_resume_latency(dev)); 221 s32 value = dev_pm_qos_requested_resume_latency(dev);
222
223 if (value == 0)
224 return sprintf(buf, "n/a\n");
225 else if (value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
226 value = 0;
227
228 return sprintf(buf, "%d\n", value);
222} 229}
223 230
224static ssize_t pm_qos_resume_latency_store(struct device *dev, 231static ssize_t pm_qos_resume_latency_store(struct device *dev,
@@ -228,11 +235,21 @@ static ssize_t pm_qos_resume_latency_store(struct device *dev,
228 s32 value; 235 s32 value;
229 int ret; 236 int ret;
230 237
231 if (kstrtos32(buf, 0, &value)) 238 if (!kstrtos32(buf, 0, &value)) {
232 return -EINVAL; 239 /*
240 * Prevent users from writing negative or "no constraint" values
241 * directly.
242 */
243 if (value < 0 || value == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
244 return -EINVAL;
233 245
234 if (value < 0) 246 if (value == 0)
247 value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
248 } else if (!strcmp(buf, "n/a") || !strcmp(buf, "n/a\n")) {
249 value = 0;
250 } else {
235 return -EINVAL; 251 return -EINVAL;
252 }
236 253
237 ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req, 254 ret = dev_pm_qos_update_request(dev->power.qos->resume_latency_req,
238 value); 255 value);
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 48eaf2879228..aa390404e85f 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -298,8 +298,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
298 data->needs_update = 0; 298 data->needs_update = 0;
299 } 299 }
300 300
301 /* resume_latency is 0 means no restriction */ 301 if (resume_latency < latency_req &&
302 if (resume_latency && resume_latency < latency_req) 302 resume_latency != PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
303 latency_req = resume_latency; 303 latency_req = resume_latency;
304 304
305 /* Special case when user has set very strict latency requirement */ 305 /* Special case when user has set very strict latency requirement */
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 51f0d7e0b15f..2a3b36da61b1 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -27,16 +27,19 @@ enum pm_qos_flags_status {
27 PM_QOS_FLAGS_ALL, 27 PM_QOS_FLAGS_ALL,
28}; 28};
29 29
30#define PM_QOS_DEFAULT_VALUE -1 30#define PM_QOS_DEFAULT_VALUE (-1)
31#define PM_QOS_LATENCY_ANY S32_MAX
32#define PM_QOS_LATENCY_ANY_NS ((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
31 33
32#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) 34#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
33#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) 35#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
34#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 36#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
35#define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE 0 37#define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE 0
36#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0 38#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE PM_QOS_LATENCY_ANY
39#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT PM_QOS_LATENCY_ANY
40#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
37#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 41#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
38#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) 42#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
39#define PM_QOS_LATENCY_ANY ((s32)(~(__u32)0 >> 1))
40 43
41#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) 44#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0)
42 45
@@ -173,7 +176,8 @@ static inline s32 dev_pm_qos_requested_flags(struct device *dev)
173static inline s32 dev_pm_qos_raw_read_value(struct device *dev) 176static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
174{ 177{
175 return IS_ERR_OR_NULL(dev->power.qos) ? 178 return IS_ERR_OR_NULL(dev->power.qos) ?
176 0 : pm_qos_read_value(&dev->power.qos->resume_latency); 179 PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
180 pm_qos_read_value(&dev->power.qos->resume_latency);
177} 181}
178#else 182#else
179static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, 183static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
@@ -183,9 +187,9 @@ static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev,
183 s32 mask) 187 s32 mask)
184 { return PM_QOS_FLAGS_UNDEFINED; } 188 { return PM_QOS_FLAGS_UNDEFINED; }
185static inline s32 __dev_pm_qos_read_value(struct device *dev) 189static inline s32 __dev_pm_qos_read_value(struct device *dev)
186 { return 0; } 190 { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
187static inline s32 dev_pm_qos_read_value(struct device *dev) 191static inline s32 dev_pm_qos_read_value(struct device *dev)
188 { return 0; } 192 { return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
189static inline int dev_pm_qos_add_request(struct device *dev, 193static inline int dev_pm_qos_add_request(struct device *dev,
190 struct dev_pm_qos_request *req, 194 struct dev_pm_qos_request *req,
191 enum dev_pm_qos_req_type type, 195 enum dev_pm_qos_req_type type,
@@ -231,9 +235,15 @@ static inline int dev_pm_qos_expose_latency_tolerance(struct device *dev)
231 { return 0; } 235 { return 0; }
232static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {} 236static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {}
233 237
234static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; } 238static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
239{
240 return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
241}
235static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; } 242static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
236static inline s32 dev_pm_qos_raw_read_value(struct device *dev) { return 0; } 243static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
244{
245 return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
246}
237#endif 247#endif
238 248
239#endif 249#endif