Branch data Line data Source code
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.
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.
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.
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>
42 : : #include <linux/export.h>
43 : : #include <linux/pm_runtime.h>
44 : : #include <linux/err.h>
45 : : #include <trace/events/power.h>
46 : :
47 : : #include "power.h"
48 : :
49 : : static DEFINE_MUTEX(dev_pm_qos_mtx);
50 : : static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
51 : :
52 : : static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
53 : :
54 : : /**
55 : : * __dev_pm_qos_flags - Check PM QoS flags for a given device.
56 : : * @dev: Device to check the PM QoS flags for.
57 : : * @mask: Flags to check against.
58 : : *
59 : : * This routine must be called with dev->power.lock held.
60 : : */
61 : 0 : enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
62 : : {
63 : 0 : struct dev_pm_qos *qos = dev->power.qos;
64 : : struct pm_qos_flags *pqf;
65 : : s32 val;
66 : :
67 [ # # ]: 0 : if (IS_ERR_OR_NULL(qos))
68 : : return PM_QOS_FLAGS_UNDEFINED;
69 : :
70 : : pqf = &qos->flags;
71 [ # # ]: 0 : if (list_empty(&pqf->list))
72 : : return PM_QOS_FLAGS_UNDEFINED;
73 : :
74 : 0 : val = pqf->effective_flags & mask;
75 [ # # ]: 0 : if (val)
76 [ # # ]: 0 : return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;
77 : :
78 : : return PM_QOS_FLAGS_NONE;
79 : : }
80 : :
81 : : /**
82 : : * dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
83 : : * @dev: Device to check the PM QoS flags for.
84 : : * @mask: Flags to check against.
85 : : */
86 : 0 : enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
87 : : {
88 : : unsigned long irqflags;
89 : : enum pm_qos_flags_status ret;
90 : :
91 : 0 : spin_lock_irqsave(&dev->power.lock, irqflags);
92 : 0 : ret = __dev_pm_qos_flags(dev, mask);
93 : : spin_unlock_irqrestore(&dev->power.lock, irqflags);
94 : :
95 : 0 : return ret;
96 : : }
97 : : EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
98 : :
99 : : /**
100 : : * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
101 : : * @dev: Device to get the PM QoS constraint value for.
102 : : *
103 : : * This routine must be called with dev->power.lock held.
104 : : */
105 : 0 : s32 __dev_pm_qos_read_value(struct device *dev)
106 : : {
107 : 0 : return IS_ERR_OR_NULL(dev->power.qos) ?
108 [ # # ]: 0 : 0 : pm_qos_read_value(&dev->power.qos->latency);
109 : : }
110 : :
111 : : /**
112 : : * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
113 : : * @dev: Device to get the PM QoS constraint value for.
114 : : */
115 : 0 : s32 dev_pm_qos_read_value(struct device *dev)
116 : : {
117 : : unsigned long flags;
118 : : s32 ret;
119 : :
120 : 0 : spin_lock_irqsave(&dev->power.lock, flags);
121 : 0 : ret = __dev_pm_qos_read_value(dev);
122 : : spin_unlock_irqrestore(&dev->power.lock, flags);
123 : :
124 : 0 : return ret;
125 : : }
126 : :
127 : : /**
128 : : * apply_constraint - Add/modify/remove device PM QoS request.
129 : : * @req: Constraint request to apply
130 : : * @action: Action to perform (add/update/remove).
131 : : * @value: Value to assign to the QoS request.
132 : : *
133 : : * Internal function to update the constraints list using the PM QoS core
134 : : * code and if needed call the per-device and the global notification
135 : : * callbacks
136 : : */
137 : 0 : static int apply_constraint(struct dev_pm_qos_request *req,
138 : : enum pm_qos_req_action action, s32 value)
139 : : {
140 : 0 : struct dev_pm_qos *qos = req->dev->power.qos;
141 : : int ret;
142 : :
143 [ # # # ]: 0 : switch(req->type) {
144 : : case DEV_PM_QOS_LATENCY:
145 : 0 : ret = pm_qos_update_target(&qos->latency, &req->data.pnode,
146 : : action, value);
147 [ # # ]: 0 : if (ret) {
148 : 0 : value = pm_qos_read_value(&qos->latency);
149 : 0 : blocking_notifier_call_chain(&dev_pm_notifiers,
150 : : (unsigned long)value,
151 : : req);
152 : : }
153 : : break;
154 : : case DEV_PM_QOS_FLAGS:
155 : 0 : ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
156 : : action, value);
157 : 0 : break;
158 : : default:
159 : : ret = -EINVAL;
160 : : }
161 : :
162 : 0 : return ret;
163 : : }
164 : :
165 : : /*
166 : : * dev_pm_qos_constraints_allocate
167 : : * @dev: device to allocate data for
168 : : *
169 : : * Called at the first call to add_request, for constraint data allocation
170 : : * Must be called with the dev_pm_qos_mtx mutex held
171 : : */
172 : 0 : static int dev_pm_qos_constraints_allocate(struct device *dev)
173 : : {
174 : : struct dev_pm_qos *qos;
175 : : struct pm_qos_constraints *c;
176 : : struct blocking_notifier_head *n;
177 : :
178 : : qos = kzalloc(sizeof(*qos), GFP_KERNEL);
179 [ # # ]: 0 : if (!qos)
180 : : return -ENOMEM;
181 : :
182 : : n = kzalloc(sizeof(*n), GFP_KERNEL);
183 [ # # ]: 0 : if (!n) {
184 : 0 : kfree(qos);
185 : 0 : return -ENOMEM;
186 : : }
187 : 0 : BLOCKING_INIT_NOTIFIER_HEAD(n);
188 : :
189 : : c = &qos->latency;
190 : : plist_head_init(&c->list);
191 : 0 : c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
192 : 0 : c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE;
193 : 0 : c->type = PM_QOS_MIN;
194 : 0 : c->notifiers = n;
195 : :
196 : 0 : INIT_LIST_HEAD(&qos->flags.list);
197 : :
198 : : spin_lock_irq(&dev->power.lock);
199 : 0 : dev->power.qos = qos;
200 : : spin_unlock_irq(&dev->power.lock);
201 : :
202 : 0 : return 0;
203 : : }
204 : :
205 : : static void __dev_pm_qos_hide_latency_limit(struct device *dev);
206 : : static void __dev_pm_qos_hide_flags(struct device *dev);
207 : :
208 : : /**
209 : : * dev_pm_qos_constraints_destroy
210 : : * @dev: target device
211 : : *
212 : : * Called from the device PM subsystem on device removal under device_pm_lock().
213 : : */
214 : 0 : void dev_pm_qos_constraints_destroy(struct device *dev)
215 : : {
216 : : struct dev_pm_qos *qos;
217 : : struct dev_pm_qos_request *req, *tmp;
218 : : struct pm_qos_constraints *c;
219 : : struct pm_qos_flags *f;
220 : :
221 : 16 : mutex_lock(&dev_pm_qos_sysfs_mtx);
222 : :
223 : : /*
224 : : * If the device's PM QoS resume latency limit or PM QoS flags have been
225 : : * exposed to user space, they have to be hidden at this point.
226 : : */
227 : 16 : pm_qos_sysfs_remove_latency(dev);
228 : 16 : pm_qos_sysfs_remove_flags(dev);
229 : :
230 : 16 : mutex_lock(&dev_pm_qos_mtx);
231 : :
232 : : __dev_pm_qos_hide_latency_limit(dev);
233 : : __dev_pm_qos_hide_flags(dev);
234 : :
235 : 16 : qos = dev->power.qos;
236 [ + - ]: 16 : if (!qos)
237 : : goto out;
238 : :
239 : : /* Flush the constraints lists for the device. */
240 : : c = &qos->latency;
241 [ # # ]: 16 : plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
242 : : /*
243 : : * Update constraints list and call the notification
244 : : * callbacks if needed
245 : : */
246 : 0 : apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
247 : 0 : memset(req, 0, sizeof(*req));
248 : : }
249 : : f = &qos->flags;
250 [ # # ]: 0 : list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
251 : 0 : apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
252 : 0 : memset(req, 0, sizeof(*req));
253 : : }
254 : :
255 : : spin_lock_irq(&dev->power.lock);
256 : 0 : dev->power.qos = ERR_PTR(-ENODEV);
257 : : spin_unlock_irq(&dev->power.lock);
258 : :
259 : 0 : kfree(c->notifiers);
260 : 0 : kfree(qos);
261 : :
262 : : out:
263 : 0 : mutex_unlock(&dev_pm_qos_mtx);
264 : :
265 : 16 : mutex_unlock(&dev_pm_qos_sysfs_mtx);
266 : 16 : }
267 : :
268 : : /**
269 : : * dev_pm_qos_add_request - inserts new qos request into the list
270 : : * @dev: target device for the constraint
271 : : * @req: pointer to a preallocated handle
272 : : * @type: type of the request
273 : : * @value: defines the qos request
274 : : *
275 : : * This function inserts a new entry in the device constraints list of
276 : : * requested qos performance characteristics. It recomputes the aggregate
277 : : * QoS expectations of parameters and initializes the dev_pm_qos_request
278 : : * handle. Caller needs to save this handle for later use in updates and
279 : : * removal.
280 : : *
281 : : * Returns 1 if the aggregated constraint value has changed,
282 : : * 0 if the aggregated constraint value has not changed,
283 : : * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
284 : : * to allocate for data structures, -ENODEV if the device has just been removed
285 : : * from the system.
286 : : *
287 : : * Callers should ensure that the target device is not RPM_SUSPENDED before
288 : : * using this function for requests of type DEV_PM_QOS_FLAGS.
289 : : */
290 : 0 : int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
291 : : enum dev_pm_qos_req_type type, s32 value)
292 : : {
293 : : int ret = 0;
294 : :
295 [ # # ]: 0 : if (!dev || !req) /*guard against callers passing in null */
296 : : return -EINVAL;
297 : :
298 [ # # ][ # # ]: 0 : if (WARN(dev_pm_qos_request_active(req),
299 : : "%s() called for already added request\n", __func__))
300 : : return -EINVAL;
301 : :
302 : 0 : mutex_lock(&dev_pm_qos_mtx);
303 : :
304 [ # # ]: 0 : if (IS_ERR(dev->power.qos))
305 : : ret = -ENODEV;
306 [ # # ]: 0 : else if (!dev->power.qos)
307 : 0 : ret = dev_pm_qos_constraints_allocate(dev);
308 : :
309 : : trace_dev_pm_qos_add_request(dev_name(dev), type, value);
310 [ # # ]: 0 : if (!ret) {
311 : 0 : req->dev = dev;
312 : 0 : req->type = type;
313 : 0 : ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
314 : : }
315 : :
316 : 0 : mutex_unlock(&dev_pm_qos_mtx);
317 : :
318 : 0 : return ret;
319 : : }
320 : : EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
321 : :
322 : : /**
323 : : * __dev_pm_qos_update_request - Modify an existing device PM QoS request.
324 : : * @req : PM QoS request to modify.
325 : : * @new_value: New value to request.
326 : : */
327 : 0 : static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
328 : : s32 new_value)
329 : : {
330 : : s32 curr_value;
331 : : int ret = 0;
332 : :
333 [ # # ]: 0 : if (!req) /*guard against callers passing in null */
334 : : return -EINVAL;
335 : :
336 [ # # ][ # # ]: 0 : if (WARN(!dev_pm_qos_request_active(req),
337 : : "%s() called for unknown object\n", __func__))
338 : : return -EINVAL;
339 : :
340 [ # # ]: 0 : if (IS_ERR_OR_NULL(req->dev->power.qos))
341 : : return -ENODEV;
342 : :
343 [ # # # ]: 0 : switch(req->type) {
344 : : case DEV_PM_QOS_LATENCY:
345 : 0 : curr_value = req->data.pnode.prio;
346 : 0 : break;
347 : : case DEV_PM_QOS_FLAGS:
348 : 0 : curr_value = req->data.flr.flags;
349 : 0 : break;
350 : : default:
351 : : return -EINVAL;
352 : : }
353 : :
354 : : trace_dev_pm_qos_update_request(dev_name(req->dev), req->type,
355 : : new_value);
356 [ # # ]: 0 : if (curr_value != new_value)
357 : 0 : ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
358 : :
359 : 0 : return ret;
360 : : }
361 : :
362 : : /**
363 : : * dev_pm_qos_update_request - modifies an existing qos request
364 : : * @req : handle to list element holding a dev_pm_qos request to use
365 : : * @new_value: defines the qos request
366 : : *
367 : : * Updates an existing dev PM qos request along with updating the
368 : : * target value.
369 : : *
370 : : * Attempts are made to make this code callable on hot code paths.
371 : : *
372 : : * Returns 1 if the aggregated constraint value has changed,
373 : : * 0 if the aggregated constraint value has not changed,
374 : : * -EINVAL in case of wrong parameters, -ENODEV if the device has been
375 : : * removed from the system
376 : : *
377 : : * Callers should ensure that the target device is not RPM_SUSPENDED before
378 : : * using this function for requests of type DEV_PM_QOS_FLAGS.
379 : : */
380 : 0 : int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value)
381 : : {
382 : : int ret;
383 : :
384 : 0 : mutex_lock(&dev_pm_qos_mtx);
385 : 0 : ret = __dev_pm_qos_update_request(req, new_value);
386 : 0 : mutex_unlock(&dev_pm_qos_mtx);
387 : 0 : return ret;
388 : : }
389 : : EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
390 : :
391 : 0 : static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
392 : : {
393 : : int ret;
394 : :
395 [ # # ]: 0 : if (!req) /*guard against callers passing in null */
396 : : return -EINVAL;
397 : :
398 [ # # ][ # # ]: 0 : if (WARN(!dev_pm_qos_request_active(req),
399 : : "%s() called for unknown object\n", __func__))
400 : : return -EINVAL;
401 : :
402 [ # # ]: 0 : if (IS_ERR_OR_NULL(req->dev->power.qos))
403 : : return -ENODEV;
404 : :
405 : 0 : trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type,
406 : : PM_QOS_DEFAULT_VALUE);
407 : 0 : ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
408 : 0 : memset(req, 0, sizeof(*req));
409 : 0 : return ret;
410 : : }
411 : :
412 : : /**
413 : : * dev_pm_qos_remove_request - modifies an existing qos request
414 : : * @req: handle to request list element
415 : : *
416 : : * Will remove pm qos request from the list of constraints and
417 : : * recompute the current target value. Call this on slow code paths.
418 : : *
419 : : * Returns 1 if the aggregated constraint value has changed,
420 : : * 0 if the aggregated constraint value has not changed,
421 : : * -EINVAL in case of wrong parameters, -ENODEV if the device has been
422 : : * removed from the system
423 : : *
424 : : * Callers should ensure that the target device is not RPM_SUSPENDED before
425 : : * using this function for requests of type DEV_PM_QOS_FLAGS.
426 : : */
427 : 0 : int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
428 : : {
429 : : int ret;
430 : :
431 : 0 : mutex_lock(&dev_pm_qos_mtx);
432 : 0 : ret = __dev_pm_qos_remove_request(req);
433 : 0 : mutex_unlock(&dev_pm_qos_mtx);
434 : 0 : return ret;
435 : : }
436 : : EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
437 : :
438 : : /**
439 : : * dev_pm_qos_add_notifier - sets notification entry for changes to target value
440 : : * of per-device PM QoS constraints
441 : : *
442 : : * @dev: target device for the constraint
443 : : * @notifier: notifier block managed by caller.
444 : : *
445 : : * Will register the notifier into a notification chain that gets called
446 : : * upon changes to the target value for the device.
447 : : *
448 : : * If the device's constraints object doesn't exist when this routine is called,
449 : : * it will be created (or error code will be returned if that fails).
450 : : */
451 : 0 : int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
452 : : {
453 : : int ret = 0;
454 : :
455 : 0 : mutex_lock(&dev_pm_qos_mtx);
456 : :
457 [ # # ]: 0 : if (IS_ERR(dev->power.qos))
458 : : ret = -ENODEV;
459 [ # # ]: 0 : else if (!dev->power.qos)
460 : 0 : ret = dev_pm_qos_constraints_allocate(dev);
461 : :
462 [ # # ]: 0 : if (!ret)
463 : 0 : ret = blocking_notifier_chain_register(
464 : 0 : dev->power.qos->latency.notifiers, notifier);
465 : :
466 : 0 : mutex_unlock(&dev_pm_qos_mtx);
467 : 0 : return ret;
468 : : }
469 : : EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
470 : :
471 : : /**
472 : : * dev_pm_qos_remove_notifier - deletes notification for changes to target value
473 : : * of per-device PM QoS constraints
474 : : *
475 : : * @dev: target device for the constraint
476 : : * @notifier: notifier block to be removed.
477 : : *
478 : : * Will remove the notifier from the notification chain that gets called
479 : : * upon changes to the target value.
480 : : */
481 : 0 : int dev_pm_qos_remove_notifier(struct device *dev,
482 : : struct notifier_block *notifier)
483 : : {
484 : : int retval = 0;
485 : :
486 : 0 : mutex_lock(&dev_pm_qos_mtx);
487 : :
488 : : /* Silently return if the constraints object is not present. */
489 [ # # ]: 0 : if (!IS_ERR_OR_NULL(dev->power.qos))
490 : 0 : retval = blocking_notifier_chain_unregister(
491 : : dev->power.qos->latency.notifiers,
492 : : notifier);
493 : :
494 : 0 : mutex_unlock(&dev_pm_qos_mtx);
495 : 0 : return retval;
496 : : }
497 : : EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
498 : :
499 : : /**
500 : : * dev_pm_qos_add_global_notifier - sets notification entry for changes to
501 : : * target value of the PM QoS constraints for any device
502 : : *
503 : : * @notifier: notifier block managed by caller.
504 : : *
505 : : * Will register the notifier into a notification chain that gets called
506 : : * upon changes to the target value for any device.
507 : : */
508 : 0 : int dev_pm_qos_add_global_notifier(struct notifier_block *notifier)
509 : : {
510 : 0 : return blocking_notifier_chain_register(&dev_pm_notifiers, notifier);
511 : : }
512 : : EXPORT_SYMBOL_GPL(dev_pm_qos_add_global_notifier);
513 : :
514 : : /**
515 : : * dev_pm_qos_remove_global_notifier - deletes notification for changes to
516 : : * target value of PM QoS constraints for any device
517 : : *
518 : : * @notifier: notifier block to be removed.
519 : : *
520 : : * Will remove the notifier from the notification chain that gets called
521 : : * upon changes to the target value for any device.
522 : : */
523 : 0 : int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier)
524 : : {
525 : 0 : return blocking_notifier_chain_unregister(&dev_pm_notifiers, notifier);
526 : : }
527 : : EXPORT_SYMBOL_GPL(dev_pm_qos_remove_global_notifier);
528 : :
529 : : /**
530 : : * dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
531 : : * @dev: Device whose ancestor to add the request for.
532 : : * @req: Pointer to the preallocated handle.
533 : : * @value: Constraint latency value.
534 : : */
535 : 0 : int dev_pm_qos_add_ancestor_request(struct device *dev,
536 : : struct dev_pm_qos_request *req, s32 value)
537 : : {
538 : 0 : struct device *ancestor = dev->parent;
539 : : int ret = -ENODEV;
540 : :
541 [ # # ][ # # ]: 0 : while (ancestor && !ancestor->power.ignore_children)
542 : 0 : ancestor = ancestor->parent;
543 : :
544 [ # # ]: 0 : if (ancestor)
545 : 0 : ret = dev_pm_qos_add_request(ancestor, req,
546 : : DEV_PM_QOS_LATENCY, value);
547 : :
548 [ # # ]: 0 : if (ret < 0)
549 : 0 : req->dev = NULL;
550 : :
551 : 0 : return ret;
552 : : }
553 : : EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
554 : :
555 : : #ifdef CONFIG_PM_RUNTIME
556 : : static void __dev_pm_qos_drop_user_request(struct device *dev,
557 : : enum dev_pm_qos_req_type type)
558 : : {
559 : : struct dev_pm_qos_request *req = NULL;
560 : :
561 : : switch(type) {
562 : : case DEV_PM_QOS_LATENCY:
563 : : req = dev->power.qos->latency_req;
564 : : dev->power.qos->latency_req = NULL;
565 : : break;
566 : : case DEV_PM_QOS_FLAGS:
567 : : req = dev->power.qos->flags_req;
568 : : dev->power.qos->flags_req = NULL;
569 : : break;
570 : : }
571 : : __dev_pm_qos_remove_request(req);
572 : : kfree(req);
573 : : }
574 : :
575 : : static void dev_pm_qos_drop_user_request(struct device *dev,
576 : : enum dev_pm_qos_req_type type)
577 : : {
578 : : mutex_lock(&dev_pm_qos_mtx);
579 : : __dev_pm_qos_drop_user_request(dev, type);
580 : : mutex_unlock(&dev_pm_qos_mtx);
581 : : }
582 : :
583 : : /**
584 : : * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
585 : : * @dev: Device whose PM QoS latency limit is to be exposed to user space.
586 : : * @value: Initial value of the latency limit.
587 : : */
588 : : int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
589 : : {
590 : : struct dev_pm_qos_request *req;
591 : : int ret;
592 : :
593 : : if (!device_is_registered(dev) || value < 0)
594 : : return -EINVAL;
595 : :
596 : : req = kzalloc(sizeof(*req), GFP_KERNEL);
597 : : if (!req)
598 : : return -ENOMEM;
599 : :
600 : : ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value);
601 : : if (ret < 0) {
602 : : kfree(req);
603 : : return ret;
604 : : }
605 : :
606 : : mutex_lock(&dev_pm_qos_sysfs_mtx);
607 : :
608 : : mutex_lock(&dev_pm_qos_mtx);
609 : :
610 : : if (IS_ERR_OR_NULL(dev->power.qos))
611 : : ret = -ENODEV;
612 : : else if (dev->power.qos->latency_req)
613 : : ret = -EEXIST;
614 : :
615 : : if (ret < 0) {
616 : : __dev_pm_qos_remove_request(req);
617 : : kfree(req);
618 : : mutex_unlock(&dev_pm_qos_mtx);
619 : : goto out;
620 : : }
621 : : dev->power.qos->latency_req = req;
622 : :
623 : : mutex_unlock(&dev_pm_qos_mtx);
624 : :
625 : : ret = pm_qos_sysfs_add_latency(dev);
626 : : if (ret)
627 : : dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
628 : :
629 : : out:
630 : : mutex_unlock(&dev_pm_qos_sysfs_mtx);
631 : : return ret;
632 : : }
633 : : EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
634 : :
635 : : static void __dev_pm_qos_hide_latency_limit(struct device *dev)
636 : : {
637 : : if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)
638 : : __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
639 : : }
640 : :
641 : : /**
642 : : * dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
643 : : * @dev: Device whose PM QoS latency limit is to be hidden from user space.
644 : : */
645 : : void dev_pm_qos_hide_latency_limit(struct device *dev)
646 : : {
647 : : mutex_lock(&dev_pm_qos_sysfs_mtx);
648 : :
649 : : pm_qos_sysfs_remove_latency(dev);
650 : :
651 : : mutex_lock(&dev_pm_qos_mtx);
652 : : __dev_pm_qos_hide_latency_limit(dev);
653 : : mutex_unlock(&dev_pm_qos_mtx);
654 : :
655 : : mutex_unlock(&dev_pm_qos_sysfs_mtx);
656 : : }
657 : : EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
658 : :
659 : : /**
660 : : * dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space.
661 : : * @dev: Device whose PM QoS flags are to be exposed to user space.
662 : : * @val: Initial values of the flags.
663 : : */
664 : : int dev_pm_qos_expose_flags(struct device *dev, s32 val)
665 : : {
666 : : struct dev_pm_qos_request *req;
667 : : int ret;
668 : :
669 : : if (!device_is_registered(dev))
670 : : return -EINVAL;
671 : :
672 : : req = kzalloc(sizeof(*req), GFP_KERNEL);
673 : : if (!req)
674 : : return -ENOMEM;
675 : :
676 : : ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val);
677 : : if (ret < 0) {
678 : : kfree(req);
679 : : return ret;
680 : : }
681 : :
682 : : pm_runtime_get_sync(dev);
683 : : mutex_lock(&dev_pm_qos_sysfs_mtx);
684 : :
685 : : mutex_lock(&dev_pm_qos_mtx);
686 : :
687 : : if (IS_ERR_OR_NULL(dev->power.qos))
688 : : ret = -ENODEV;
689 : : else if (dev->power.qos->flags_req)
690 : : ret = -EEXIST;
691 : :
692 : : if (ret < 0) {
693 : : __dev_pm_qos_remove_request(req);
694 : : kfree(req);
695 : : mutex_unlock(&dev_pm_qos_mtx);
696 : : goto out;
697 : : }
698 : : dev->power.qos->flags_req = req;
699 : :
700 : : mutex_unlock(&dev_pm_qos_mtx);
701 : :
702 : : ret = pm_qos_sysfs_add_flags(dev);
703 : : if (ret)
704 : : dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
705 : :
706 : : out:
707 : : mutex_unlock(&dev_pm_qos_sysfs_mtx);
708 : : pm_runtime_put(dev);
709 : : return ret;
710 : : }
711 : : EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
712 : :
713 : : static void __dev_pm_qos_hide_flags(struct device *dev)
714 : : {
715 : : if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)
716 : : __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
717 : : }
718 : :
719 : : /**
720 : : * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space.
721 : : * @dev: Device whose PM QoS flags are to be hidden from user space.
722 : : */
723 : : void dev_pm_qos_hide_flags(struct device *dev)
724 : : {
725 : : pm_runtime_get_sync(dev);
726 : : mutex_lock(&dev_pm_qos_sysfs_mtx);
727 : :
728 : : pm_qos_sysfs_remove_flags(dev);
729 : :
730 : : mutex_lock(&dev_pm_qos_mtx);
731 : : __dev_pm_qos_hide_flags(dev);
732 : : mutex_unlock(&dev_pm_qos_mtx);
733 : :
734 : : mutex_unlock(&dev_pm_qos_sysfs_mtx);
735 : : pm_runtime_put(dev);
736 : : }
737 : : EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
738 : :
739 : : /**
740 : : * dev_pm_qos_update_flags - Update PM QoS flags request owned by user space.
741 : : * @dev: Device to update the PM QoS flags request for.
742 : : * @mask: Flags to set/clear.
743 : : * @set: Whether to set or clear the flags (true means set).
744 : : */
745 : : int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
746 : : {
747 : : s32 value;
748 : : int ret;
749 : :
750 : : pm_runtime_get_sync(dev);
751 : : mutex_lock(&dev_pm_qos_mtx);
752 : :
753 : : if (IS_ERR_OR_NULL(dev->power.qos) || !dev->power.qos->flags_req) {
754 : : ret = -EINVAL;
755 : : goto out;
756 : : }
757 : :
758 : : value = dev_pm_qos_requested_flags(dev);
759 : : if (set)
760 : : value |= mask;
761 : : else
762 : : value &= ~mask;
763 : :
764 : : ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value);
765 : :
766 : : out:
767 : : mutex_unlock(&dev_pm_qos_mtx);
768 : : pm_runtime_put(dev);
769 : : return ret;
770 : : }
771 : : #else /* !CONFIG_PM_RUNTIME */
772 : : static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
773 : : static void __dev_pm_qos_hide_flags(struct device *dev) {}
774 : : #endif /* CONFIG_PM_RUNTIME */
|