aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/qos.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-10-22 19:09:12 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-10-22 19:09:12 -0400
commitae0fb4b72c8db7e6c4ef32bc58a43a759ad414b9 (patch)
tree41f5b9014613d865ca69fe25ceb8fcc05c22b2f1 /drivers/base/power/qos.c
parent021c870ba4ab4bc9a23d5db4e324f50f26d8ab24 (diff)
PM / QoS: Introduce PM QoS device flags support
Modify the device PM QoS core code to support PM QoS flags requests. First, add a new field of type struct pm_qos_flags called "flags" to struct dev_pm_qos for representing the list of PM QoS flags requests for the given device. Accordingly, add a new "type" field to struct dev_pm_qos_request (along with an enum for representing request types) and a new member called "flr" to its data union for representig flags requests. Second, modify dev_pm_qos_add_request(), dev_pm_qos_update_request(), the internal routine apply_constraint() used by them and their existing callers to cover flags requests as well as latency requests. In particular, dev_pm_qos_add_request() gets a new argument called "type" for specifying the type of a request to be added. Finally, introduce two routines, __dev_pm_qos_flags() and dev_pm_qos_flags(), allowing their callers to check which PM QoS flags have been requested for the given device (the caller is supposed to pass the mask of flags to check as the routine's second argument and examine its return value for the result). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Jean Pihet <j-pihet@ti.com> Reviewed-by: mark gross <markgross@thegnar.org>
Diffstat (limited to 'drivers/base/power/qos.c')
-rw-r--r--drivers/base/power/qos.c124
1 files changed, 98 insertions, 26 deletions
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 96d27b821bb8..3c66f75d14b0 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -48,6 +48,50 @@ static DEFINE_MUTEX(dev_pm_qos_mtx);
48static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); 48static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
49 49
50/** 50/**
51 * __dev_pm_qos_flags - Check PM QoS flags for a given device.
52 * @dev: Device to check the PM QoS flags for.
53 * @mask: Flags to check against.
54 *
55 * This routine must be called with dev->power.lock held.
56 */
57enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
58{
59 struct dev_pm_qos *qos = dev->power.qos;
60 struct pm_qos_flags *pqf;
61 s32 val;
62
63 if (!qos)
64 return PM_QOS_FLAGS_UNDEFINED;
65
66 pqf = &qos->flags;
67 if (list_empty(&pqf->list))
68 return PM_QOS_FLAGS_UNDEFINED;
69
70 val = pqf->effective_flags & mask;
71 if (val)
72 return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;
73
74 return PM_QOS_FLAGS_NONE;
75}
76
77/**
78 * dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
79 * @dev: Device to check the PM QoS flags for.
80 * @mask: Flags to check against.
81 */
82enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
83{
84 unsigned long irqflags;
85 enum pm_qos_flags_status ret;
86
87 spin_lock_irqsave(&dev->power.lock, irqflags);
88 ret = __dev_pm_qos_flags(dev, mask);
89 spin_unlock_irqrestore(&dev->power.lock, irqflags);
90
91 return ret;
92}
93
94/**
51 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device. 95 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
52 * @dev: Device to get the PM QoS constraint value for. 96 * @dev: Device to get the PM QoS constraint value for.
53 * 97 *
@@ -74,30 +118,39 @@ s32 dev_pm_qos_read_value(struct device *dev)
74 return ret; 118 return ret;
75} 119}
76 120
77/* 121/**
78 * apply_constraint 122 * apply_constraint - Add/modify/remove device PM QoS request.
79 * @req: constraint request to apply 123 * @req: Constraint request to apply
80 * @action: action to perform add/update/remove, of type enum pm_qos_req_action 124 * @action: Action to perform (add/update/remove).
81 * @value: defines the qos request 125 * @value: Value to assign to the QoS request.
82 * 126 *
83 * Internal function to update the constraints list using the PM QoS core 127 * Internal function to update the constraints list using the PM QoS core
84 * code and if needed call the per-device and the global notification 128 * code and if needed call the per-device and the global notification
85 * callbacks 129 * callbacks
86 */ 130 */
87static int apply_constraint(struct dev_pm_qos_request *req, 131static int apply_constraint(struct dev_pm_qos_request *req,
88 enum pm_qos_req_action action, int value) 132 enum pm_qos_req_action action, s32 value)
89{ 133{
90 int ret, curr_value; 134 struct dev_pm_qos *qos = req->dev->power.qos;
91 135 int ret;
92 ret = pm_qos_update_target(&req->dev->power.qos->latency,
93 &req->data.pnode, action, value);
94 136
95 if (ret) { 137 switch(req->type) {
96 /* Call the global callbacks if needed */ 138 case DEV_PM_QOS_LATENCY:
97 curr_value = pm_qos_read_value(&req->dev->power.qos->latency); 139 ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
98 blocking_notifier_call_chain(&dev_pm_notifiers, 140 action, value);
99 (unsigned long)curr_value, 141 if (ret) {
100 req); 142 value = pm_qos_read_value(&qos->latency);
143 blocking_notifier_call_chain(&dev_pm_notifiers,
144 (unsigned long)value,
145 req);
146 }
147 break;
148 case DEV_PM_QOS_FLAGS:
149 ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
150 action, value);
151 break;
152 default:
153 ret = -EINVAL;
101 } 154 }
102 155
103 return ret; 156 return ret;
@@ -134,6 +187,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
134 c->type = PM_QOS_MIN; 187 c->type = PM_QOS_MIN;
135 c->notifiers = n; 188 c->notifiers = n;
136 189
190 INIT_LIST_HEAD(&qos->flags.list);
191
137 spin_lock_irq(&dev->power.lock); 192 spin_lock_irq(&dev->power.lock);
138 dev->power.qos = qos; 193 dev->power.qos = qos;
139 spin_unlock_irq(&dev->power.lock); 194 spin_unlock_irq(&dev->power.lock);
@@ -207,6 +262,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
207 * dev_pm_qos_add_request - inserts new qos request into the list 262 * dev_pm_qos_add_request - inserts new qos request into the list
208 * @dev: target device for the constraint 263 * @dev: target device for the constraint
209 * @req: pointer to a preallocated handle 264 * @req: pointer to a preallocated handle
265 * @type: type of the request
210 * @value: defines the qos request 266 * @value: defines the qos request
211 * 267 *
212 * This function inserts a new entry in the device constraints list of 268 * This function inserts a new entry in the device constraints list of
@@ -222,7 +278,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
222 * from the system. 278 * from the system.
223 */ 279 */
224int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, 280int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
225 s32 value) 281 enum dev_pm_qos_req_type type, s32 value)
226{ 282{
227 int ret = 0; 283 int ret = 0;
228 284
@@ -253,8 +309,10 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
253 } 309 }
254 } 310 }
255 311
256 if (!ret) 312 if (!ret) {
313 req->type = type;
257 ret = apply_constraint(req, PM_QOS_ADD_REQ, value); 314 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
315 }
258 316
259 out: 317 out:
260 mutex_unlock(&dev_pm_qos_mtx); 318 mutex_unlock(&dev_pm_qos_mtx);
@@ -281,6 +339,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
281int dev_pm_qos_update_request(struct dev_pm_qos_request *req, 339int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
282 s32 new_value) 340 s32 new_value)
283{ 341{
342 s32 curr_value;
284 int ret = 0; 343 int ret = 0;
285 344
286 if (!req) /*guard against callers passing in null */ 345 if (!req) /*guard against callers passing in null */
@@ -292,15 +351,27 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
292 351
293 mutex_lock(&dev_pm_qos_mtx); 352 mutex_lock(&dev_pm_qos_mtx);
294 353
295 if (req->dev->power.qos) { 354 if (!req->dev->power.qos) {
296 if (new_value != req->data.pnode.prio)
297 ret = apply_constraint(req, PM_QOS_UPDATE_REQ,
298 new_value);
299 } else {
300 /* Return if the device has been removed */
301 ret = -ENODEV; 355 ret = -ENODEV;
356 goto out;
302 } 357 }
303 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:
304 mutex_unlock(&dev_pm_qos_mtx); 375 mutex_unlock(&dev_pm_qos_mtx);
305 return ret; 376 return ret;
306} 377}
@@ -451,7 +522,8 @@ int dev_pm_qos_add_ancestor_request(struct device *dev,
451 ancestor = ancestor->parent; 522 ancestor = ancestor->parent;
452 523
453 if (ancestor) 524 if (ancestor)
454 error = dev_pm_qos_add_request(ancestor, req, value); 525 error = dev_pm_qos_add_request(ancestor, req,
526 DEV_PM_QOS_LATENCY, value);
455 527
456 if (error) 528 if (error)
457 req->dev = NULL; 529 req->dev = NULL;
@@ -487,7 +559,7 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
487 if (!req) 559 if (!req)
488 return -ENOMEM; 560 return -ENOMEM;
489 561
490 ret = dev_pm_qos_add_request(dev, req, value); 562 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
491 if (ret < 0) 563 if (ret < 0)
492 return ret; 564 return ret;
493 565