aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/power/main.c2
-rw-r--r--drivers/base/power/power.h8
-rw-r--r--drivers/base/power/qos.c120
-rw-r--r--drivers/base/power/sysfs.c1
4 files changed, 55 insertions, 76 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 2b7f77d3fcb0..15beb500a4e4 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -99,7 +99,6 @@ void device_pm_add(struct device *dev)
99 dev_warn(dev, "parent %s should not be sleeping\n", 99 dev_warn(dev, "parent %s should not be sleeping\n",
100 dev_name(dev->parent)); 100 dev_name(dev->parent));
101 list_add_tail(&dev->power.entry, &dpm_list); 101 list_add_tail(&dev->power.entry, &dpm_list);
102 dev_pm_qos_constraints_init(dev);
103 mutex_unlock(&dpm_list_mtx); 102 mutex_unlock(&dpm_list_mtx);
104} 103}
105 104
@@ -113,7 +112,6 @@ void device_pm_remove(struct device *dev)
113 dev->bus ? dev->bus->name : "No Bus", dev_name(dev)); 112 dev->bus ? dev->bus->name : "No Bus", dev_name(dev));
114 complete_all(&dev->power.completion); 113 complete_all(&dev->power.completion);
115 mutex_lock(&dpm_list_mtx); 114 mutex_lock(&dpm_list_mtx);
116 dev_pm_qos_constraints_destroy(dev);
117 list_del_init(&dev->power.entry); 115 list_del_init(&dev->power.entry);
118 mutex_unlock(&dpm_list_mtx); 116 mutex_unlock(&dpm_list_mtx);
119 device_wakeup_disable(dev); 117 device_wakeup_disable(dev);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index b16686a0a5a2..cfc3226ec492 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -4,7 +4,7 @@ static inline void device_pm_init_common(struct device *dev)
4{ 4{
5 if (!dev->power.early_init) { 5 if (!dev->power.early_init) {
6 spin_lock_init(&dev->power.lock); 6 spin_lock_init(&dev->power.lock);
7 dev->power.power_state = PMSG_INVALID; 7 dev->power.qos = NULL;
8 dev->power.early_init = true; 8 dev->power.early_init = true;
9 } 9 }
10} 10}
@@ -56,14 +56,10 @@ extern void device_pm_move_last(struct device *);
56 56
57static inline void device_pm_sleep_init(struct device *dev) {} 57static inline void device_pm_sleep_init(struct device *dev) {}
58 58
59static inline void device_pm_add(struct device *dev) 59static inline void device_pm_add(struct device *dev) {}
60{
61 dev_pm_qos_constraints_init(dev);
62}
63 60
64static inline void device_pm_remove(struct device *dev) 61static inline void device_pm_remove(struct device *dev)
65{ 62{
66 dev_pm_qos_constraints_destroy(dev);
67 pm_runtime_remove(dev); 63 pm_runtime_remove(dev);
68} 64}
69 65
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 2159d62c858a..5f74587ef258 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -41,6 +41,7 @@
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#include <linux/pm_runtime.h>
44#include <linux/err.h>
44 45
45#include "power.h" 46#include "power.h"
46 47
@@ -61,7 +62,7 @@ enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
61 struct pm_qos_flags *pqf; 62 struct pm_qos_flags *pqf;
62 s32 val; 63 s32 val;
63 64
64 if (!qos) 65 if (IS_ERR_OR_NULL(qos))
65 return PM_QOS_FLAGS_UNDEFINED; 66 return PM_QOS_FLAGS_UNDEFINED;
66 67
67 pqf = &qos->flags; 68 pqf = &qos->flags;
@@ -101,7 +102,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
101 */ 102 */
102s32 __dev_pm_qos_read_value(struct device *dev) 103s32 __dev_pm_qos_read_value(struct device *dev)
103{ 104{
104 return dev->power.qos ? pm_qos_read_value(&dev->power.qos->latency) : 0; 105 return IS_ERR_OR_NULL(dev->power.qos) ?
106 0 : pm_qos_read_value(&dev->power.qos->latency);
105} 107}
106 108
107/** 109/**
@@ -198,20 +200,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
198 return 0; 200 return 0;
199} 201}
200 202
201/** 203static void __dev_pm_qos_hide_latency_limit(struct device *dev);
202 * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer. 204static void __dev_pm_qos_hide_flags(struct device *dev);
203 * @dev: target device
204 *
205 * Called from the device PM subsystem during device insertion under
206 * device_pm_lock().
207 */
208void dev_pm_qos_constraints_init(struct device *dev)
209{
210 mutex_lock(&dev_pm_qos_mtx);
211 dev->power.qos = NULL;
212 dev->power.power_state = PMSG_ON;
213 mutex_unlock(&dev_pm_qos_mtx);
214}
215 205
216/** 206/**
217 * dev_pm_qos_constraints_destroy 207 * dev_pm_qos_constraints_destroy
@@ -226,16 +216,15 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
226 struct pm_qos_constraints *c; 216 struct pm_qos_constraints *c;
227 struct pm_qos_flags *f; 217 struct pm_qos_flags *f;
228 218
219 mutex_lock(&dev_pm_qos_mtx);
220
229 /* 221 /*
230 * If the device's PM QoS resume latency limit or PM QoS flags have been 222 * If the device's PM QoS resume latency limit or PM QoS flags have been
231 * exposed to user space, they have to be hidden at this point. 223 * exposed to user space, they have to be hidden at this point.
232 */ 224 */
233 dev_pm_qos_hide_latency_limit(dev); 225 __dev_pm_qos_hide_latency_limit(dev);
234 dev_pm_qos_hide_flags(dev); 226 __dev_pm_qos_hide_flags(dev);
235
236 mutex_lock(&dev_pm_qos_mtx);
237 227
238 dev->power.power_state = PMSG_INVALID;
239 qos = dev->power.qos; 228 qos = dev->power.qos;
240 if (!qos) 229 if (!qos)
241 goto out; 230 goto out;
@@ -257,7 +246,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
257 } 246 }
258 247
259 spin_lock_irq(&dev->power.lock); 248 spin_lock_irq(&dev->power.lock);
260 dev->power.qos = NULL; 249 dev->power.qos = ERR_PTR(-ENODEV);
261 spin_unlock_irq(&dev->power.lock); 250 spin_unlock_irq(&dev->power.lock);
262 251
263 kfree(c->notifiers); 252 kfree(c->notifiers);
@@ -301,32 +290,19 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
301 "%s() called for already added request\n", __func__)) 290 "%s() called for already added request\n", __func__))
302 return -EINVAL; 291 return -EINVAL;
303 292
304 req->dev = dev;
305
306 mutex_lock(&dev_pm_qos_mtx); 293 mutex_lock(&dev_pm_qos_mtx);
307 294
308 if (!dev->power.qos) { 295 if (IS_ERR(dev->power.qos))
309 if (dev->power.power_state.event == PM_EVENT_INVALID) { 296 ret = -ENODEV;
310 /* The device has been removed from the system. */ 297 else if (!dev->power.qos)
311 req->dev = NULL; 298 ret = dev_pm_qos_constraints_allocate(dev);
312 ret = -ENODEV;
313 goto out;
314 } else {
315 /*
316 * Allocate the constraints data on the first call to
317 * add_request, i.e. only if the data is not already
318 * allocated and if the device has not been removed.
319 */
320 ret = dev_pm_qos_constraints_allocate(dev);
321 }
322 }
323 299
324 if (!ret) { 300 if (!ret) {
301 req->dev = dev;
325 req->type = type; 302 req->type = type;
326 ret = apply_constraint(req, PM_QOS_ADD_REQ, value); 303 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
327 } 304 }
328 305
329 out:
330 mutex_unlock(&dev_pm_qos_mtx); 306 mutex_unlock(&dev_pm_qos_mtx);
331 307
332 return ret; 308 return ret;
@@ -351,7 +327,7 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
351 "%s() called for unknown object\n", __func__)) 327 "%s() called for unknown object\n", __func__))
352 return -EINVAL; 328 return -EINVAL;
353 329
354 if (!req->dev->power.qos) 330 if (IS_ERR_OR_NULL(req->dev->power.qos))
355 return -ENODEV; 331 return -ENODEV;
356 332
357 switch(req->type) { 333 switch(req->type) {
@@ -402,7 +378,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
402 378
403static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req) 379static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
404{ 380{
405 int ret = 0; 381 int ret;
406 382
407 if (!req) /*guard against callers passing in null */ 383 if (!req) /*guard against callers passing in null */
408 return -EINVAL; 384 return -EINVAL;
@@ -411,13 +387,11 @@ static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
411 "%s() called for unknown object\n", __func__)) 387 "%s() called for unknown object\n", __func__))
412 return -EINVAL; 388 return -EINVAL;
413 389
414 if (req->dev->power.qos) { 390 if (IS_ERR_OR_NULL(req->dev->power.qos))
415 ret = apply_constraint(req, PM_QOS_REMOVE_REQ, 391 return -ENODEV;
416 PM_QOS_DEFAULT_VALUE); 392
417 memset(req, 0, sizeof(*req)); 393 ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
418 } else { 394 memset(req, 0, sizeof(*req));
419 ret = -ENODEV;
420 }
421 return ret; 395 return ret;
422} 396}
423 397
@@ -466,9 +440,10 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
466 440
467 mutex_lock(&dev_pm_qos_mtx); 441 mutex_lock(&dev_pm_qos_mtx);
468 442
469 if (!dev->power.qos) 443 if (IS_ERR(dev->power.qos))
470 ret = dev->power.power_state.event != PM_EVENT_INVALID ? 444 ret = -ENODEV;
471 dev_pm_qos_constraints_allocate(dev) : -ENODEV; 445 else if (!dev->power.qos)
446 ret = dev_pm_qos_constraints_allocate(dev);
472 447
473 if (!ret) 448 if (!ret)
474 ret = blocking_notifier_chain_register( 449 ret = blocking_notifier_chain_register(
@@ -497,7 +472,7 @@ int dev_pm_qos_remove_notifier(struct device *dev,
497 mutex_lock(&dev_pm_qos_mtx); 472 mutex_lock(&dev_pm_qos_mtx);
498 473
499 /* Silently return if the constraints object is not present. */ 474 /* Silently return if the constraints object is not present. */
500 if (dev->power.qos) 475 if (!IS_ERR_OR_NULL(dev->power.qos))
501 retval = blocking_notifier_chain_unregister( 476 retval = blocking_notifier_chain_unregister(
502 dev->power.qos->latency.notifiers, 477 dev->power.qos->latency.notifiers,
503 notifier); 478 notifier);
@@ -608,7 +583,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
608 583
609 mutex_lock(&dev_pm_qos_mtx); 584 mutex_lock(&dev_pm_qos_mtx);
610 585
611 if (!dev->power.qos) 586 if (IS_ERR_OR_NULL(dev->power.qos))
612 ret = -ENODEV; 587 ret = -ENODEV;
613 else if (dev->power.qos->latency_req) 588 else if (dev->power.qos->latency_req)
614 ret = -EEXIST; 589 ret = -EEXIST;
@@ -630,6 +605,14 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
630} 605}
631EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit); 606EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
632 607
608static void __dev_pm_qos_hide_latency_limit(struct device *dev)
609{
610 if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req) {
611 pm_qos_sysfs_remove_latency(dev);
612 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
613 }
614}
615
633/** 616/**
634 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space. 617 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
635 * @dev: Device whose PM QoS latency limit is to be hidden from user space. 618 * @dev: Device whose PM QoS latency limit is to be hidden from user space.
@@ -637,12 +620,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
637void dev_pm_qos_hide_latency_limit(struct device *dev) 620void dev_pm_qos_hide_latency_limit(struct device *dev)
638{ 621{
639 mutex_lock(&dev_pm_qos_mtx); 622 mutex_lock(&dev_pm_qos_mtx);
640 623 __dev_pm_qos_hide_latency_limit(dev);
641 if (dev->power.qos && dev->power.qos->latency_req) {
642 pm_qos_sysfs_remove_latency(dev);
643 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
644 }
645
646 mutex_unlock(&dev_pm_qos_mtx); 624 mutex_unlock(&dev_pm_qos_mtx);
647} 625}
648EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); 626EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
@@ -673,7 +651,7 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)
673 pm_runtime_get_sync(dev); 651 pm_runtime_get_sync(dev);
674 mutex_lock(&dev_pm_qos_mtx); 652 mutex_lock(&dev_pm_qos_mtx);
675 653
676 if (!dev->power.qos) 654 if (IS_ERR_OR_NULL(dev->power.qos))
677 ret = -ENODEV; 655 ret = -ENODEV;
678 else if (dev->power.qos->flags_req) 656 else if (dev->power.qos->flags_req)
679 ret = -EEXIST; 657 ret = -EEXIST;
@@ -696,6 +674,14 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)
696} 674}
697EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags); 675EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
698 676
677static void __dev_pm_qos_hide_flags(struct device *dev)
678{
679 if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req) {
680 pm_qos_sysfs_remove_flags(dev);
681 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
682 }
683}
684
699/** 685/**
700 * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space. 686 * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space.
701 * @dev: Device whose PM QoS flags are to be hidden from user space. 687 * @dev: Device whose PM QoS flags are to be hidden from user space.
@@ -704,12 +690,7 @@ void dev_pm_qos_hide_flags(struct device *dev)
704{ 690{
705 pm_runtime_get_sync(dev); 691 pm_runtime_get_sync(dev);
706 mutex_lock(&dev_pm_qos_mtx); 692 mutex_lock(&dev_pm_qos_mtx);
707 693 __dev_pm_qos_hide_flags(dev);
708 if (dev->power.qos && dev->power.qos->flags_req) {
709 pm_qos_sysfs_remove_flags(dev);
710 __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
711 }
712
713 mutex_unlock(&dev_pm_qos_mtx); 694 mutex_unlock(&dev_pm_qos_mtx);
714 pm_runtime_put(dev); 695 pm_runtime_put(dev);
715} 696}
@@ -729,7 +710,7 @@ int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
729 pm_runtime_get_sync(dev); 710 pm_runtime_get_sync(dev);
730 mutex_lock(&dev_pm_qos_mtx); 711 mutex_lock(&dev_pm_qos_mtx);
731 712
732 if (!dev->power.qos || !dev->power.qos->flags_req) { 713 if (IS_ERR_OR_NULL(dev->power.qos) || !dev->power.qos->flags_req) {
733 ret = -EINVAL; 714 ret = -EINVAL;
734 goto out; 715 goto out;
735 } 716 }
@@ -747,4 +728,7 @@ int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
747 pm_runtime_put(dev); 728 pm_runtime_put(dev);
748 return ret; 729 return ret;
749} 730}
731#else /* !CONFIG_PM_RUNTIME */
732static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
733static void __dev_pm_qos_hide_flags(struct device *dev) {}
750#endif /* CONFIG_PM_RUNTIME */ 734#endif /* CONFIG_PM_RUNTIME */
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 50d16e3cb0a9..a53ebd265701 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -708,6 +708,7 @@ void rpm_sysfs_remove(struct device *dev)
708 708
709void dpm_sysfs_remove(struct device *dev) 709void dpm_sysfs_remove(struct device *dev)
710{ 710{
711 dev_pm_qos_constraints_destroy(dev);
711 rpm_sysfs_remove(dev); 712 rpm_sysfs_remove(dev);
712 sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); 713 sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group);
713 sysfs_remove_group(&dev->kobj, &pm_attr_group); 714 sysfs_remove_group(&dev->kobj, &pm_attr_group);