aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/qos.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/qos.c')
-rw-r--r--drivers/base/power/qos.c89
1 files changed, 75 insertions, 14 deletions
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index cc4c541398aa..8d0b81151c14 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -17,6 +17,12 @@
17 * 17 *
18 * This QoS design is best effort based. Dependents register their QoS needs. 18 * This QoS design is best effort based. Dependents register their QoS needs.
19 * Watchers register to keep track of the current QoS needs of the system. 19 * Watchers register to keep track of the current QoS needs of the system.
20 * Watchers can register different types of notification callbacks:
21 * . a per-device notification callback using the dev_pm_qos_*_notifier API.
22 * The notification chain data is stored in the per-device constraint
23 * data struct.
24 * . a system-wide notification callback using the dev_pm_qos_*_global_notifier
25 * API. The notification chain data is stored in a static variable.
20 * 26 *
21 * Note about the per-device constraint data struct allocation: 27 * Note about the per-device constraint data struct allocation:
22 * . The per-device constraints data struct ptr is tored into the device 28 * . The per-device constraints data struct ptr is tored into the device
@@ -45,6 +51,36 @@
45 51
46 52
47static DEFINE_MUTEX(dev_pm_qos_mtx); 53static DEFINE_MUTEX(dev_pm_qos_mtx);
54static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
55
56/*
57 * apply_constraint
58 * @req: constraint request to apply
59 * @action: action to perform add/update/remove, of type enum pm_qos_req_action
60 * @value: defines the qos request
61 *
62 * Internal function to update the constraints list using the PM QoS core
63 * code and if needed call the per-device and the global notification
64 * callbacks
65 */
66static int apply_constraint(struct dev_pm_qos_request *req,
67 enum pm_qos_req_action action, int value)
68{
69 int ret, curr_value;
70
71 ret = pm_qos_update_target(req->dev->power.constraints,
72 &req->node, action, value);
73
74 if (ret) {
75 /* Call the global callbacks if needed */
76 curr_value = pm_qos_read_value(req->dev->power.constraints);
77 blocking_notifier_call_chain(&dev_pm_notifiers,
78 (unsigned long)curr_value,
79 req);
80 }
81
82 return ret;
83}
48 84
49/* 85/*
50 * dev_pm_qos_constraints_allocate 86 * dev_pm_qos_constraints_allocate
@@ -111,12 +147,11 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
111 &dev->power.constraints->list, 147 &dev->power.constraints->list,
112 node) { 148 node) {
113 /* 149 /*
114 * Update constraints list and call the per-device 150 * Update constraints list and call the notification
115 * callbacks if needed 151 * callbacks if needed
116 */ 152 */
117 pm_qos_update_target(req->dev->power.constraints, 153 apply_constraint(req, PM_QOS_REMOVE_REQ,
118 &req->node, PM_QOS_REMOVE_REQ, 154 PM_QOS_DEFAULT_VALUE);
119 PM_QOS_DEFAULT_VALUE);
120 memset(req, 0, sizeof(*req)); 155 memset(req, 0, sizeof(*req));
121 } 156 }
122 157
@@ -147,7 +182,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
147 * removed from the system 182 * removed from the system
148 */ 183 */
149int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, 184int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
150 s32 value) 185 s32 value)
151{ 186{
152 int ret = 0; 187 int ret = 0;
153 188
@@ -178,8 +213,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
178 ret = dev_pm_qos_constraints_allocate(dev); 213 ret = dev_pm_qos_constraints_allocate(dev);
179 214
180 if (!ret) 215 if (!ret)
181 ret = pm_qos_update_target(dev->power.constraints, &req->node, 216 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
182 PM_QOS_ADD_REQ, value);
183 217
184out: 218out:
185 mutex_unlock(&dev_pm_qos_mtx); 219 mutex_unlock(&dev_pm_qos_mtx);
@@ -220,10 +254,8 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
220 254
221 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) { 255 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) {
222 if (new_value != req->node.prio) 256 if (new_value != req->node.prio)
223 ret = pm_qos_update_target(req->dev->power.constraints, 257 ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
224 &req->node, 258 new_value);
225 PM_QOS_UPDATE_REQ,
226 new_value);
227 } else { 259 } else {
228 /* Return if the device has been removed */ 260 /* Return if the device has been removed */
229 ret = -ENODEV; 261 ret = -ENODEV;
@@ -262,9 +294,8 @@ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
262 mutex_lock(&dev_pm_qos_mtx); 294 mutex_lock(&dev_pm_qos_mtx);
263 295
264 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) { 296 if (req->dev->power.constraints_state == DEV_PM_QOS_ALLOCATED) {
265 ret = pm_qos_update_target(req->dev->power.constraints, 297 ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
266 &req->node, PM_QOS_REMOVE_REQ, 298 PM_QOS_DEFAULT_VALUE);
267 PM_QOS_DEFAULT_VALUE);
268 memset(req, 0, sizeof(*req)); 299 memset(req, 0, sizeof(*req));
269 } else { 300 } else {
270 /* Return if the device has been removed */ 301 /* Return if the device has been removed */
@@ -336,3 +367,33 @@ out:
336 return retval; 367 return retval;
337} 368}
338EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier); 369EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
370
371/**
372 * dev_pm_qos_add_global_notifier - sets notification entry for changes to
373 * target value of the PM QoS constraints for any device
374 *
375 * @notifier: notifier block managed by caller.
376 *
377 * Will register the notifier into a notification chain that gets called
378 * upon changes to the target value for any device.
379 */
380int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
381{
382 return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
383}
384EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
385
386/**
387 * dev_pm_qos_remove_global_notifier - deletes notification for changes to
388 * target value of PM QoS constraints for any device
389 *
390 * @notifier: notifier block to be removed.
391 *
392 * Will remove the notifier from the notification chain that gets called
393 * upon changes to the target value for any device.
394 */
395int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
396{
397 return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
398}
399EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);