aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power
diff options
context:
space:
mode:
authorJean Pihet <j-pihet@ti.com>2011-08-25 09:35:47 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-08-25 09:35:47 -0400
commitb66213cdb002b08b29603d488c451dfe25e2ca20 (patch)
treeeebdfa34524d5cd40f30c722098e8c51457a15e0 /drivers/base/power
parent91ff4cb803df6de9114351b9f2f0f39f397ee03e (diff)
PM QoS: Add global notification mechanism for device constraints
Add a global notification chain that gets called upon changes to the aggregated constraint value for any device. The notification callbacks are passing the full constraint request data in order for the callees to have access to it. The current use is for the platform low-level code to access the target device of the constraint. Signed-off-by: Jean Pihet <j-pihet@ti.com> Reviewed-by: Kevin Hilman <khilman@ti.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power')
-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);