aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-devices-power31
-rw-r--r--drivers/base/power/power.h6
-rw-r--r--drivers/base/power/qos.c168
-rw-r--r--drivers/base/power/sysfs.c94
-rw-r--r--include/linux/pm.h1
-rw-r--r--include/linux/pm_qos.h26
6 files changed, 278 insertions, 48 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index 45000f0db4d4..7fc2997b23a6 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -204,3 +204,34 @@ Description:
204 204
205 This attribute has no effect on system-wide suspend/resume and 205 This attribute has no effect on system-wide suspend/resume and
206 hibernation. 206 hibernation.
207
208What: /sys/devices/.../power/pm_qos_no_power_off
209Date: September 2012
210Contact: Rafael J. Wysocki <rjw@sisk.pl>
211Description:
212 The /sys/devices/.../power/pm_qos_no_power_off attribute
213 is used for manipulating the PM QoS "no power off" flag. If
214 set, this flag indicates to the kernel that power should not
215 be removed entirely from the device.
216
217 Not all drivers support this attribute. If it isn't supported,
218 it is not present.
219
220 This attribute has no effect on system-wide suspend/resume and
221 hibernation.
222
223What: /sys/devices/.../power/pm_qos_remote_wakeup
224Date: September 2012
225Contact: Rafael J. Wysocki <rjw@sisk.pl>
226Description:
227 The /sys/devices/.../power/pm_qos_remote_wakeup attribute
228 is used for manipulating the PM QoS "remote wakeup required"
229 flag. If set, this flag indicates to the kernel that the
230 device is a source of user events that have to be signaled from
231 its low-power states.
232
233 Not all drivers support this attribute. If it isn't supported,
234 it is not present.
235
236 This attribute has no effect on system-wide suspend/resume and
237 hibernation.
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 0dbfdf4419af..b16686a0a5a2 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -93,8 +93,10 @@ extern void dpm_sysfs_remove(struct device *dev);
93extern void rpm_sysfs_remove(struct device *dev); 93extern void rpm_sysfs_remove(struct device *dev);
94extern int wakeup_sysfs_add(struct device *dev); 94extern int wakeup_sysfs_add(struct device *dev);
95extern void wakeup_sysfs_remove(struct device *dev); 95extern void wakeup_sysfs_remove(struct device *dev);
96extern int pm_qos_sysfs_add(struct device *dev); 96extern int pm_qos_sysfs_add_latency(struct device *dev);
97extern void pm_qos_sysfs_remove(struct device *dev); 97extern void pm_qos_sysfs_remove_latency(struct device *dev);
98extern int pm_qos_sysfs_add_flags(struct device *dev);
99extern void pm_qos_sysfs_remove_flags(struct device *dev);
98 100
99#else /* CONFIG_PM */ 101#else /* CONFIG_PM */
100 102
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 3c66f75d14b0..167834dcc82a 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -40,6 +40,7 @@
40#include <linux/device.h> 40#include <linux/device.h>
41#include <linux/mutex.h> 41#include <linux/mutex.h>
42#include <linux/export.h> 42#include <linux/export.h>
43#include <linux/pm_runtime.h>
43 44
44#include "power.h" 45#include "power.h"
45 46
@@ -322,6 +323,37 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
322EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); 323EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
323 324
324/** 325/**
326 * __dev_pm_qos_update_request - Modify an existing device PM QoS request.
327 * @req : PM QoS request to modify.
328 * @new_value: New value to request.
329 */
330static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
331 s32 new_value)
332{
333 s32 curr_value;
334 int ret = 0;
335
336 if (!req->dev->power.qos)
337 return -ENODEV;
338
339 switch(req->type) {
340 case DEV_PM_QOS_LATENCY:
341 curr_value = req->data.pnode.prio;
342 break;
343 case DEV_PM_QOS_FLAGS:
344 curr_value = req->data.flr.flags;
345 break;
346 default:
347 return -EINVAL;
348 }
349
350 if (curr_value != new_value)
351 ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
352
353 return ret;
354}
355
356/**
325 * dev_pm_qos_update_request - modifies an existing qos request 357 * dev_pm_qos_update_request - modifies an existing qos request
326 * @req : handle to list element holding a dev_pm_qos request to use 358 * @req : handle to list element holding a dev_pm_qos request to use
327 * @new_value: defines the qos request 359 * @new_value: defines the qos request
@@ -336,11 +368,9 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
336 * -EINVAL in case of wrong parameters, -ENODEV if the device has been 368 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
337 * removed from the system 369 * removed from the system
338 */ 370 */
339int dev_pm_qos_update_request(struct dev_pm_qos_request *req, 371int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value)
340 s32 new_value)
341{ 372{
342 s32 curr_value; 373 int ret;
343 int ret = 0;
344 374
345 if (!req) /*guard against callers passing in null */ 375 if (!req) /*guard against callers passing in null */
346 return -EINVAL; 376 return -EINVAL;
@@ -350,29 +380,9 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
350 return -EINVAL; 380 return -EINVAL;
351 381
352 mutex_lock(&dev_pm_qos_mtx); 382 mutex_lock(&dev_pm_qos_mtx);
353 383 __dev_pm_qos_update_request(req, new_value);
354 if (!req->dev->power.qos) {
355 ret = -ENODEV;
356 goto out;
357 }
358
359 switch(req->type) {
360 case DEV_PM_QOS_LATENCY:
361 curr_value = req->data.pnode.prio;
362 break;
363 case DEV_PM_QOS_FLAGS:
364 curr_value = req->data.flr.flags;
365 break;
366 default:
367 ret = -EINVAL;
368 goto out;
369 }
370
371 if (curr_value != new_value)
372 ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
373
374 out:
375 mutex_unlock(&dev_pm_qos_mtx); 384 mutex_unlock(&dev_pm_qos_mtx);
385
376 return ret; 386 return ret;
377} 387}
378EXPORT_SYMBOL_GPL(dev_pm_qos_update_request); 388EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
@@ -533,10 +543,19 @@ int dev_pm_qos_add_ancestor_request(struct device *dev,
533EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); 543EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
534 544
535#ifdef CONFIG_PM_RUNTIME 545#ifdef CONFIG_PM_RUNTIME
536static void __dev_pm_qos_drop_user_request(struct device *dev) 546static void __dev_pm_qos_drop_user_request(struct device *dev,
547 enum dev_pm_qos_req_type type)
537{ 548{
538 dev_pm_qos_remove_request(dev->power.pq_req); 549 switch(type) {
539 dev->power.pq_req = NULL; 550 case DEV_PM_QOS_LATENCY:
551 dev_pm_qos_remove_request(dev->power.qos->latency_req);
552 dev->power.qos->latency_req = NULL;
553 break;
554 case DEV_PM_QOS_FLAGS:
555 dev_pm_qos_remove_request(dev->power.qos->flags_req);
556 dev->power.qos->flags_req = NULL;
557 break;
558 }
540} 559}
541 560
542/** 561/**
@@ -552,7 +571,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
552 if (!device_is_registered(dev) || value < 0) 571 if (!device_is_registered(dev) || value < 0)
553 return -EINVAL; 572 return -EINVAL;
554 573
555 if (dev->power.pq_req) 574 if (dev->power.qos && dev->power.qos->latency_req)
556 return -EEXIST; 575 return -EEXIST;
557 576
558 req = kzalloc(sizeof(*req), GFP_KERNEL); 577 req = kzalloc(sizeof(*req), GFP_KERNEL);
@@ -563,10 +582,10 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
563 if (ret < 0) 582 if (ret < 0)
564 return ret; 583 return ret;
565 584
566 dev->power.pq_req = req; 585 dev->power.qos->latency_req = req;
567 ret = pm_qos_sysfs_add(dev); 586 ret = pm_qos_sysfs_add_latency(dev);
568 if (ret) 587 if (ret)
569 __dev_pm_qos_drop_user_request(dev); 588 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
570 589
571 return ret; 590 return ret;
572} 591}
@@ -578,10 +597,87 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
578 */ 597 */
579void dev_pm_qos_hide_latency_limit(struct device *dev) 598void dev_pm_qos_hide_latency_limit(struct device *dev)
580{ 599{
581 if (dev->power.pq_req) { 600 if (dev->power.qos && dev->power.qos->latency_req) {
582 pm_qos_sysfs_remove(dev); 601 pm_qos_sysfs_remove_latency(dev);
583 __dev_pm_qos_drop_user_request(dev); 602 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
584 } 603 }
585} 604}
586EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); 605EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
606
607/**
608 * dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space.
609 * @dev: Device whose PM QoS flags are to be exposed to user space.
610 * @val: Initial values of the flags.
611 */
612int dev_pm_qos_expose_flags(struct device *dev, s32 val)
613{
614 struct dev_pm_qos_request *req;
615 int ret;
616
617 if (!device_is_registered(dev))
618 return -EINVAL;
619
620 if (dev->power.qos && dev->power.qos->flags_req)
621 return -EEXIST;
622
623 req = kzalloc(sizeof(*req), GFP_KERNEL);
624 if (!req)
625 return -ENOMEM;
626
627 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val);
628 if (ret < 0)
629 return ret;
630
631 dev->power.qos->flags_req = req;
632 ret = pm_qos_sysfs_add_flags(dev);
633 if (ret)
634 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
635
636 return ret;
637}
638EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
639
640/**
641 * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space.
642 * @dev: Device whose PM QoS flags are to be hidden from user space.
643 */
644void dev_pm_qos_hide_flags(struct device *dev)
645{
646 if (dev->power.qos && dev->power.qos->flags_req) {
647 pm_qos_sysfs_remove_flags(dev);
648 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
649 }
650}
651EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
652
653/**
654 * dev_pm_qos_update_flags - Update PM QoS flags request owned by user space.
655 * @dev: Device to update the PM QoS flags request for.
656 * @mask: Flags to set/clear.
657 * @set: Whether to set or clear the flags (true means set).
658 */
659int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
660{
661 s32 value;
662 int ret;
663
664 if (!dev->power.qos || !dev->power.qos->flags_req)
665 return -EINVAL;
666
667 pm_runtime_get_sync(dev);
668 mutex_lock(&dev_pm_qos_mtx);
669
670 value = dev_pm_qos_requested_flags(dev);
671 if (set)
672 value |= mask;
673 else
674 value &= ~mask;
675
676 ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value);
677
678 mutex_unlock(&dev_pm_qos_mtx);
679 pm_runtime_put(dev);
680
681 return ret;
682}
587#endif /* CONFIG_PM_RUNTIME */ 683#endif /* CONFIG_PM_RUNTIME */
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 54c61ffa2044..50d16e3cb0a9 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -221,7 +221,7 @@ static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
221static ssize_t pm_qos_latency_show(struct device *dev, 221static ssize_t pm_qos_latency_show(struct device *dev,
222 struct device_attribute *attr, char *buf) 222 struct device_attribute *attr, char *buf)
223{ 223{
224 return sprintf(buf, "%d\n", dev->power.pq_req->data.pnode.prio); 224 return sprintf(buf, "%d\n", dev_pm_qos_requested_latency(dev));
225} 225}
226 226
227static ssize_t pm_qos_latency_store(struct device *dev, 227static ssize_t pm_qos_latency_store(struct device *dev,
@@ -237,12 +237,66 @@ static ssize_t pm_qos_latency_store(struct device *dev,
237 if (value < 0) 237 if (value < 0)
238 return -EINVAL; 238 return -EINVAL;
239 239
240 ret = dev_pm_qos_update_request(dev->power.pq_req, value); 240 ret = dev_pm_qos_update_request(dev->power.qos->latency_req, value);
241 return ret < 0 ? ret : n; 241 return ret < 0 ? ret : n;
242} 242}
243 243
244static DEVICE_ATTR(pm_qos_resume_latency_us, 0644, 244static DEVICE_ATTR(pm_qos_resume_latency_us, 0644,
245 pm_qos_latency_show, pm_qos_latency_store); 245 pm_qos_latency_show, pm_qos_latency_store);
246
247static ssize_t pm_qos_no_power_off_show(struct device *dev,
248 struct device_attribute *attr,
249 char *buf)
250{
251 return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev)
252 & PM_QOS_FLAG_NO_POWER_OFF));
253}
254
255static ssize_t pm_qos_no_power_off_store(struct device *dev,
256 struct device_attribute *attr,
257 const char *buf, size_t n)
258{
259 int ret;
260
261 if (kstrtoint(buf, 0, &ret))
262 return -EINVAL;
263
264 if (ret != 0 && ret != 1)
265 return -EINVAL;
266
267 ret = dev_pm_qos_update_flags(dev, PM_QOS_FLAG_NO_POWER_OFF, ret);
268 return ret < 0 ? ret : n;
269}
270
271static DEVICE_ATTR(pm_qos_no_power_off, 0644,
272 pm_qos_no_power_off_show, pm_qos_no_power_off_store);
273
274static ssize_t pm_qos_remote_wakeup_show(struct device *dev,
275 struct device_attribute *attr,
276 char *buf)
277{
278 return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev)
279 & PM_QOS_FLAG_REMOTE_WAKEUP));
280}
281
282static ssize_t pm_qos_remote_wakeup_store(struct device *dev,
283 struct device_attribute *attr,
284 const char *buf, size_t n)
285{
286 int ret;
287
288 if (kstrtoint(buf, 0, &ret))
289 return -EINVAL;
290
291 if (ret != 0 && ret != 1)
292 return -EINVAL;
293
294 ret = dev_pm_qos_update_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP, ret);
295 return ret < 0 ? ret : n;
296}
297
298static DEVICE_ATTR(pm_qos_remote_wakeup, 0644,
299 pm_qos_remote_wakeup_show, pm_qos_remote_wakeup_store);
246#endif /* CONFIG_PM_RUNTIME */ 300#endif /* CONFIG_PM_RUNTIME */
247 301
248#ifdef CONFIG_PM_SLEEP 302#ifdef CONFIG_PM_SLEEP
@@ -564,15 +618,27 @@ static struct attribute_group pm_runtime_attr_group = {
564 .attrs = runtime_attrs, 618 .attrs = runtime_attrs,
565}; 619};
566 620
567static struct attribute *pm_qos_attrs[] = { 621static struct attribute *pm_qos_latency_attrs[] = {
568#ifdef CONFIG_PM_RUNTIME 622#ifdef CONFIG_PM_RUNTIME
569 &dev_attr_pm_qos_resume_latency_us.attr, 623 &dev_attr_pm_qos_resume_latency_us.attr,
570#endif /* CONFIG_PM_RUNTIME */ 624#endif /* CONFIG_PM_RUNTIME */
571 NULL, 625 NULL,
572}; 626};
573static struct attribute_group pm_qos_attr_group = { 627static struct attribute_group pm_qos_latency_attr_group = {
574 .name = power_group_name, 628 .name = power_group_name,
575 .attrs = pm_qos_attrs, 629 .attrs = pm_qos_latency_attrs,
630};
631
632static struct attribute *pm_qos_flags_attrs[] = {
633#ifdef CONFIG_PM_RUNTIME
634 &dev_attr_pm_qos_no_power_off.attr,
635 &dev_attr_pm_qos_remote_wakeup.attr,
636#endif /* CONFIG_PM_RUNTIME */
637 NULL,
638};
639static struct attribute_group pm_qos_flags_attr_group = {
640 .name = power_group_name,
641 .attrs = pm_qos_flags_attrs,
576}; 642};
577 643
578int dpm_sysfs_add(struct device *dev) 644int dpm_sysfs_add(struct device *dev)
@@ -615,14 +681,24 @@ void wakeup_sysfs_remove(struct device *dev)
615 sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); 681 sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
616} 682}
617 683
618int pm_qos_sysfs_add(struct device *dev) 684int pm_qos_sysfs_add_latency(struct device *dev)
685{
686 return sysfs_merge_group(&dev->kobj, &pm_qos_latency_attr_group);
687}
688
689void pm_qos_sysfs_remove_latency(struct device *dev)
690{
691 sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_attr_group);
692}
693
694int pm_qos_sysfs_add_flags(struct device *dev)
619{ 695{
620 return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group); 696 return sysfs_merge_group(&dev->kobj, &pm_qos_flags_attr_group);
621} 697}
622 698
623void pm_qos_sysfs_remove(struct device *dev) 699void pm_qos_sysfs_remove_flags(struct device *dev)
624{ 700{
625 sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group); 701 sysfs_unmerge_group(&dev->kobj, &pm_qos_flags_attr_group);
626} 702}
627 703
628void rpm_sysfs_remove(struct device *dev) 704void rpm_sysfs_remove(struct device *dev)
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 0ce6df94221a..03d7bb145311 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -546,7 +546,6 @@ struct dev_pm_info {
546 unsigned long active_jiffies; 546 unsigned long active_jiffies;
547 unsigned long suspended_jiffies; 547 unsigned long suspended_jiffies;
548 unsigned long accounting_timestamp; 548 unsigned long accounting_timestamp;
549 struct dev_pm_qos_request *pq_req;
550#endif 549#endif
551 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ 550 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
552 struct dev_pm_qos *qos; 551 struct dev_pm_qos *qos;
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 3af7d8573c23..5a95013905c8 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -34,6 +34,9 @@ enum pm_qos_flags_status {
34#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 34#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0
35#define PM_QOS_DEV_LAT_DEFAULT_VALUE 0 35#define PM_QOS_DEV_LAT_DEFAULT_VALUE 0
36 36
37#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0)
38#define PM_QOS_FLAG_REMOTE_WAKEUP (1 << 1)
39
37struct pm_qos_request { 40struct pm_qos_request {
38 struct plist_node node; 41 struct plist_node node;
39 int pm_qos_class; 42 int pm_qos_class;
@@ -86,6 +89,8 @@ struct pm_qos_flags {
86struct dev_pm_qos { 89struct dev_pm_qos {
87 struct pm_qos_constraints latency; 90 struct pm_qos_constraints latency;
88 struct pm_qos_flags flags; 91 struct pm_qos_flags flags;
92 struct dev_pm_qos_request *latency_req;
93 struct dev_pm_qos_request *flags_req;
89}; 94};
90 95
91/* Action requested to pm_qos_update_target */ 96/* Action requested to pm_qos_update_target */
@@ -187,10 +192,31 @@ static inline int dev_pm_qos_add_ancestor_request(struct device *dev,
187#ifdef CONFIG_PM_RUNTIME 192#ifdef CONFIG_PM_RUNTIME
188int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value); 193int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value);
189void dev_pm_qos_hide_latency_limit(struct device *dev); 194void dev_pm_qos_hide_latency_limit(struct device *dev);
195int dev_pm_qos_expose_flags(struct device *dev, s32 value);
196void dev_pm_qos_hide_flags(struct device *dev);
197int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set);
198
199static inline s32 dev_pm_qos_requested_latency(struct device *dev)
200{
201 return dev->power.qos->latency_req->data.pnode.prio;
202}
203
204static inline s32 dev_pm_qos_requested_flags(struct device *dev)
205{
206 return dev->power.qos->flags_req->data.flr.flags;
207}
190#else 208#else
191static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) 209static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
192 { return 0; } 210 { return 0; }
193static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {} 211static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {}
212static inline int dev_pm_qos_expose_flags(struct device *dev, s32 value)
213 { return 0; }
214static inline void dev_pm_qos_hide_flags(struct device *dev) {}
215static inline int dev_pm_qos_update_flags(struct device *dev, s32 m, bool set)
216 { return 0; }
217
218static inline s32 dev_pm_qos_requested_latency(struct device *dev) { return 0; }
219static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
194#endif 220#endif
195 221
196#endif 222#endif