diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-devices-power | 4 | ||||
-rw-r--r-- | drivers/base/cpu.c | 3 | ||||
-rw-r--r-- | drivers/base/power/domain_governor.c | 53 | ||||
-rw-r--r-- | drivers/base/power/qos.c | 2 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 2 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 25 | ||||
-rw-r--r-- | drivers/cpuidle/governors/menu.c | 4 | ||||
-rw-r--r-- | include/linux/pm_qos.h | 5 |
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 @@ | |||
14 | static int dev_update_qos_constraint(struct device *dev, void *data) | 14 | static 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 | ||
224 | static ssize_t pm_qos_resume_latency_store(struct device *dev, | 231 | static 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) |