1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include <linux/pm_qos.h>
33#include <linux/sched.h>
34#include <linux/spinlock.h>
35#include <linux/slab.h>
36#include <linux/time.h>
37#include <linux/fs.h>
38#include <linux/device.h>
39#include <linux/miscdevice.h>
40#include <linux/string.h>
41#include <linux/platform_device.h>
42#include <linux/init.h>
43#include <linux/kernel.h>
44
45#include <linux/uaccess.h>
46#include <linux/export.h>
47#include <trace/events/power.h>
48
49
50
51
52
53
54struct pm_qos_object {
55 struct pm_qos_constraints *constraints;
56 struct miscdevice pm_qos_power_miscdev;
57 char *name;
58};
59
60static DEFINE_SPINLOCK(pm_qos_lock);
61
62static struct pm_qos_object null_pm_qos;
63
64static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
65static struct pm_qos_constraints cpu_dma_constraints = {
66 .list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
67 .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
68 .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
69 .type = PM_QOS_MIN,
70 .notifiers = &cpu_dma_lat_notifier,
71};
72static struct pm_qos_object cpu_dma_pm_qos = {
73 .constraints = &cpu_dma_constraints,
74 .name = "cpu_dma_latency",
75};
76
77static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
78static struct pm_qos_constraints network_lat_constraints = {
79 .list = PLIST_HEAD_INIT(network_lat_constraints.list),
80 .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
81 .default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
82 .type = PM_QOS_MIN,
83 .notifiers = &network_lat_notifier,
84};
85static struct pm_qos_object network_lat_pm_qos = {
86 .constraints = &network_lat_constraints,
87 .name = "network_latency",
88};
89
90
91static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
92static struct pm_qos_constraints network_tput_constraints = {
93 .list = PLIST_HEAD_INIT(network_tput_constraints.list),
94 .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
95 .default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE,
96 .type = PM_QOS_MAX,
97 .notifiers = &network_throughput_notifier,
98};
99static struct pm_qos_object network_throughput_pm_qos = {
100 .constraints = &network_tput_constraints,
101 .name = "network_throughput",
102};
103
104
105static struct pm_qos_object *pm_qos_array[] = {
106 &null_pm_qos,
107 &cpu_dma_pm_qos,
108 &network_lat_pm_qos,
109 &network_throughput_pm_qos
110};
111
112static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
113 size_t count, loff_t *f_pos);
114static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
115 size_t count, loff_t *f_pos);
116static int pm_qos_power_open(struct inode *inode, struct file *filp);
117static int pm_qos_power_release(struct inode *inode, struct file *filp);
118
119static const struct file_operations pm_qos_power_fops = {
120 .write = pm_qos_power_write,
121 .read = pm_qos_power_read,
122 .open = pm_qos_power_open,
123 .release = pm_qos_power_release,
124 .llseek = noop_llseek,
125};
126
127
128static inline int pm_qos_get_value(struct pm_qos_constraints *c)
129{
130 if (plist_head_empty(&c->list))
131 return c->default_value;
132
133 switch (c->type) {
134 case PM_QOS_MIN:
135 return plist_first(&c->list)->prio;
136
137 case PM_QOS_MAX:
138 return plist_last(&c->list)->prio;
139
140 default:
141
142 BUG();
143 return PM_QOS_DEFAULT_VALUE;
144 }
145}
146
147s32 pm_qos_read_value(struct pm_qos_constraints *c)
148{
149 return c->target_value;
150}
151
152static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
153{
154 c->target_value = value;
155}
156
157
158
159
160
161
162
163
164
165
166
167
168int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
169 enum pm_qos_req_action action, int value)
170{
171 unsigned long flags;
172 int prev_value, curr_value, new_value;
173
174 spin_lock_irqsave(&pm_qos_lock, flags);
175 prev_value = pm_qos_get_value(c);
176 if (value == PM_QOS_DEFAULT_VALUE)
177 new_value = c->default_value;
178 else
179 new_value = value;
180
181 switch (action) {
182 case PM_QOS_REMOVE_REQ:
183 plist_del(node, &c->list);
184 break;
185 case PM_QOS_UPDATE_REQ:
186
187
188
189
190
191 plist_del(node, &c->list);
192 case PM_QOS_ADD_REQ:
193 plist_node_init(node, new_value);
194 plist_add(node, &c->list);
195 break;
196 default:
197
198 ;
199 }
200
201 curr_value = pm_qos_get_value(c);
202 pm_qos_set_value(c, curr_value);
203
204 spin_unlock_irqrestore(&pm_qos_lock, flags);
205
206 trace_pm_qos_update_target(action, prev_value, curr_value);
207 if (prev_value != curr_value) {
208 blocking_notifier_call_chain(c->notifiers,
209 (unsigned long)curr_value,
210 NULL);
211 return 1;
212 } else {
213 return 0;
214 }
215}
216
217
218
219
220
221
222static void pm_qos_flags_remove_req(struct pm_qos_flags *pqf,
223 struct pm_qos_flags_request *req)
224{
225 s32 val = 0;
226
227 list_del(&req->node);
228 list_for_each_entry(req, &pqf->list, node)
229 val |= req->flags;
230
231 pqf->effective_flags = val;
232}
233
234
235
236
237
238
239
240
241
242
243
244
245bool pm_qos_update_flags(struct pm_qos_flags *pqf,
246 struct pm_qos_flags_request *req,
247 enum pm_qos_req_action action, s32 val)
248{
249 unsigned long irqflags;
250 s32 prev_value, curr_value;
251
252 spin_lock_irqsave(&pm_qos_lock, irqflags);
253
254 prev_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
255
256 switch (action) {
257 case PM_QOS_REMOVE_REQ:
258 pm_qos_flags_remove_req(pqf, req);
259 break;
260 case PM_QOS_UPDATE_REQ:
261 pm_qos_flags_remove_req(pqf, req);
262 case PM_QOS_ADD_REQ:
263 req->flags = val;
264 INIT_LIST_HEAD(&req->node);
265 list_add_tail(&req->node, &pqf->list);
266 pqf->effective_flags |= val;
267 break;
268 default:
269
270 ;
271 }
272
273 curr_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags;
274
275 spin_unlock_irqrestore(&pm_qos_lock, irqflags);
276
277 trace_pm_qos_update_flags(action, prev_value, curr_value);
278 return prev_value != curr_value;
279}
280
281
282
283
284
285
286
287int pm_qos_request(int pm_qos_class)
288{
289 return pm_qos_read_value(pm_qos_array[pm_qos_class]->constraints);
290}
291EXPORT_SYMBOL_GPL(pm_qos_request);
292
293int pm_qos_request_active(struct pm_qos_request *req)
294{
295 return req->pm_qos_class != 0;
296}
297EXPORT_SYMBOL_GPL(pm_qos_request_active);
298
299static void __pm_qos_update_request(struct pm_qos_request *req,
300 s32 new_value)
301{
302 trace_pm_qos_update_request(req->pm_qos_class, new_value);
303
304 if (new_value != req->node.prio)
305 pm_qos_update_target(
306 pm_qos_array[req->pm_qos_class]->constraints,
307 &req->node, PM_QOS_UPDATE_REQ, new_value);
308}
309
310
311
312
313
314
315
316static void pm_qos_work_fn(struct work_struct *work)
317{
318 struct pm_qos_request *req = container_of(to_delayed_work(work),
319 struct pm_qos_request,
320 work);
321
322 __pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
323}
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338void pm_qos_add_request(struct pm_qos_request *req,
339 int pm_qos_class, s32 value)
340{
341 if (!req)
342 return;
343
344 if (pm_qos_request_active(req)) {
345 WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
346 return;
347 }
348 req->pm_qos_class = pm_qos_class;
349 INIT_DELAYED_WORK(&req->work, pm_qos_work_fn);
350 trace_pm_qos_add_request(pm_qos_class, value);
351 pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
352 &req->node, PM_QOS_ADD_REQ, value);
353}
354EXPORT_SYMBOL_GPL(pm_qos_add_request);
355
356
357
358
359
360
361
362
363
364
365
366void pm_qos_update_request(struct pm_qos_request *req,
367 s32 new_value)
368{
369 if (!req)
370 return;
371
372 if (!pm_qos_request_active(req)) {
373 WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
374 return;
375 }
376
377 cancel_delayed_work_sync(&req->work);
378 __pm_qos_update_request(req, new_value);
379}
380EXPORT_SYMBOL_GPL(pm_qos_update_request);
381
382
383
384
385
386
387
388
389
390void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value,
391 unsigned long timeout_us)
392{
393 if (!req)
394 return;
395 if (WARN(!pm_qos_request_active(req),
396 "%s called for unknown object.", __func__))
397 return;
398
399 cancel_delayed_work_sync(&req->work);
400
401 trace_pm_qos_update_request_timeout(req->pm_qos_class,
402 new_value, timeout_us);
403 if (new_value != req->node.prio)
404 pm_qos_update_target(
405 pm_qos_array[req->pm_qos_class]->constraints,
406 &req->node, PM_QOS_UPDATE_REQ, new_value);
407
408 schedule_delayed_work(&req->work, usecs_to_jiffies(timeout_us));
409}
410
411
412
413
414
415
416
417
418
419void pm_qos_remove_request(struct pm_qos_request *req)
420{
421 if (!req)
422 return;
423
424
425 if (!pm_qos_request_active(req)) {
426 WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
427 return;
428 }
429
430 cancel_delayed_work_sync(&req->work);
431
432 trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE);
433 pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
434 &req->node, PM_QOS_REMOVE_REQ,
435 PM_QOS_DEFAULT_VALUE);
436 memset(req, 0, sizeof(*req));
437}
438EXPORT_SYMBOL_GPL(pm_qos_remove_request);
439
440
441
442
443
444
445
446
447
448int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
449{
450 int retval;
451
452 retval = blocking_notifier_chain_register(
453 pm_qos_array[pm_qos_class]->constraints->notifiers,
454 notifier);
455
456 return retval;
457}
458EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
459
460
461
462
463
464
465
466
467
468int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
469{
470 int retval;
471
472 retval = blocking_notifier_chain_unregister(
473 pm_qos_array[pm_qos_class]->constraints->notifiers,
474 notifier);
475
476 return retval;
477}
478EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
479
480
481static int register_pm_qos_misc(struct pm_qos_object *qos)
482{
483 qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
484 qos->pm_qos_power_miscdev.name = qos->name;
485 qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
486
487 return misc_register(&qos->pm_qos_power_miscdev);
488}
489
490static int find_pm_qos_object_by_minor(int minor)
491{
492 int pm_qos_class;
493
494 for (pm_qos_class = PM_QOS_CPU_DMA_LATENCY;
495 pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
496 if (minor ==
497 pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
498 return pm_qos_class;
499 }
500 return -1;
501}
502
503static int pm_qos_power_open(struct inode *inode, struct file *filp)
504{
505 long pm_qos_class;
506
507 pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
508 if (pm_qos_class >= PM_QOS_CPU_DMA_LATENCY) {
509 struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL);
510 if (!req)
511 return -ENOMEM;
512
513 pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
514 filp->private_data = req;
515
516 return 0;
517 }
518 return -EPERM;
519}
520
521static int pm_qos_power_release(struct inode *inode, struct file *filp)
522{
523 struct pm_qos_request *req;
524
525 req = filp->private_data;
526 pm_qos_remove_request(req);
527 kfree(req);
528
529 return 0;
530}
531
532
533static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
534 size_t count, loff_t *f_pos)
535{
536 s32 value;
537 unsigned long flags;
538 struct pm_qos_request *req = filp->private_data;
539
540 if (!req)
541 return -EINVAL;
542 if (!pm_qos_request_active(req))
543 return -EINVAL;
544
545 spin_lock_irqsave(&pm_qos_lock, flags);
546 value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints);
547 spin_unlock_irqrestore(&pm_qos_lock, flags);
548
549 return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
550}
551
552static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
553 size_t count, loff_t *f_pos)
554{
555 s32 value;
556 struct pm_qos_request *req;
557
558 if (count == sizeof(s32)) {
559 if (copy_from_user(&value, buf, sizeof(s32)))
560 return -EFAULT;
561 } else if (count <= 11) {
562 char ascii_value[11];
563 unsigned long int ulval;
564 int ret;
565
566 if (copy_from_user(ascii_value, buf, count))
567 return -EFAULT;
568
569 if (count > 10) {
570 if (ascii_value[10] == '\n')
571 ascii_value[10] = '\0';
572 else
573 return -EINVAL;
574 } else {
575 ascii_value[count] = '\0';
576 }
577 ret = kstrtoul(ascii_value, 16, &ulval);
578 if (ret) {
579 pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
580 return -EINVAL;
581 }
582 value = (s32)lower_32_bits(ulval);
583 } else {
584 return -EINVAL;
585 }
586
587 req = filp->private_data;
588 pm_qos_update_request(req, value);
589
590 return count;
591}
592
593
594static int __init pm_qos_power_init(void)
595{
596 int ret = 0;
597 int i;
598
599 BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES);
600
601 for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) {
602 ret = register_pm_qos_misc(pm_qos_array[i]);
603 if (ret < 0) {
604 printk(KERN_ERR "pm_qos_param: %s setup failed\n",
605 pm_qos_array[i]->name);
606 return ret;
607 }
608 }
609
610 return ret;
611}
612
613late_initcall(pm_qos_power_init);
614