Commit 59fb53ea75eef4aa029cf31c88cdacec2f7b794b
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Merge branch 'pm-qos'
* pm-qos: sh_mmcif / PM: Use PM QoS latency constraint tmio_mmc / PM: Use PM QoS latency constraint PM / QoS: Make it possible to expose PM QoS latency constraints
Showing 8 changed files Side-by-side Diff
Documentation/ABI/testing/sysfs-devices-power
... | ... | @@ -165,4 +165,22 @@ |
165 | 165 | |
166 | 166 | Not all drivers support this attribute. If it isn't supported, |
167 | 167 | attempts to read or write it will yield I/O errors. |
168 | + | |
169 | +What: /sys/devices/.../power/pm_qos_latency_us | |
170 | +Date: March 2012 | |
171 | +Contact: Rafael J. Wysocki <rjw@sisk.pl> | |
172 | +Description: | |
173 | + The /sys/devices/.../power/pm_qos_resume_latency_us attribute | |
174 | + contains the PM QoS resume latency limit for the given device, | |
175 | + which is the maximum allowed time it can take to resume the | |
176 | + device, after it has been suspended at run time, from a resume | |
177 | + request to the moment the device will be ready to process I/O, | |
178 | + in microseconds. If it is equal to 0, however, this means that | |
179 | + the PM QoS resume latency may be arbitrary. | |
180 | + | |
181 | + Not all drivers support this attribute. If it isn't supported, | |
182 | + it is not present. | |
183 | + | |
184 | + This attribute has no effect on system-wide suspend/resume and | |
185 | + hibernation. |
drivers/base/power/power.h
... | ... | @@ -71,6 +71,8 @@ |
71 | 71 | extern void rpm_sysfs_remove(struct device *dev); |
72 | 72 | extern int wakeup_sysfs_add(struct device *dev); |
73 | 73 | extern void wakeup_sysfs_remove(struct device *dev); |
74 | +extern int pm_qos_sysfs_add(struct device *dev); | |
75 | +extern void pm_qos_sysfs_remove(struct device *dev); | |
74 | 76 | |
75 | 77 | #else /* CONFIG_PM */ |
76 | 78 | |
... | ... | @@ -79,6 +81,8 @@ |
79 | 81 | static inline void rpm_sysfs_remove(struct device *dev) {} |
80 | 82 | static inline int wakeup_sysfs_add(struct device *dev) { return 0; } |
81 | 83 | static inline void wakeup_sysfs_remove(struct device *dev) {} |
84 | +static inline int pm_qos_sysfs_add(struct device *dev) { return 0; } | |
85 | +static inline void pm_qos_sysfs_remove(struct device *dev) {} | |
82 | 86 | |
83 | 87 | #endif |
drivers/base/power/qos.c
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 | #include <linux/mutex.h> |
42 | 42 | #include <linux/export.h> |
43 | 43 | |
44 | +#include "power.h" | |
44 | 45 | |
45 | 46 | static DEFINE_MUTEX(dev_pm_qos_mtx); |
46 | 47 | |
... | ... | @@ -166,6 +167,12 @@ |
166 | 167 | struct dev_pm_qos_request *req, *tmp; |
167 | 168 | struct pm_qos_constraints *c; |
168 | 169 | |
170 | + /* | |
171 | + * If the device's PM QoS resume latency limit has been exposed to user | |
172 | + * space, it has to be hidden at this point. | |
173 | + */ | |
174 | + dev_pm_qos_hide_latency_limit(dev); | |
175 | + | |
169 | 176 | mutex_lock(&dev_pm_qos_mtx); |
170 | 177 | |
171 | 178 | dev->power.power_state = PMSG_INVALID; |
... | ... | @@ -445,4 +452,58 @@ |
445 | 452 | return error; |
446 | 453 | } |
447 | 454 | EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); |
455 | + | |
456 | +#ifdef CONFIG_PM_RUNTIME | |
457 | +static void __dev_pm_qos_drop_user_request(struct device *dev) | |
458 | +{ | |
459 | + dev_pm_qos_remove_request(dev->power.pq_req); | |
460 | + dev->power.pq_req = 0; | |
461 | +} | |
462 | + | |
463 | +/** | |
464 | + * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space. | |
465 | + * @dev: Device whose PM QoS latency limit is to be exposed to user space. | |
466 | + * @value: Initial value of the latency limit. | |
467 | + */ | |
468 | +int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) | |
469 | +{ | |
470 | + struct dev_pm_qos_request *req; | |
471 | + int ret; | |
472 | + | |
473 | + if (!device_is_registered(dev) || value < 0) | |
474 | + return -EINVAL; | |
475 | + | |
476 | + if (dev->power.pq_req) | |
477 | + return -EEXIST; | |
478 | + | |
479 | + req = kzalloc(sizeof(*req), GFP_KERNEL); | |
480 | + if (!req) | |
481 | + return -ENOMEM; | |
482 | + | |
483 | + ret = dev_pm_qos_add_request(dev, req, value); | |
484 | + if (ret < 0) | |
485 | + return ret; | |
486 | + | |
487 | + dev->power.pq_req = req; | |
488 | + ret = pm_qos_sysfs_add(dev); | |
489 | + if (ret) | |
490 | + __dev_pm_qos_drop_user_request(dev); | |
491 | + | |
492 | + return ret; | |
493 | +} | |
494 | +EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit); | |
495 | + | |
496 | +/** | |
497 | + * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space. | |
498 | + * @dev: Device whose PM QoS latency limit is to be hidden from user space. | |
499 | + */ | |
500 | +void dev_pm_qos_hide_latency_limit(struct device *dev) | |
501 | +{ | |
502 | + if (dev->power.pq_req) { | |
503 | + pm_qos_sysfs_remove(dev); | |
504 | + __dev_pm_qos_drop_user_request(dev); | |
505 | + } | |
506 | +} | |
507 | +EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); | |
508 | +#endif /* CONFIG_PM_RUNTIME */ |
drivers/base/power/sysfs.c
... | ... | @@ -5,6 +5,7 @@ |
5 | 5 | #include <linux/device.h> |
6 | 6 | #include <linux/string.h> |
7 | 7 | #include <linux/export.h> |
8 | +#include <linux/pm_qos.h> | |
8 | 9 | #include <linux/pm_runtime.h> |
9 | 10 | #include <linux/atomic.h> |
10 | 11 | #include <linux/jiffies.h> |
... | ... | @@ -217,6 +218,31 @@ |
217 | 218 | static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, |
218 | 219 | autosuspend_delay_ms_store); |
219 | 220 | |
221 | +static ssize_t pm_qos_latency_show(struct device *dev, | |
222 | + struct device_attribute *attr, char *buf) | |
223 | +{ | |
224 | + return sprintf(buf, "%d\n", dev->power.pq_req->node.prio); | |
225 | +} | |
226 | + | |
227 | +static ssize_t pm_qos_latency_store(struct device *dev, | |
228 | + struct device_attribute *attr, | |
229 | + const char *buf, size_t n) | |
230 | +{ | |
231 | + s32 value; | |
232 | + int ret; | |
233 | + | |
234 | + if (kstrtos32(buf, 0, &value)) | |
235 | + return -EINVAL; | |
236 | + | |
237 | + if (value < 0) | |
238 | + return -EINVAL; | |
239 | + | |
240 | + ret = dev_pm_qos_update_request(dev->power.pq_req, value); | |
241 | + return ret < 0 ? ret : n; | |
242 | +} | |
243 | + | |
244 | +static DEVICE_ATTR(pm_qos_resume_latency_us, 0644, | |
245 | + pm_qos_latency_show, pm_qos_latency_store); | |
220 | 246 | #endif /* CONFIG_PM_RUNTIME */ |
221 | 247 | |
222 | 248 | #ifdef CONFIG_PM_SLEEP |
... | ... | @@ -490,6 +516,17 @@ |
490 | 516 | .attrs = runtime_attrs, |
491 | 517 | }; |
492 | 518 | |
519 | +static struct attribute *pm_qos_attrs[] = { | |
520 | +#ifdef CONFIG_PM_RUNTIME | |
521 | + &dev_attr_pm_qos_resume_latency_us.attr, | |
522 | +#endif /* CONFIG_PM_RUNTIME */ | |
523 | + NULL, | |
524 | +}; | |
525 | +static struct attribute_group pm_qos_attr_group = { | |
526 | + .name = power_group_name, | |
527 | + .attrs = pm_qos_attrs, | |
528 | +}; | |
529 | + | |
493 | 530 | int dpm_sysfs_add(struct device *dev) |
494 | 531 | { |
495 | 532 | int rc; |
... | ... | @@ -528,6 +565,16 @@ |
528 | 565 | void wakeup_sysfs_remove(struct device *dev) |
529 | 566 | { |
530 | 567 | sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); |
568 | +} | |
569 | + | |
570 | +int pm_qos_sysfs_add(struct device *dev) | |
571 | +{ | |
572 | + return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group); | |
573 | +} | |
574 | + | |
575 | +void pm_qos_sysfs_remove(struct device *dev) | |
576 | +{ | |
577 | + sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group); | |
531 | 578 | } |
532 | 579 | |
533 | 580 | void rpm_sysfs_remove(struct device *dev) |
drivers/mmc/host/sh_mmcif.c
... | ... | @@ -56,6 +56,7 @@ |
56 | 56 | #include <linux/mmc/sh_mmcif.h> |
57 | 57 | #include <linux/pagemap.h> |
58 | 58 | #include <linux/platform_device.h> |
59 | +#include <linux/pm_qos.h> | |
59 | 60 | #include <linux/pm_runtime.h> |
60 | 61 | #include <linux/spinlock.h> |
61 | 62 | #include <linux/module.h> |
... | ... | @@ -1346,6 +1347,8 @@ |
1346 | 1347 | if (ret < 0) |
1347 | 1348 | goto clean_up5; |
1348 | 1349 | |
1350 | + dev_pm_qos_expose_latency_limit(&pdev->dev, 100); | |
1351 | + | |
1349 | 1352 | dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION); |
1350 | 1353 | dev_dbg(&pdev->dev, "chip ver H'%04x\n", |
1351 | 1354 | sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff); |
... | ... | @@ -1375,6 +1378,8 @@ |
1375 | 1378 | |
1376 | 1379 | host->dying = true; |
1377 | 1380 | pm_runtime_get_sync(&pdev->dev); |
1381 | + | |
1382 | + dev_pm_qos_hide_latency_limit(&pdev->dev); | |
1378 | 1383 | |
1379 | 1384 | mmc_remove_host(host->mmc); |
1380 | 1385 | sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); |
drivers/mmc/host/tmio_mmc_pio.c
... | ... | @@ -39,6 +39,7 @@ |
39 | 39 | #include <linux/module.h> |
40 | 40 | #include <linux/pagemap.h> |
41 | 41 | #include <linux/platform_device.h> |
42 | +#include <linux/pm_qos.h> | |
42 | 43 | #include <linux/pm_runtime.h> |
43 | 44 | #include <linux/scatterlist.h> |
44 | 45 | #include <linux/spinlock.h> |
... | ... | @@ -955,6 +956,8 @@ |
955 | 956 | |
956 | 957 | mmc_add_host(mmc); |
957 | 958 | |
959 | + dev_pm_qos_expose_latency_limit(&pdev->dev, 100); | |
960 | + | |
958 | 961 | /* Unmask the IRQs we want to know about */ |
959 | 962 | if (!_host->chan_rx) |
960 | 963 | irq_mask |= TMIO_MASK_READOP; |
... | ... | @@ -992,6 +995,8 @@ |
992 | 995 | || host->mmc->caps & MMC_CAP_NEEDS_POLL |
993 | 996 | || host->mmc->caps & MMC_CAP_NONREMOVABLE) |
994 | 997 | pm_runtime_get_sync(&pdev->dev); |
998 | + | |
999 | + dev_pm_qos_hide_latency_limit(&pdev->dev); | |
995 | 1000 | |
996 | 1001 | mmc_remove_host(host->mmc); |
997 | 1002 | cancel_work_sync(&host->done); |
include/linux/pm.h
... | ... | @@ -546,6 +546,7 @@ |
546 | 546 | unsigned long accounting_timestamp; |
547 | 547 | ktime_t suspend_time; |
548 | 548 | s64 max_time_suspended_ns; |
549 | + struct dev_pm_qos_request *pq_req; | |
549 | 550 | #endif |
550 | 551 | struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ |
551 | 552 | struct pm_qos_constraints *constraints; |
include/linux/pm_qos.h
... | ... | @@ -137,5 +137,14 @@ |
137 | 137 | { return 0; } |
138 | 138 | #endif |
139 | 139 | |
140 | +#ifdef CONFIG_PM_RUNTIME | |
141 | +int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value); | |
142 | +void dev_pm_qos_hide_latency_limit(struct device *dev); | |
143 | +#else | |
144 | +static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) | |
145 | + { return 0; } | |
146 | +static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {} | |
147 | +#endif | |
148 | + | |
140 | 149 | #endif |