aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-10-24 09:20:45 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-10-24 09:20:45 -0400
commit0cc2b4e5a020fc7f4d1795741c116c983e9467d7 (patch)
tree38602fa4c8dccc952cac0b100bdd4673cf15bf79
parentbb176f67090ca54869fc1262c913aa69d2ede070 (diff)
PM / QoS: Fix device resume latency PM QoS
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> Tested-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Alex Shi <alex.shi@linaro.org> Cc: All applicable <stable@vger.kernel.org>
-rw-r--r--Documentation/ABI/testing/sysfs-devices-power4
-rw-r--r--drivers/base/cpu.c3
-rw-r--r--drivers/base/power/domain_governor.c53
-rw-r--r--drivers/base/power/qos.c2
-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.h5
8 files changed, 63 insertions, 35 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index 676fdf5f2a99..5cbb6f038615 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_governor.c b/drivers/base/power/domain_governor.c
index 281f949c5ffe..51751cc8c9e6 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -14,23 +14,20 @@
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 = -1;
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 constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns; 20 constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
21 21
22 if (constraint_ns < 0) { 22 if (constraint_ns < 0)
23 constraint_ns = dev_pm_qos_read_value(dev); 23 constraint_ns = dev_pm_qos_read_value(dev);
24 constraint_ns *= NSEC_PER_USEC; 24
25 } 25 if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
26 if (constraint_ns == 0)
27 return 0; 26 return 0;
28 27
29 /* 28 constraint_ns *= NSEC_PER_USEC;
30 * constraint_ns cannot be negative here, because the device has been 29
31 * suspended. 30 if (constraint_ns < *constraint_ns_p || *constraint_ns_p < 0)
32 */
33 if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
34 *constraint_ns_p = constraint_ns; 31 *constraint_ns_p = constraint_ns;
35 32
36 return 0; 33 return 0;
@@ -63,10 +60,14 @@ static bool default_suspend_ok(struct device *dev)
63 60
64 spin_unlock_irqrestore(&dev->power.lock, flags); 61 spin_unlock_irqrestore(&dev->power.lock, flags);
65 62
66 if (constraint_ns < 0) 63 if (constraint_ns == 0)
67 return false; 64 return false;
68 65
69 constraint_ns *= NSEC_PER_USEC; 66 if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
67 constraint_ns = -1;
68 else
69 constraint_ns *= NSEC_PER_USEC;
70
70 /* 71 /*
71 * We can walk the children without any additional locking, because 72 * We can walk the children without any additional locking, because
72 * they all have been suspended at this point and their 73 * they all have been suspended at this point and their
@@ -76,14 +77,19 @@ static bool default_suspend_ok(struct device *dev)
76 device_for_each_child(dev, &constraint_ns, 77 device_for_each_child(dev, &constraint_ns,
77 dev_update_qos_constraint); 78 dev_update_qos_constraint);
78 79
79 if (constraint_ns > 0) { 80 if (constraint_ns < 0) {
80 constraint_ns -= td->suspend_latency_ns + 81 /* The children have no constraints. */
81 td->resume_latency_ns; 82 td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
82 if (constraint_ns == 0) 83 td->cached_suspend_ok = true;
83 return false; 84 } else {
85 constraint_ns -= td->suspend_latency_ns + td->resume_latency_ns;
86 if (constraint_ns > 0) {
87 td->effective_constraint_ns = constraint_ns;
88 td->cached_suspend_ok = true;
89 } else {
90 td->effective_constraint_ns = 0;
91 }
84 } 92 }
85 td->effective_constraint_ns = constraint_ns;
86 td->cached_suspend_ok = constraint_ns >= 0;
87 93
88 /* 94 /*
89 * The children have been suspended already, so we don't need to take 95 * The children have been suspended already, so we don't need to take
@@ -145,13 +151,14 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
145 td = &to_gpd_data(pdd)->td; 151 td = &to_gpd_data(pdd)->td;
146 constraint_ns = td->effective_constraint_ns; 152 constraint_ns = td->effective_constraint_ns;
147 /* default_suspend_ok() need not be called before us. */ 153 /* default_suspend_ok() need not be called before us. */
148 if (constraint_ns < 0) { 154 if (constraint_ns < 0)
149 constraint_ns = dev_pm_qos_read_value(pdd->dev); 155 constraint_ns = dev_pm_qos_read_value(pdd->dev);
150 constraint_ns *= NSEC_PER_USEC; 156
151 } 157 if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT)
152 if (constraint_ns == 0)
153 continue; 158 continue;
154 159
160 constraint_ns *= NSEC_PER_USEC;
161
155 /* 162 /*
156 * constraint_ns cannot be negative here, because the device has 163 * constraint_ns cannot be negative here, because the device has
157 * been suspended. 164 * been suspended.
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 277d43a83f53..7d29286d9313 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -189,7 +189,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
189 plist_head_init(&c->list); 189 plist_head_init(&c->list);
190 c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; 190 c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
191 c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; 191 c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
192 c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE; 192 c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
193 c->type = PM_QOS_MIN; 193 c->type = PM_QOS_MIN;
194 c->notifiers = n; 194 c->notifiers = n;
195 195
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 156ab57bca77..632077f05c57 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 032b55909145..6737a8c9e8c6 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -27,16 +27,17 @@ 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
31 32
32#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) 33#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
33#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) 34#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC)
34#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 35#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
35#define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE 0 36#define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE 0
36#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0 37#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0
38#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT PM_QOS_LATENCY_ANY
37#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 39#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
38#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) 40#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
39#define PM_QOS_LATENCY_ANY ((s32)(~(__u32)0 >> 1))
40 41
41#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) 42#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0)
42#define PM_QOS_FLAG_REMOTE_WAKEUP (1 << 1) 43#define PM_QOS_FLAG_REMOTE_WAKEUP (1 << 1)