Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
qos.c
Go to the documentation of this file.
1 /*
2  * This module exposes the interface to kernel space for specifying
3  * QoS dependencies. It provides infrastructure for registration of:
4  *
5  * Dependents on a QoS value : register requests
6  * Watchers of QoS value : get notified when target QoS value changes
7  *
8  * This QoS design is best effort based. Dependents register their QoS needs.
9  * Watchers register to keep track of the current QoS needs of the system.
10  *
11  * There are 3 basic classes of QoS parameter: latency, timeout, throughput
12  * each have defined units:
13  * latency: usec
14  * timeout: usec <-- currently not used.
15  * throughput: kbs (kilo byte / sec)
16  *
17  * There are lists of pm_qos_objects each one wrapping requests, notifiers
18  *
19  * User mode requests on a QOS parameter register themselves to the
20  * subsystem by opening the device node /dev/... and writing there request to
21  * the node. As long as the process holds a file handle open to the node the
22  * client continues to be accounted for. Upon file release the usermode
23  * request is removed and a new qos target is computed. This way when the
24  * request that the application has is cleaned up when closes the file
25  * pointer or exits the pm_qos_object will get an opportunity to clean up.
26  *
27  * Mark Gross <[email protected]>
28  */
29 
30 /*#define DEBUG*/
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 
48 /*
49  * locking rule: all changes to constraints or notifiers lists
50  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
51  * held, taken with _irqsave. One lock to rule them all
52  */
53 struct pm_qos_object {
56  char *name;
57 };
58 
59 static DEFINE_SPINLOCK(pm_qos_lock);
60 
61 static struct pm_qos_object null_pm_qos;
62 
63 static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
64 static struct pm_qos_constraints cpu_dma_constraints = {
65  .list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
66  .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
67  .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
68  .type = PM_QOS_MIN,
69  .notifiers = &cpu_dma_lat_notifier,
70 };
71 static struct pm_qos_object cpu_dma_pm_qos = {
72  .constraints = &cpu_dma_constraints,
73  .name = "cpu_dma_latency",
74 };
75 
76 static BLOCKING_NOTIFIER_HEAD(network_lat_notifier);
77 static struct pm_qos_constraints network_lat_constraints = {
78  .list = PLIST_HEAD_INIT(network_lat_constraints.list),
79  .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
80  .default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE,
81  .type = PM_QOS_MIN,
82  .notifiers = &network_lat_notifier,
83 };
84 static struct pm_qos_object network_lat_pm_qos = {
85  .constraints = &network_lat_constraints,
86  .name = "network_latency",
87 };
88 
89 
90 static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier);
91 static struct pm_qos_constraints network_tput_constraints = {
92  .list = PLIST_HEAD_INIT(network_tput_constraints.list),
95  .type = PM_QOS_MAX,
96  .notifiers = &network_throughput_notifier,
97 };
98 static struct pm_qos_object network_throughput_pm_qos = {
99  .constraints = &network_tput_constraints,
100  .name = "network_throughput",
101 };
102 
103 
104 static struct pm_qos_object *pm_qos_array[] = {
105  &null_pm_qos,
106  &cpu_dma_pm_qos,
107  &network_lat_pm_qos,
108  &network_throughput_pm_qos
109 };
110 
111 static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
112  size_t count, loff_t *f_pos);
113 static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
114  size_t count, loff_t *f_pos);
115 static int pm_qos_power_open(struct inode *inode, struct file *filp);
116 static int pm_qos_power_release(struct inode *inode, struct file *filp);
117 
118 static const struct file_operations pm_qos_power_fops = {
119  .write = pm_qos_power_write,
120  .read = pm_qos_power_read,
121  .open = pm_qos_power_open,
122  .release = pm_qos_power_release,
123  .llseek = noop_llseek,
124 };
125 
126 /* unlocked internal variant */
127 static inline int pm_qos_get_value(struct pm_qos_constraints *c)
128 {
129  if (plist_head_empty(&c->list))
130  return c->default_value;
131 
132  switch (c->type) {
133  case PM_QOS_MIN:
134  return plist_first(&c->list)->prio;
135 
136  case PM_QOS_MAX:
137  return plist_last(&c->list)->prio;
138 
139  default:
140  /* runtime check for not using enum */
141  BUG();
142  return PM_QOS_DEFAULT_VALUE;
143  }
144 }
145 
147 {
148  return c->target_value;
149 }
150 
151 static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
152 {
153  c->target_value = value;
154 }
155 
168  enum pm_qos_req_action action, int value)
169 {
170  unsigned long flags;
171  int prev_value, curr_value, new_value;
172 
173  spin_lock_irqsave(&pm_qos_lock, flags);
174  prev_value = pm_qos_get_value(c);
175  if (value == PM_QOS_DEFAULT_VALUE)
176  new_value = c->default_value;
177  else
178  new_value = value;
179 
180  switch (action) {
181  case PM_QOS_REMOVE_REQ:
182  plist_del(node, &c->list);
183  break;
184  case PM_QOS_UPDATE_REQ:
185  /*
186  * to change the list, we atomically remove, reinit
187  * with new value and add, then see if the extremal
188  * changed
189  */
190  plist_del(node, &c->list);
191  case PM_QOS_ADD_REQ:
192  plist_node_init(node, new_value);
193  plist_add(node, &c->list);
194  break;
195  default:
196  /* no action */
197  ;
198  }
199 
200  curr_value = pm_qos_get_value(c);
201  pm_qos_set_value(c, curr_value);
202 
203  spin_unlock_irqrestore(&pm_qos_lock, flags);
204 
205  if (prev_value != curr_value) {
207  (unsigned long)curr_value,
208  NULL);
209  return 1;
210  } else {
211  return 0;
212  }
213 }
214 
221 int pm_qos_request(int pm_qos_class)
222 {
223  return pm_qos_read_value(pm_qos_array[pm_qos_class]->constraints);
224 }
226 
228 {
229  return req->pm_qos_class != 0;
230 }
232 
239 static void pm_qos_work_fn(struct work_struct *work)
240 {
241  struct pm_qos_request *req = container_of(to_delayed_work(work),
242  struct pm_qos_request,
243  work);
244 
246 }
247 
262  int pm_qos_class, s32 value)
263 {
264  if (!req) /*guard against callers passing in null */
265  return;
266 
267  if (pm_qos_request_active(req)) {
268  WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
269  return;
270  }
271  req->pm_qos_class = pm_qos_class;
272  INIT_DELAYED_WORK(&req->work, pm_qos_work_fn);
273  pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
274  &req->node, PM_QOS_ADD_REQ, value);
275 }
277 
289  s32 new_value)
290 {
291  if (!req) /*guard against callers passing in null */
292  return;
293 
294  if (!pm_qos_request_active(req)) {
295  WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
296  return;
297  }
298 
299  if (delayed_work_pending(&req->work))
301 
302  if (new_value != req->node.prio)
304  pm_qos_array[req->pm_qos_class]->constraints,
305  &req->node, PM_QOS_UPDATE_REQ, new_value);
306 }
308 
318  unsigned long timeout_us)
319 {
320  if (!req)
321  return;
322  if (WARN(!pm_qos_request_active(req),
323  "%s called for unknown object.", __func__))
324  return;
325 
326  if (delayed_work_pending(&req->work))
328 
329  if (new_value != req->node.prio)
331  pm_qos_array[req->pm_qos_class]->constraints,
332  &req->node, PM_QOS_UPDATE_REQ, new_value);
333 
334  schedule_delayed_work(&req->work, usecs_to_jiffies(timeout_us));
335 }
336 
346 {
347  if (!req) /*guard against callers passing in null */
348  return;
349  /* silent return to keep pcm code cleaner */
350 
351  if (!pm_qos_request_active(req)) {
352  WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
353  return;
354  }
355 
356  if (delayed_work_pending(&req->work))
358 
359  pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
360  &req->node, PM_QOS_REMOVE_REQ,
362  memset(req, 0, sizeof(*req));
363 }
365 
375 {
376  int retval;
377 
379  pm_qos_array[pm_qos_class]->constraints->notifiers,
380  notifier);
381 
382  return retval;
383 }
385 
395 {
396  int retval;
397 
399  pm_qos_array[pm_qos_class]->constraints->notifiers,
400  notifier);
401 
402  return retval;
403 }
405 
406 /* User space interface to PM QoS classes via misc devices */
407 static int register_pm_qos_misc(struct pm_qos_object *qos)
408 {
410  qos->pm_qos_power_miscdev.name = qos->name;
411  qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
412 
413  return misc_register(&qos->pm_qos_power_miscdev);
414 }
415 
416 static int find_pm_qos_object_by_minor(int minor)
417 {
418  int pm_qos_class;
419 
420  for (pm_qos_class = 0;
421  pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
422  if (minor ==
423  pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
424  return pm_qos_class;
425  }
426  return -1;
427 }
428 
429 static int pm_qos_power_open(struct inode *inode, struct file *filp)
430 {
431  long pm_qos_class;
432 
433  pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
434  if (pm_qos_class >= 0) {
435  struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL);
436  if (!req)
437  return -ENOMEM;
438 
439  pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
440  filp->private_data = req;
441 
442  return 0;
443  }
444  return -EPERM;
445 }
446 
447 static int pm_qos_power_release(struct inode *inode, struct file *filp)
448 {
449  struct pm_qos_request *req;
450 
451  req = filp->private_data;
453  kfree(req);
454 
455  return 0;
456 }
457 
458 
459 static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
460  size_t count, loff_t *f_pos)
461 {
462  s32 value;
463  unsigned long flags;
464  struct pm_qos_request *req = filp->private_data;
465 
466  if (!req)
467  return -EINVAL;
468  if (!pm_qos_request_active(req))
469  return -EINVAL;
470 
471  spin_lock_irqsave(&pm_qos_lock, flags);
472  value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints);
473  spin_unlock_irqrestore(&pm_qos_lock, flags);
474 
475  return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
476 }
477 
478 static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
479  size_t count, loff_t *f_pos)
480 {
481  s32 value;
482  struct pm_qos_request *req;
483 
484  if (count == sizeof(s32)) {
485  if (copy_from_user(&value, buf, sizeof(s32)))
486  return -EFAULT;
487  } else if (count <= 11) { /* ASCII perhaps? */
488  char ascii_value[11];
489  unsigned long int ulval;
490  int ret;
491 
492  if (copy_from_user(ascii_value, buf, count))
493  return -EFAULT;
494 
495  if (count > 10) {
496  if (ascii_value[10] == '\n')
497  ascii_value[10] = '\0';
498  else
499  return -EINVAL;
500  } else {
501  ascii_value[count] = '\0';
502  }
503  ret = strict_strtoul(ascii_value, 16, &ulval);
504  if (ret) {
505  pr_debug("%s, 0x%lx, 0x%x\n", ascii_value, ulval, ret);
506  return -EINVAL;
507  }
508  value = (s32)lower_32_bits(ulval);
509  } else {
510  return -EINVAL;
511  }
512 
513  req = filp->private_data;
514  pm_qos_update_request(req, value);
515 
516  return count;
517 }
518 
519 
520 static int __init pm_qos_power_init(void)
521 {
522  int ret = 0;
523  int i;
524 
525  BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES);
526 
527  for (i = 1; i < PM_QOS_NUM_CLASSES; i++) {
528  ret = register_pm_qos_misc(pm_qos_array[i]);
529  if (ret < 0) {
530  printk(KERN_ERR "pm_qos_param: %s setup failed\n",
531  pm_qos_array[i]->name);
532  return ret;
533  }
534  }
535 
536  return ret;
537 }
538 
539 late_initcall(pm_qos_power_init);