PM / QoS: Introduce PM QoS device flags support
[deliverable/linux.git] / drivers / base / power / qos.c
CommitLineData
91ff4cb8
JP
1/*
2 * Devices PM QoS constraints management
3 *
4 * Copyright (C) 2011 Texas Instruments, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 *
11 * This module exposes the interface to kernel space for specifying
12 * per-device PM QoS dependencies. It provides infrastructure for registration
13 * of:
14 *
15 * Dependents on a QoS value : register requests
16 * Watchers of QoS value : get notified when target QoS value changes
17 *
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.
b66213cd
JP
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.
91ff4cb8
JP
26 *
27 * Note about the per-device constraint data struct allocation:
28 * . The per-device constraints data struct ptr is tored into the device
29 * dev_pm_info.
30 * . To minimize the data usage by the per-device constraints, the data struct
31 * is only allocated at the first call to dev_pm_qos_add_request.
32 * . The data is later free'd when the device is removed from the system.
91ff4cb8
JP
33 * . A global mutex protects the constraints users from the data being
34 * allocated and free'd.
35 */
36
37#include <linux/pm_qos.h>
38#include <linux/spinlock.h>
39#include <linux/slab.h>
40#include <linux/device.h>
41#include <linux/mutex.h>
1b6bc32f 42#include <linux/export.h>
91ff4cb8 43
85dc0b8a 44#include "power.h"
91ff4cb8
JP
45
46static DEFINE_MUTEX(dev_pm_qos_mtx);
1a9a9152 47
b66213cd
JP
48static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
49
ae0fb4b7
RW
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
1a9a9152 94/**
00dc9ad1
RW
95 * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
96 * @dev: Device to get the PM QoS constraint value for.
97 *
98 * This routine must be called with dev->power.lock held.
99 */
100s32 __dev_pm_qos_read_value(struct device *dev)
101{
5f986c59 102 return dev->power.qos ? pm_qos_read_value(&dev->power.qos->latency) : 0;
00dc9ad1
RW
103}
104
105/**
106 * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
1a9a9152
RW
107 * @dev: Device to get the PM QoS constraint value for.
108 */
109s32 dev_pm_qos_read_value(struct device *dev)
110{
1a9a9152 111 unsigned long flags;
00dc9ad1 112 s32 ret;
1a9a9152
RW
113
114 spin_lock_irqsave(&dev->power.lock, flags);
00dc9ad1 115 ret = __dev_pm_qos_read_value(dev);
1a9a9152
RW
116 spin_unlock_irqrestore(&dev->power.lock, flags);
117
118 return ret;
119}
120
ae0fb4b7
RW
121/**
122 * apply_constraint - Add/modify/remove device PM QoS request.
123 * @req: Constraint request to apply
124 * @action: Action to perform (add/update/remove).
125 * @value: Value to assign to the QoS request.
b66213cd
JP
126 *
127 * Internal function to update the constraints list using the PM QoS core
128 * code and if needed call the per-device and the global notification
129 * callbacks
130 */
131static int apply_constraint(struct dev_pm_qos_request *req,
ae0fb4b7 132 enum pm_qos_req_action action, s32 value)
b66213cd 133{
ae0fb4b7
RW
134 struct dev_pm_qos *qos = req->dev->power.qos;
135 int ret;
b66213cd 136
ae0fb4b7
RW
137 switch(req->type) {
138 case DEV_PM_QOS_LATENCY:
139 ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
140 action, value);
141 if (ret) {
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;
b66213cd
JP
154 }
155
156 return ret;
157}
91ff4cb8
JP
158
159/*
160 * dev_pm_qos_constraints_allocate
161 * @dev: device to allocate data for
162 *
163 * Called at the first call to add_request, for constraint data allocation
164 * Must be called with the dev_pm_qos_mtx mutex held
165 */
166static int dev_pm_qos_constraints_allocate(struct device *dev)
167{
5f986c59 168 struct dev_pm_qos *qos;
91ff4cb8
JP
169 struct pm_qos_constraints *c;
170 struct blocking_notifier_head *n;
171
5f986c59
RW
172 qos = kzalloc(sizeof(*qos), GFP_KERNEL);
173 if (!qos)
91ff4cb8
JP
174 return -ENOMEM;
175
176 n = kzalloc(sizeof(*n), GFP_KERNEL);
177 if (!n) {
5f986c59 178 kfree(qos);
91ff4cb8
JP
179 return -ENOMEM;
180 }
181 BLOCKING_INIT_NOTIFIER_HEAD(n);
182
5f986c59 183 c = &qos->latency;
1a9a9152
RW
184 plist_head_init(&c->list);
185 c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
186 c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
187 c->type = PM_QOS_MIN;
188 c->notifiers = n;
189
ae0fb4b7
RW
190 INIT_LIST_HEAD(&qos->flags.list);
191
1a9a9152 192 spin_lock_irq(&dev->power.lock);
5f986c59 193 dev->power.qos = qos;
1a9a9152 194 spin_unlock_irq(&dev->power.lock);
91ff4cb8
JP
195
196 return 0;
197}
198
199/**
1a9a9152 200 * dev_pm_qos_constraints_init - Initalize device's PM QoS constraints pointer.
91ff4cb8
JP
201 * @dev: target device
202 *
1a9a9152
RW
203 * Called from the device PM subsystem during device insertion under
204 * device_pm_lock().
91ff4cb8
JP
205 */
206void dev_pm_qos_constraints_init(struct device *dev)
207{
208 mutex_lock(&dev_pm_qos_mtx);
5f986c59 209 dev->power.qos = NULL;
1a9a9152 210 dev->power.power_state = PMSG_ON;
91ff4cb8
JP
211 mutex_unlock(&dev_pm_qos_mtx);
212}
213
214/**
215 * dev_pm_qos_constraints_destroy
216 * @dev: target device
217 *
1a9a9152 218 * Called from the device PM subsystem on device removal under device_pm_lock().
91ff4cb8
JP
219 */
220void dev_pm_qos_constraints_destroy(struct device *dev)
221{
5f986c59 222 struct dev_pm_qos *qos;
91ff4cb8 223 struct dev_pm_qos_request *req, *tmp;
1a9a9152 224 struct pm_qos_constraints *c;
91ff4cb8 225
85dc0b8a
RW
226 /*
227 * If the device's PM QoS resume latency limit has been exposed to user
228 * space, it has to be hidden at this point.
229 */
230 dev_pm_qos_hide_latency_limit(dev);
231
91ff4cb8
JP
232 mutex_lock(&dev_pm_qos_mtx);
233
1a9a9152 234 dev->power.power_state = PMSG_INVALID;
5f986c59
RW
235 qos = dev->power.qos;
236 if (!qos)
1a9a9152 237 goto out;
91ff4cb8 238
5f986c59 239 c = &qos->latency;
1a9a9152 240 /* Flush the constraints list for the device */
021c870b 241 plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
1a9a9152
RW
242 /*
243 * Update constraints list and call the notification
244 * callbacks if needed
245 */
246 apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
247 memset(req, 0, sizeof(*req));
91ff4cb8 248 }
91ff4cb8 249
1a9a9152 250 spin_lock_irq(&dev->power.lock);
5f986c59 251 dev->power.qos = NULL;
1a9a9152
RW
252 spin_unlock_irq(&dev->power.lock);
253
254 kfree(c->notifiers);
255 kfree(c);
256
257 out:
91ff4cb8
JP
258 mutex_unlock(&dev_pm_qos_mtx);
259}
260
261/**
262 * dev_pm_qos_add_request - inserts new qos request into the list
263 * @dev: target device for the constraint
264 * @req: pointer to a preallocated handle
ae0fb4b7 265 * @type: type of the request
91ff4cb8
JP
266 * @value: defines the qos request
267 *
268 * This function inserts a new entry in the device constraints list of
269 * requested qos performance characteristics. It recomputes the aggregate
270 * QoS expectations of parameters and initializes the dev_pm_qos_request
271 * handle. Caller needs to save this handle for later use in updates and
272 * removal.
273 *
274 * Returns 1 if the aggregated constraint value has changed,
275 * 0 if the aggregated constraint value has not changed,
1a9a9152
RW
276 * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
277 * to allocate for data structures, -ENODEV if the device has just been removed
278 * from the system.
91ff4cb8
JP
279 */
280int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
ae0fb4b7 281 enum dev_pm_qos_req_type type, s32 value)
91ff4cb8
JP
282{
283 int ret = 0;
284
285 if (!dev || !req) /*guard against callers passing in null */
286 return -EINVAL;
287
af4c720e
GL
288 if (WARN(dev_pm_qos_request_active(req),
289 "%s() called for already added request\n", __func__))
91ff4cb8 290 return -EINVAL;
91ff4cb8 291
91ff4cb8
JP
292 req->dev = dev;
293
1a9a9152 294 mutex_lock(&dev_pm_qos_mtx);
91ff4cb8 295
5f986c59 296 if (!dev->power.qos) {
1a9a9152
RW
297 if (dev->power.power_state.event == PM_EVENT_INVALID) {
298 /* The device has been removed from the system. */
299 req->dev = NULL;
300 ret = -ENODEV;
301 goto out;
302 } else {
303 /*
304 * Allocate the constraints data on the first call to
305 * add_request, i.e. only if the data is not already
306 * allocated and if the device has not been removed.
307 */
308 ret = dev_pm_qos_constraints_allocate(dev);
309 }
310 }
91ff4cb8 311
ae0fb4b7
RW
312 if (!ret) {
313 req->type = type;
b66213cd 314 ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
ae0fb4b7 315 }
91ff4cb8 316
1a9a9152 317 out:
91ff4cb8 318 mutex_unlock(&dev_pm_qos_mtx);
1a9a9152 319
91ff4cb8
JP
320 return ret;
321}
322EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
323
324/**
325 * dev_pm_qos_update_request - modifies an existing qos request
326 * @req : handle to list element holding a dev_pm_qos request to use
327 * @new_value: defines the qos request
328 *
329 * Updates an existing dev PM qos request along with updating the
330 * target value.
331 *
332 * Attempts are made to make this code callable on hot code paths.
333 *
334 * Returns 1 if the aggregated constraint value has changed,
335 * 0 if the aggregated constraint value has not changed,
336 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
337 * removed from the system
338 */
339int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
340 s32 new_value)
341{
ae0fb4b7 342 s32 curr_value;
91ff4cb8
JP
343 int ret = 0;
344
345 if (!req) /*guard against callers passing in null */
346 return -EINVAL;
347
af4c720e
GL
348 if (WARN(!dev_pm_qos_request_active(req),
349 "%s() called for unknown object\n", __func__))
91ff4cb8 350 return -EINVAL;
91ff4cb8
JP
351
352 mutex_lock(&dev_pm_qos_mtx);
353
ae0fb4b7 354 if (!req->dev->power.qos) {
91ff4cb8 355 ret = -ENODEV;
ae0fb4b7 356 goto out;
91ff4cb8
JP
357 }
358
ae0fb4b7
RW
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:
91ff4cb8
JP
375 mutex_unlock(&dev_pm_qos_mtx);
376 return ret;
377}
378EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
379
380/**
381 * dev_pm_qos_remove_request - modifies an existing qos request
382 * @req: handle to request list element
383 *
384 * Will remove pm qos request from the list of constraints and
385 * recompute the current target value. Call this on slow code paths.
386 *
387 * Returns 1 if the aggregated constraint value has changed,
388 * 0 if the aggregated constraint value has not changed,
389 * -EINVAL in case of wrong parameters, -ENODEV if the device has been
390 * removed from the system
391 */
392int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
393{
394 int ret = 0;
395
396 if (!req) /*guard against callers passing in null */
397 return -EINVAL;
398
af4c720e
GL
399 if (WARN(!dev_pm_qos_request_active(req),
400 "%s() called for unknown object\n", __func__))
91ff4cb8 401 return -EINVAL;
91ff4cb8
JP
402
403 mutex_lock(&dev_pm_qos_mtx);
404
5f986c59 405 if (req->dev->power.qos) {
b66213cd
JP
406 ret = apply_constraint(req, PM_QOS_REMOVE_REQ,
407 PM_QOS_DEFAULT_VALUE);
91ff4cb8
JP
408 memset(req, 0, sizeof(*req));
409 } else {
410 /* Return if the device has been removed */
411 ret = -ENODEV;
412 }
413
414 mutex_unlock(&dev_pm_qos_mtx);
415 return ret;
416}
417EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
418
419/**
420 * dev_pm_qos_add_notifier - sets notification entry for changes to target value
421 * of per-device PM QoS constraints
422 *
423 * @dev: target device for the constraint
424 * @notifier: notifier block managed by caller.
425 *
426 * Will register the notifier into a notification chain that gets called
427 * upon changes to the target value for the device.
23e0fc5a
RW
428 *
429 * If the device's constraints object doesn't exist when this routine is called,
430 * it will be created (or error code will be returned if that fails).
91ff4cb8
JP
431 */
432int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
433{
23e0fc5a 434 int ret = 0;
91ff4cb8
JP
435
436 mutex_lock(&dev_pm_qos_mtx);
437
5f986c59 438 if (!dev->power.qos)
23e0fc5a
RW
439 ret = dev->power.power_state.event != PM_EVENT_INVALID ?
440 dev_pm_qos_constraints_allocate(dev) : -ENODEV;
441
442 if (!ret)
443 ret = blocking_notifier_chain_register(
5f986c59 444 dev->power.qos->latency.notifiers, notifier);
91ff4cb8 445
91ff4cb8 446 mutex_unlock(&dev_pm_qos_mtx);
23e0fc5a 447 return ret;
91ff4cb8
JP
448}
449EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
450
451/**
452 * dev_pm_qos_remove_notifier - deletes notification for changes to target value
453 * of per-device PM QoS constraints
454 *
455 * @dev: target device for the constraint
456 * @notifier: notifier block to be removed.
457 *
458 * Will remove the notifier from the notification chain that gets called
459 * upon changes to the target value.
460 */
461int dev_pm_qos_remove_notifier(struct device *dev,
462 struct notifier_block *notifier)
463{
464 int retval = 0;
465
466 mutex_lock(&dev_pm_qos_mtx);
467
1a9a9152 468 /* Silently return if the constraints object is not present. */
5f986c59 469 if (dev->power.qos)
1a9a9152 470 retval = blocking_notifier_chain_unregister(
5f986c59 471 dev->power.qos->latency.notifiers,
1a9a9152 472 notifier);
91ff4cb8 473
91ff4cb8
JP
474 mutex_unlock(&dev_pm_qos_mtx);
475 return retval;
476}
477EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
b66213cd
JP
478
479/**
480 * dev_pm_qos_add_global_notifier - sets notification entry for changes to
481 * target value of the PM QoS constraints for any device
482 *
483 * @notifier: notifier block managed by caller.
484 *
485 * Will register the notifier into a notification chain that gets called
486 * upon changes to the target value for any device.
487 */
488int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
489{
490 return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
491}
492EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
493
494/**
495 * dev_pm_qos_remove_global_notifier - deletes notification for changes to
496 * target value of PM QoS constraints for any device
497 *
498 * @notifier: notifier block to be removed.
499 *
500 * Will remove the notifier from the notification chain that gets called
501 * upon changes to the target value for any device.
502 */
503int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
504{
505 return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
506}
507EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
40a5f8be
RW
508
509/**
510 * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
511 * @dev: Device whose ancestor to add the request for.
512 * @req: Pointer to the preallocated handle.
513 * @value: Constraint latency value.
514 */
515int dev_pm_qos_add_ancestor_request(struct device *dev,
516 struct dev_pm_qos_request *req, s32 value)
517{
518 struct device *ancestor = dev->parent;
519 int error = -ENODEV;
520
521 while (ancestor && !ancestor->power.ignore_children)
522 ancestor = ancestor->parent;
523
524 if (ancestor)
ae0fb4b7
RW
525 error = dev_pm_qos_add_request(ancestor, req,
526 DEV_PM_QOS_LATENCY, value);
40a5f8be
RW
527
528 if (error)
529 req->dev = NULL;
530
531 return error;
532}
533EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
85dc0b8a
RW
534
535#ifdef CONFIG_PM_RUNTIME
536static void __dev_pm_qos_drop_user_request(struct device *dev)
537{
538 dev_pm_qos_remove_request(dev->power.pq_req);
ad0446eb 539 dev->power.pq_req = NULL;
85dc0b8a
RW
540}
541
542/**
543 * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
544 * @dev: Device whose PM QoS latency limit is to be exposed to user space.
545 * @value: Initial value of the latency limit.
546 */
547int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
548{
549 struct dev_pm_qos_request *req;
550 int ret;
551
552 if (!device_is_registered(dev) || value < 0)
553 return -EINVAL;
554
555 if (dev->power.pq_req)
556 return -EEXIST;
557
558 req = kzalloc(sizeof(*req), GFP_KERNEL);
559 if (!req)
560 return -ENOMEM;
561
ae0fb4b7 562 ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
85dc0b8a
RW
563 if (ret < 0)
564 return ret;
565
566 dev->power.pq_req = req;
567 ret = pm_qos_sysfs_add(dev);
568 if (ret)
569 __dev_pm_qos_drop_user_request(dev);
570
571 return ret;
572}
573EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
574
575/**
576 * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
577 * @dev: Device whose PM QoS latency limit is to be hidden from user space.
578 */
579void dev_pm_qos_hide_latency_limit(struct device *dev)
580{
581 if (dev->power.pq_req) {
582 pm_qos_sysfs_remove(dev);
583 __dev_pm_qos_drop_user_request(dev);
584 }
585}
586EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
587#endif /* CONFIG_PM_RUNTIME */
This page took 0.110587 seconds and 5 git commands to generate.