Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * This module exposes the interface to kernel space for specifying
4 : : * QoS dependencies. It provides infrastructure for registration of:
5 : : *
6 : : * Dependents on a QoS value : register requests
7 : : * Watchers of QoS value : get notified when target QoS value changes
8 : : *
9 : : * This QoS design is best effort based. Dependents register their QoS needs.
10 : : * Watchers register to keep track of the current QoS needs of the system.
11 : : *
12 : : * There are 3 basic classes of QoS parameter: latency, timeout, throughput
13 : : * each have defined units:
14 : : * latency: usec
15 : : * timeout: usec <-- currently not used.
16 : : * throughput: kbs (kilo byte / sec)
17 : : *
18 : : * There are lists of pm_qos_objects each one wrapping requests, notifiers
19 : : *
20 : : * User mode requests on a QOS parameter register themselves to the
21 : : * subsystem by opening the device node /dev/... and writing there request to
22 : : * the node. As long as the process holds a file handle open to the node the
23 : : * client continues to be accounted for. Upon file release the usermode
24 : : * request is removed and a new qos target is computed. This way when the
25 : : * request that the application has is cleaned up when closes the file
26 : : * pointer or exits the pm_qos_object will get an opportunity to clean up.
27 : : *
28 : : * Mark Gross <mgross@linux.intel.com>
29 : : */
30 : :
31 : : /*#define DEBUG*/
32 : :
33 : : #include <linux/pm_qos.h>
34 : : #include <linux/sched.h>
35 : : #include <linux/spinlock.h>
36 : : #include <linux/slab.h>
37 : : #include <linux/time.h>
38 : : #include <linux/fs.h>
39 : : #include <linux/device.h>
40 : : #include <linux/miscdevice.h>
41 : : #include <linux/string.h>
42 : : #include <linux/platform_device.h>
43 : : #include <linux/init.h>
44 : : #include <linux/kernel.h>
45 : : #include <linux/debugfs.h>
46 : : #include <linux/seq_file.h>
47 : :
48 : : #include <linux/uaccess.h>
49 : : #include <linux/export.h>
50 : : #include <trace/events/power.h>
51 : :
52 : : /*
53 : : * locking rule: all changes to constraints or notifiers lists
54 : : * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
55 : : * held, taken with _irqsave. One lock to rule them all
56 : : */
57 : : struct pm_qos_object {
58 : : struct pm_qos_constraints *constraints;
59 : : struct miscdevice pm_qos_power_miscdev;
60 : : char *name;
61 : : };
62 : :
63 : : static DEFINE_SPINLOCK(pm_qos_lock);
64 : :
65 : : static struct pm_qos_object null_pm_qos;
66 : :
67 : : static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
68 : : static struct pm_qos_constraints cpu_dma_constraints = {
69 : : .list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
70 : : .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
71 : : .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
72 : : .no_constraint_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
73 : : .type = PM_QOS_MIN,
74 : : .notifiers = &cpu_dma_lat_notifier,
75 : : };
76 : : static struct pm_qos_object cpu_dma_pm_qos = {
77 : : .constraints = &cpu_dma_constraints,
78 : : .name = "cpu_dma_latency",
79 : : };
80 : :
81 : : static struct pm_qos_object *pm_qos_array[] = {
82 : : &null_pm_qos,
83 : : &cpu_dma_pm_qos,
84 : : };
85 : :
86 : : static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
87 : : size_t count, loff_t *f_pos);
88 : : static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
89 : : size_t count, loff_t *f_pos);
90 : : static int pm_qos_power_open(struct inode *inode, struct file *filp);
91 : : static int pm_qos_power_release(struct inode *inode, struct file *filp);
92 : :
93 : : static const struct file_operations pm_qos_power_fops = {
94 : : .write = pm_qos_power_write,
95 : : .read = pm_qos_power_read,
96 : : .open = pm_qos_power_open,
97 : : .release = pm_qos_power_release,
98 : : .llseek = noop_llseek,
99 : : };
100 : :
101 : : /* unlocked internal variant */
102 : 3232 : static inline int pm_qos_get_value(struct pm_qos_constraints *c)
103 : : {
104 : : struct plist_node *node;
105 : : int total_value = 0;
106 : :
107 [ + + ]: 3232 : if (plist_head_empty(&c->list))
108 : 1616 : return c->no_constraint_value;
109 : :
110 [ + - - - ]: 1616 : switch (c->type) {
111 : : case PM_QOS_MIN:
112 : 1616 : return plist_first(&c->list)->prio;
113 : :
114 : : case PM_QOS_MAX:
115 : 0 : return plist_last(&c->list)->prio;
116 : :
117 : : case PM_QOS_SUM:
118 [ # # ]: 0 : plist_for_each(node, &c->list)
119 : 0 : total_value += node->prio;
120 : :
121 : 0 : return total_value;
122 : :
123 : : default:
124 : : /* runtime check for not using enum */
125 : 0 : BUG();
126 : : return PM_QOS_DEFAULT_VALUE;
127 : : }
128 : : }
129 : :
130 : 10908 : s32 pm_qos_read_value(struct pm_qos_constraints *c)
131 : : {
132 : 10908 : return c->target_value;
133 : : }
134 : :
135 : : static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
136 : : {
137 : 1616 : c->target_value = value;
138 : : }
139 : :
140 : 0 : static int pm_qos_debug_show(struct seq_file *s, void *unused)
141 : : {
142 : 0 : struct pm_qos_object *qos = (struct pm_qos_object *)s->private;
143 : : struct pm_qos_constraints *c;
144 : : struct pm_qos_request *req;
145 : : char *type;
146 : : unsigned long flags;
147 : : int tot_reqs = 0;
148 : : int active_reqs = 0;
149 : :
150 [ # # ]: 0 : if (IS_ERR_OR_NULL(qos)) {
151 : 0 : pr_err("%s: bad qos param!\n", __func__);
152 : 0 : return -EINVAL;
153 : : }
154 : 0 : c = qos->constraints;
155 [ # # ]: 0 : if (IS_ERR_OR_NULL(c)) {
156 : 0 : pr_err("%s: Bad constraints on qos?\n", __func__);
157 : 0 : return -EINVAL;
158 : : }
159 : :
160 : : /* Lock to ensure we have a snapshot */
161 : 0 : spin_lock_irqsave(&pm_qos_lock, flags);
162 [ # # ]: 0 : if (plist_head_empty(&c->list)) {
163 : 0 : seq_puts(s, "Empty!\n");
164 : 0 : goto out;
165 : : }
166 : :
167 [ # # ]: 0 : switch (c->type) {
168 : : case PM_QOS_MIN:
169 : : type = "Minimum";
170 : : break;
171 : : case PM_QOS_MAX:
172 : : type = "Maximum";
173 : : break;
174 : : case PM_QOS_SUM:
175 : : type = "Sum";
176 : : break;
177 : : default:
178 : : type = "Unknown";
179 : : }
180 : :
181 [ # # ]: 0 : plist_for_each_entry(req, &c->list, node) {
182 : : char *state = "Default";
183 : :
184 [ # # ]: 0 : if ((req->node).prio != c->default_value) {
185 : 0 : active_reqs++;
186 : : state = "Active";
187 : : }
188 : 0 : tot_reqs++;
189 : 0 : seq_printf(s, "%d: %d: %s\n", tot_reqs,
190 : : (req->node).prio, state);
191 : : }
192 : :
193 : 0 : seq_printf(s, "Type=%s, Value=%d, Requests: active=%d / total=%d\n",
194 : : type, pm_qos_get_value(c), active_reqs, tot_reqs);
195 : :
196 : : out:
197 : : spin_unlock_irqrestore(&pm_qos_lock, flags);
198 : 0 : return 0;
199 : : }
200 : :
201 : 0 : DEFINE_SHOW_ATTRIBUTE(pm_qos_debug);
202 : :
203 : : /**
204 : : * pm_qos_update_target - manages the constraints list and calls the notifiers
205 : : * if needed
206 : : * @c: constraints data struct
207 : : * @node: request to add to the list, to update or to remove
208 : : * @action: action to take on the constraints list
209 : : * @value: value of the request to add or update
210 : : *
211 : : * This function returns 1 if the aggregated constraint value has changed, 0
212 : : * otherwise.
213 : : */
214 : 1616 : int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
215 : : enum pm_qos_req_action action, int value)
216 : : {
217 : : unsigned long flags;
218 : : int prev_value, curr_value, new_value;
219 : : int ret;
220 : :
221 : 1616 : spin_lock_irqsave(&pm_qos_lock, flags);
222 : 1616 : prev_value = pm_qos_get_value(c);
223 [ - + ]: 1616 : if (value == PM_QOS_DEFAULT_VALUE)
224 : 0 : new_value = c->default_value;
225 : : else
226 : : new_value = value;
227 : :
228 [ - - + - ]: 1616 : switch (action) {
229 : : case PM_QOS_REMOVE_REQ:
230 : 0 : plist_del(node, &c->list);
231 : 0 : break;
232 : : case PM_QOS_UPDATE_REQ:
233 : : /*
234 : : * to change the list, we atomically remove, reinit
235 : : * with new value and add, then see if the extremal
236 : : * changed
237 : : */
238 : 0 : plist_del(node, &c->list);
239 : : /* fall through */
240 : : case PM_QOS_ADD_REQ:
241 : : plist_node_init(node, new_value);
242 : 1616 : plist_add(node, &c->list);
243 : 1616 : break;
244 : : default:
245 : : /* no action */
246 : : ;
247 : : }
248 : :
249 : 1616 : curr_value = pm_qos_get_value(c);
250 : : pm_qos_set_value(c, curr_value);
251 : :
252 : : spin_unlock_irqrestore(&pm_qos_lock, flags);
253 : :
254 : 1616 : trace_pm_qos_update_target(action, prev_value, curr_value);
255 [ - + ]: 1616 : if (prev_value != curr_value) {
256 : : ret = 1;
257 [ # # ]: 0 : if (c->notifiers)
258 : 0 : blocking_notifier_call_chain(c->notifiers,
259 : : (unsigned long)curr_value,
260 : : NULL);
261 : : } else {
262 : : ret = 0;
263 : : }
264 : 1616 : return ret;
265 : : }
266 : :
267 : : /**
268 : : * pm_qos_flags_remove_req - Remove device PM QoS flags request.
269 : : * @pqf: Device PM QoS flags set to remove the request from.
270 : : * @req: Request to remove from the set.
271 : : */
272 : : static void pm_qos_flags_remove_req(struct pm_qos_flags *pqf,
273 : : struct pm_qos_flags_request *req)
274 : : {
275 : : s32 val = 0;
276 : :
277 : : list_del(&req->node);
278 [ + + # # ]: 808 : list_for_each_entry(req, &pqf->list, node)
279 : 404 : val |= req->flags;
280 : :
281 : 404 : pqf->effective_flags = val;
282 : : }
283 : :
284 : : /**
285 : : * pm_qos_update_flags - Update a set of PM QoS flags.
286 : : * @pqf: Set of flags to update.
287 : : * @req: Request to add to the set, to modify, or to remove from the set.
288 : : * @action: Action to take on the set.
289 : : * @val: Value of the request to add or modify.
290 : : *
291 : : * Update the given set of PM QoS flags and call notifiers if the aggregate
292 : : * value has changed. Returns 1 if the aggregate constraint value has changed,
293 : : * 0 otherwise.
294 : : */
295 : 4444 : bool pm_qos_update_flags(struct pm_qos_flags *pqf,
296 : : struct pm_qos_flags_request *req,
297 : : enum pm_qos_req_action action, s32 val)
298 : : {
299 : : unsigned long irqflags;
300 : : s32 prev_value, curr_value;
301 : :
302 : 4444 : spin_lock_irqsave(&pm_qos_lock, irqflags);
303 : :
304 [ + + ]: 8888 : prev_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
305 : :
306 [ + - + - ]: 4444 : switch (action) {
307 : : case PM_QOS_REMOVE_REQ:
308 : : pm_qos_flags_remove_req(pqf, req);
309 : : break;
310 : : case PM_QOS_UPDATE_REQ:
311 : : pm_qos_flags_remove_req(pqf, req);
312 : : /* fall through */
313 : : case PM_QOS_ADD_REQ:
314 : 4040 : req->flags = val;
315 : 4040 : INIT_LIST_HEAD(&req->node);
316 : : list_add_tail(&req->node, &pqf->list);
317 : 4040 : pqf->effective_flags |= val;
318 : 4040 : break;
319 : : default:
320 : : /* no action */
321 : : ;
322 : : }
323 : :
324 [ + - ]: 4444 : curr_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
325 : :
326 : : spin_unlock_irqrestore(&pm_qos_lock, irqflags);
327 : :
328 : 4444 : trace_pm_qos_update_flags(action, prev_value, curr_value);
329 : 4444 : return prev_value != curr_value;
330 : : }
331 : :
332 : : /**
333 : : * pm_qos_request - returns current system wide qos expectation
334 : : * @pm_qos_class: identification of which qos value is requested
335 : : *
336 : : * This function returns the current target value.
337 : : */
338 : 0 : int pm_qos_request(int pm_qos_class)
339 : : {
340 : 0 : return pm_qos_read_value(pm_qos_array[pm_qos_class]->constraints);
341 : : }
342 : : EXPORT_SYMBOL_GPL(pm_qos_request);
343 : :
344 : 0 : int pm_qos_request_active(struct pm_qos_request *req)
345 : : {
346 : 0 : return req->pm_qos_class != 0;
347 : : }
348 : : EXPORT_SYMBOL_GPL(pm_qos_request_active);
349 : :
350 : 0 : static void __pm_qos_update_request(struct pm_qos_request *req,
351 : : s32 new_value)
352 : : {
353 : 0 : trace_pm_qos_update_request(req->pm_qos_class, new_value);
354 : :
355 [ # # ]: 0 : if (new_value != req->node.prio)
356 : 0 : pm_qos_update_target(
357 : 0 : pm_qos_array[req->pm_qos_class]->constraints,
358 : : &req->node, PM_QOS_UPDATE_REQ, new_value);
359 : 0 : }
360 : :
361 : : /**
362 : : * pm_qos_work_fn - the timeout handler of pm_qos_update_request_timeout
363 : : * @work: work struct for the delayed work (timeout)
364 : : *
365 : : * This cancels the timeout request by falling back to the default at timeout.
366 : : */
367 : 0 : static void pm_qos_work_fn(struct work_struct *work)
368 : : {
369 : 0 : struct pm_qos_request *req = container_of(to_delayed_work(work),
370 : : struct pm_qos_request,
371 : : work);
372 : :
373 : 0 : __pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
374 : 0 : }
375 : :
376 : : /**
377 : : * pm_qos_add_request - inserts new qos request into the list
378 : : * @req: pointer to a preallocated handle
379 : : * @pm_qos_class: identifies which list of qos request to use
380 : : * @value: defines the qos request
381 : : *
382 : : * This function inserts a new entry in the pm_qos_class list of requested qos
383 : : * performance characteristics. It recomputes the aggregate QoS expectations
384 : : * for the pm_qos_class of parameters and initializes the pm_qos_request
385 : : * handle. Caller needs to save this handle for later use in updates and
386 : : * removal.
387 : : */
388 : :
389 : 0 : void pm_qos_add_request(struct pm_qos_request *req,
390 : : int pm_qos_class, s32 value)
391 : : {
392 [ # # ]: 0 : if (!req) /*guard against callers passing in null */
393 : : return;
394 : :
395 [ # # ]: 0 : if (pm_qos_request_active(req)) {
396 : 0 : WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
397 : 0 : return;
398 : : }
399 : 0 : req->pm_qos_class = pm_qos_class;
400 : 0 : INIT_DELAYED_WORK(&req->work, pm_qos_work_fn);
401 : 0 : trace_pm_qos_add_request(pm_qos_class, value);
402 : 0 : pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
403 : : &req->node, PM_QOS_ADD_REQ, value);
404 : : }
405 : : EXPORT_SYMBOL_GPL(pm_qos_add_request);
406 : :
407 : : /**
408 : : * pm_qos_update_request - modifies an existing qos request
409 : : * @req : handle to list element holding a pm_qos request to use
410 : : * @value: defines the qos request
411 : : *
412 : : * Updates an existing qos request for the pm_qos_class of parameters along
413 : : * with updating the target pm_qos_class value.
414 : : *
415 : : * Attempts are made to make this code callable on hot code paths.
416 : : */
417 : 0 : void pm_qos_update_request(struct pm_qos_request *req,
418 : : s32 new_value)
419 : : {
420 [ # # ]: 0 : if (!req) /*guard against callers passing in null */
421 : : return;
422 : :
423 [ # # ]: 0 : if (!pm_qos_request_active(req)) {
424 : 0 : WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
425 : 0 : return;
426 : : }
427 : :
428 : 0 : cancel_delayed_work_sync(&req->work);
429 : 0 : __pm_qos_update_request(req, new_value);
430 : : }
431 : : EXPORT_SYMBOL_GPL(pm_qos_update_request);
432 : :
433 : : /**
434 : : * pm_qos_update_request_timeout - modifies an existing qos request temporarily.
435 : : * @req : handle to list element holding a pm_qos request to use
436 : : * @new_value: defines the temporal qos request
437 : : * @timeout_us: the effective duration of this qos request in usecs.
438 : : *
439 : : * After timeout_us, this qos request is cancelled automatically.
440 : : */
441 : 0 : void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value,
442 : : unsigned long timeout_us)
443 : : {
444 [ # # ]: 0 : if (!req)
445 : : return;
446 [ # # # # ]: 0 : if (WARN(!pm_qos_request_active(req),
447 : : "%s called for unknown object.", __func__))
448 : : return;
449 : :
450 : 0 : cancel_delayed_work_sync(&req->work);
451 : :
452 : 0 : trace_pm_qos_update_request_timeout(req->pm_qos_class,
453 : : new_value, timeout_us);
454 [ # # ]: 0 : if (new_value != req->node.prio)
455 : 0 : pm_qos_update_target(
456 : 0 : pm_qos_array[req->pm_qos_class]->constraints,
457 : : &req->node, PM_QOS_UPDATE_REQ, new_value);
458 : :
459 : : schedule_delayed_work(&req->work, usecs_to_jiffies(timeout_us));
460 : : }
461 : :
462 : : /**
463 : : * pm_qos_remove_request - modifies an existing qos request
464 : : * @req: handle to request list element
465 : : *
466 : : * Will remove pm qos request from the list of constraints and
467 : : * recompute the current target value for the pm_qos_class. Call this
468 : : * on slow code paths.
469 : : */
470 : 0 : void pm_qos_remove_request(struct pm_qos_request *req)
471 : : {
472 [ # # ]: 0 : if (!req) /*guard against callers passing in null */
473 : : return;
474 : : /* silent return to keep pcm code cleaner */
475 : :
476 [ # # ]: 0 : if (!pm_qos_request_active(req)) {
477 : 0 : WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
478 : 0 : return;
479 : : }
480 : :
481 : 0 : cancel_delayed_work_sync(&req->work);
482 : :
483 : 0 : trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE);
484 : 0 : pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
485 : : &req->node, PM_QOS_REMOVE_REQ,
486 : : PM_QOS_DEFAULT_VALUE);
487 : 0 : memset(req, 0, sizeof(*req));
488 : : }
489 : : EXPORT_SYMBOL_GPL(pm_qos_remove_request);
490 : :
491 : : /**
492 : : * pm_qos_add_notifier - sets notification entry for changes to target value
493 : : * @pm_qos_class: identifies which qos target changes should be notified.
494 : : * @notifier: notifier block managed by caller.
495 : : *
496 : : * will register the notifier into a notification chain that gets called
497 : : * upon changes to the pm_qos_class target value.
498 : : */
499 : 0 : int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
500 : : {
501 : : int retval;
502 : :
503 : 0 : retval = blocking_notifier_chain_register(
504 : 0 : pm_qos_array[pm_qos_class]->constraints->notifiers,
505 : : notifier);
506 : :
507 : 0 : return retval;
508 : : }
509 : : EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
510 : :
511 : : /**
512 : : * pm_qos_remove_notifier - deletes notification entry from chain.
513 : : * @pm_qos_class: identifies which qos target changes are notified.
514 : : * @notifier: notifier block to be removed.
515 : : *
516 : : * will remove the notifier from the notification chain that gets called
517 : : * upon changes to the pm_qos_class target value.
518 : : */
519 : 0 : int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
520 : : {
521 : : int retval;
522 : :
523 : 0 : retval = blocking_notifier_chain_unregister(
524 : 0 : pm_qos_array[pm_qos_class]->constraints->notifiers,
525 : : notifier);
526 : :
527 : 0 : return retval;
528 : : }
529 : : EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
530 : :
531 : : /* User space interface to PM QoS classes via misc devices */
532 : 404 : static int register_pm_qos_misc(struct pm_qos_object *qos, struct dentry *d)
533 : : {
534 : 404 : qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
535 : 404 : qos->pm_qos_power_miscdev.name = qos->name;
536 : 404 : qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
537 : :
538 : 404 : debugfs_create_file(qos->name, S_IRUGO, d, (void *)qos,
539 : : &pm_qos_debug_fops);
540 : :
541 : 404 : return misc_register(&qos->pm_qos_power_miscdev);
542 : : }
543 : :
544 : : static int find_pm_qos_object_by_minor(int minor)
545 : : {
546 : : int pm_qos_class;
547 : :
548 [ # # ]: 0 : for (pm_qos_class = PM_QOS_CPU_DMA_LATENCY;
549 : 0 : pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
550 [ # # ]: 0 : if (minor ==
551 : 0 : pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
552 : 0 : return pm_qos_class;
553 : : }
554 : : return -1;
555 : : }
556 : :
557 : 0 : static int pm_qos_power_open(struct inode *inode, struct file *filp)
558 : : {
559 : : long pm_qos_class;
560 : :
561 : 0 : pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
562 [ # # ]: 0 : if (pm_qos_class >= PM_QOS_CPU_DMA_LATENCY) {
563 : 0 : struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL);
564 [ # # ]: 0 : if (!req)
565 : : return -ENOMEM;
566 : :
567 : 0 : pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
568 : 0 : filp->private_data = req;
569 : :
570 : 0 : return 0;
571 : : }
572 : : return -EPERM;
573 : : }
574 : :
575 : 0 : static int pm_qos_power_release(struct inode *inode, struct file *filp)
576 : : {
577 : : struct pm_qos_request *req;
578 : :
579 : 0 : req = filp->private_data;
580 : 0 : pm_qos_remove_request(req);
581 : 0 : kfree(req);
582 : :
583 : 0 : return 0;
584 : : }
585 : :
586 : :
587 : 0 : static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
588 : : size_t count, loff_t *f_pos)
589 : : {
590 : : s32 value;
591 : : unsigned long flags;
592 : 0 : struct pm_qos_request *req = filp->private_data;
593 : :
594 [ # # ]: 0 : if (!req)
595 : : return -EINVAL;
596 [ # # ]: 0 : if (!pm_qos_request_active(req))
597 : : return -EINVAL;
598 : :
599 : 0 : spin_lock_irqsave(&pm_qos_lock, flags);
600 : 0 : value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints);
601 : : spin_unlock_irqrestore(&pm_qos_lock, flags);
602 : :
603 : 0 : return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
604 : : }
605 : :
606 : 0 : static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
607 : : size_t count, loff_t *f_pos)
608 : : {
609 : : s32 value;
610 : : struct pm_qos_request *req;
611 : :
612 [ # # ]: 0 : if (count == sizeof(s32)) {
613 [ # # ]: 0 : if (copy_from_user(&value, buf, sizeof(s32)))
614 : : return -EFAULT;
615 : : } else {
616 : : int ret;
617 : :
618 : : ret = kstrtos32_from_user(buf, count, 16, &value);
619 [ # # ]: 0 : if (ret)
620 : : return ret;
621 : : }
622 : :
623 : 0 : req = filp->private_data;
624 : 0 : pm_qos_update_request(req, value);
625 : :
626 : 0 : return count;
627 : : }
628 : :
629 : :
630 : 404 : static int __init pm_qos_power_init(void)
631 : : {
632 : : int ret = 0;
633 : : int i;
634 : : struct dentry *d;
635 : :
636 : : BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES);
637 : :
638 : 404 : d = debugfs_create_dir("pm_qos", NULL);
639 : :
640 [ + + ]: 808 : for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) {
641 : 404 : ret = register_pm_qos_misc(pm_qos_array[i], d);
642 [ - + ]: 404 : if (ret < 0) {
643 : 0 : pr_err("%s: %s setup failed\n",
644 : : __func__, pm_qos_array[i]->name);
645 : 0 : return ret;
646 : : }
647 : : }
648 : :
649 : 404 : return ret;
650 : : }
651 : :
652 : : late_initcall(pm_qos_power_init);
653 : :
654 : : /* Definitions related to the frequency QoS below. */
655 : :
656 : : /**
657 : : * freq_constraints_init - Initialize frequency QoS constraints.
658 : : * @qos: Frequency QoS constraints to initialize.
659 : : */
660 : 0 : void freq_constraints_init(struct freq_constraints *qos)
661 : : {
662 : : struct pm_qos_constraints *c;
663 : :
664 : : c = &qos->min_freq;
665 : : plist_head_init(&c->list);
666 : 0 : c->target_value = FREQ_QOS_MIN_DEFAULT_VALUE;
667 : 0 : c->default_value = FREQ_QOS_MIN_DEFAULT_VALUE;
668 : 0 : c->no_constraint_value = FREQ_QOS_MIN_DEFAULT_VALUE;
669 : 0 : c->type = PM_QOS_MAX;
670 : 0 : c->notifiers = &qos->min_freq_notifiers;
671 : 0 : BLOCKING_INIT_NOTIFIER_HEAD(c->notifiers);
672 : :
673 : : c = &qos->max_freq;
674 : : plist_head_init(&c->list);
675 : 0 : c->target_value = FREQ_QOS_MAX_DEFAULT_VALUE;
676 : 0 : c->default_value = FREQ_QOS_MAX_DEFAULT_VALUE;
677 : 0 : c->no_constraint_value = FREQ_QOS_MAX_DEFAULT_VALUE;
678 : 0 : c->type = PM_QOS_MIN;
679 : 0 : c->notifiers = &qos->max_freq_notifiers;
680 : 0 : BLOCKING_INIT_NOTIFIER_HEAD(c->notifiers);
681 : 0 : }
682 : :
683 : : /**
684 : : * freq_qos_read_value - Get frequency QoS constraint for a given list.
685 : : * @qos: Constraints to evaluate.
686 : : * @type: QoS request type.
687 : : */
688 : 0 : s32 freq_qos_read_value(struct freq_constraints *qos,
689 : : enum freq_qos_req_type type)
690 : : {
691 : : s32 ret;
692 : :
693 [ # # # ]: 0 : switch (type) {
694 : : case FREQ_QOS_MIN:
695 : : ret = IS_ERR_OR_NULL(qos) ?
696 [ # # ]: 0 : FREQ_QOS_MIN_DEFAULT_VALUE :
697 : : pm_qos_read_value(&qos->min_freq);
698 : 0 : break;
699 : : case FREQ_QOS_MAX:
700 : : ret = IS_ERR_OR_NULL(qos) ?
701 [ # # ]: 0 : FREQ_QOS_MAX_DEFAULT_VALUE :
702 : : pm_qos_read_value(&qos->max_freq);
703 : 0 : break;
704 : : default:
705 : 0 : WARN_ON(1);
706 : : ret = 0;
707 : : }
708 : :
709 : 0 : return ret;
710 : : }
711 : :
712 : : /**
713 : : * freq_qos_apply - Add/modify/remove frequency QoS request.
714 : : * @req: Constraint request to apply.
715 : : * @action: Action to perform (add/update/remove).
716 : : * @value: Value to assign to the QoS request.
717 : : */
718 : 0 : static int freq_qos_apply(struct freq_qos_request *req,
719 : : enum pm_qos_req_action action, s32 value)
720 : : {
721 : : int ret;
722 : :
723 [ # # # ]: 0 : switch(req->type) {
724 : : case FREQ_QOS_MIN:
725 : 0 : ret = pm_qos_update_target(&req->qos->min_freq, &req->pnode,
726 : : action, value);
727 : 0 : break;
728 : : case FREQ_QOS_MAX:
729 : 0 : ret = pm_qos_update_target(&req->qos->max_freq, &req->pnode,
730 : : action, value);
731 : 0 : break;
732 : : default:
733 : : ret = -EINVAL;
734 : : }
735 : :
736 : 0 : return ret;
737 : : }
738 : :
739 : : /**
740 : : * freq_qos_add_request - Insert new frequency QoS request into a given list.
741 : : * @qos: Constraints to update.
742 : : * @req: Preallocated request object.
743 : : * @type: Request type.
744 : : * @value: Request value.
745 : : *
746 : : * Insert a new entry into the @qos list of requests, recompute the effective
747 : : * QoS constraint value for that list and initialize the @req object. The
748 : : * caller needs to save that object for later use in updates and removal.
749 : : *
750 : : * Return 1 if the effective constraint value has changed, 0 if the effective
751 : : * constraint value has not changed, or a negative error code on failures.
752 : : */
753 : 0 : int freq_qos_add_request(struct freq_constraints *qos,
754 : : struct freq_qos_request *req,
755 : : enum freq_qos_req_type type, s32 value)
756 : : {
757 : : int ret;
758 : :
759 [ # # # # ]: 0 : if (IS_ERR_OR_NULL(qos) || !req)
760 : : return -EINVAL;
761 : :
762 [ # # # # ]: 0 : if (WARN(freq_qos_request_active(req),
763 : : "%s() called for active request\n", __func__))
764 : : return -EINVAL;
765 : :
766 : 0 : req->qos = qos;
767 : 0 : req->type = type;
768 : 0 : ret = freq_qos_apply(req, PM_QOS_ADD_REQ, value);
769 [ # # ]: 0 : if (ret < 0) {
770 : 0 : req->qos = NULL;
771 : 0 : req->type = 0;
772 : : }
773 : :
774 : 0 : return ret;
775 : : }
776 : : EXPORT_SYMBOL_GPL(freq_qos_add_request);
777 : :
778 : : /**
779 : : * freq_qos_update_request - Modify existing frequency QoS request.
780 : : * @req: Request to modify.
781 : : * @new_value: New request value.
782 : : *
783 : : * Update an existing frequency QoS request along with the effective constraint
784 : : * value for the list of requests it belongs to.
785 : : *
786 : : * Return 1 if the effective constraint value has changed, 0 if the effective
787 : : * constraint value has not changed, or a negative error code on failures.
788 : : */
789 : 0 : int freq_qos_update_request(struct freq_qos_request *req, s32 new_value)
790 : : {
791 [ # # ]: 0 : if (!req)
792 : : return -EINVAL;
793 : :
794 [ # # # # ]: 0 : if (WARN(!freq_qos_request_active(req),
795 : : "%s() called for unknown object\n", __func__))
796 : : return -EINVAL;
797 : :
798 [ # # ]: 0 : if (req->pnode.prio == new_value)
799 : : return 0;
800 : :
801 : 0 : return freq_qos_apply(req, PM_QOS_UPDATE_REQ, new_value);
802 : : }
803 : : EXPORT_SYMBOL_GPL(freq_qos_update_request);
804 : :
805 : : /**
806 : : * freq_qos_remove_request - Remove frequency QoS request from its list.
807 : : * @req: Request to remove.
808 : : *
809 : : * Remove the given frequency QoS request from the list of constraints it
810 : : * belongs to and recompute the effective constraint value for that list.
811 : : *
812 : : * Return 1 if the effective constraint value has changed, 0 if the effective
813 : : * constraint value has not changed, or a negative error code on failures.
814 : : */
815 : 0 : int freq_qos_remove_request(struct freq_qos_request *req)
816 : : {
817 : : int ret;
818 : :
819 [ # # ]: 0 : if (!req)
820 : : return -EINVAL;
821 : :
822 [ # # # # ]: 0 : if (WARN(!freq_qos_request_active(req),
823 : : "%s() called for unknown object\n", __func__))
824 : : return -EINVAL;
825 : :
826 : 0 : ret = freq_qos_apply(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
827 : 0 : req->qos = NULL;
828 : 0 : req->type = 0;
829 : :
830 : 0 : return ret;
831 : : }
832 : : EXPORT_SYMBOL_GPL(freq_qos_remove_request);
833 : :
834 : : /**
835 : : * freq_qos_add_notifier - Add frequency QoS change notifier.
836 : : * @qos: List of requests to add the notifier to.
837 : : * @type: Request type.
838 : : * @notifier: Notifier block to add.
839 : : */
840 : 0 : int freq_qos_add_notifier(struct freq_constraints *qos,
841 : : enum freq_qos_req_type type,
842 : : struct notifier_block *notifier)
843 : : {
844 : : int ret;
845 : :
846 [ # # # # ]: 0 : if (IS_ERR_OR_NULL(qos) || !notifier)
847 : : return -EINVAL;
848 : :
849 [ # # # ]: 0 : switch (type) {
850 : : case FREQ_QOS_MIN:
851 : 0 : ret = blocking_notifier_chain_register(qos->min_freq.notifiers,
852 : : notifier);
853 : 0 : break;
854 : : case FREQ_QOS_MAX:
855 : 0 : ret = blocking_notifier_chain_register(qos->max_freq.notifiers,
856 : : notifier);
857 : 0 : break;
858 : : default:
859 : 0 : WARN_ON(1);
860 : : ret = -EINVAL;
861 : : }
862 : :
863 : 0 : return ret;
864 : : }
865 : : EXPORT_SYMBOL_GPL(freq_qos_add_notifier);
866 : :
867 : : /**
868 : : * freq_qos_remove_notifier - Remove frequency QoS change notifier.
869 : : * @qos: List of requests to remove the notifier from.
870 : : * @type: Request type.
871 : : * @notifier: Notifier block to remove.
872 : : */
873 : 0 : int freq_qos_remove_notifier(struct freq_constraints *qos,
874 : : enum freq_qos_req_type type,
875 : : struct notifier_block *notifier)
876 : : {
877 : : int ret;
878 : :
879 [ # # # # ]: 0 : if (IS_ERR_OR_NULL(qos) || !notifier)
880 : : return -EINVAL;
881 : :
882 [ # # # ]: 0 : switch (type) {
883 : : case FREQ_QOS_MIN:
884 : 0 : ret = blocking_notifier_chain_unregister(qos->min_freq.notifiers,
885 : : notifier);
886 : 0 : break;
887 : : case FREQ_QOS_MAX:
888 : 0 : ret = blocking_notifier_chain_unregister(qos->max_freq.notifiers,
889 : : notifier);
890 : 0 : break;
891 : : default:
892 : 0 : WARN_ON(1);
893 : : ret = -EINVAL;
894 : : }
895 : :
896 : 0 : return ret;
897 : : }
898 : : EXPORT_SYMBOL_GPL(freq_qos_remove_notifier);
|