Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
driver.c
Go to the documentation of this file.
1 /*
2  * driver.c - driver support
3  *
4  * (C) 2006-2007 Venkatesh Pallipadi <[email protected]>
5  * Shaohua Li <[email protected]>
6  * Adam Belay <[email protected]>
7  *
8  * This code is licenced under the GPL.
9  */
10 
11 #include <linux/mutex.h>
12 #include <linux/module.h>
13 #include <linux/cpuidle.h>
14 
15 #include "cpuidle.h"
16 
17 static struct cpuidle_driver *cpuidle_curr_driver;
18 DEFINE_SPINLOCK(cpuidle_driver_lock);
20 
21 static void set_power_states(struct cpuidle_driver *drv)
22 {
23  int i;
24 
25  /*
26  * cpuidle driver should set the drv->power_specified bit
27  * before registering if the driver provides
28  * power_usage numbers.
29  *
30  * If power_specified is not set,
31  * we fill in power_usage with decreasing values as the
32  * cpuidle code has an implicit assumption that state Cn
33  * uses less power than C(n-1).
34  *
35  * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
36  * an power value of -1. So we use -2, -3, etc, for other
37  * c-states.
38  */
39  for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
40  drv->states[i].power_usage = -1 - i;
41 }
42 
48 {
49  if (!drv || !drv->state_count)
50  return -EINVAL;
51 
52  if (cpuidle_disabled())
53  return -ENODEV;
54 
55  spin_lock(&cpuidle_driver_lock);
56  if (cpuidle_curr_driver) {
57  spin_unlock(&cpuidle_driver_lock);
58  return -EBUSY;
59  }
60 
61  if (!drv->power_specified)
62  set_power_states(drv);
63 
64  cpuidle_curr_driver = drv;
65 
66  spin_unlock(&cpuidle_driver_lock);
67 
68  return 0;
69 }
71 
76 {
77  return cpuidle_curr_driver;
78 }
80 
86 {
87  if (drv != cpuidle_curr_driver) {
88  WARN(1, "invalid cpuidle_unregister_driver(%s)\n",
89  drv->name);
90  return;
91  }
92 
93  spin_lock(&cpuidle_driver_lock);
94 
96  cpuidle_curr_driver = NULL;
97 
98  spin_unlock(&cpuidle_driver_lock);
99 }
101 
103 {
104  struct cpuidle_driver *drv;
105 
106  spin_lock(&cpuidle_driver_lock);
107 
108  drv = cpuidle_curr_driver;
110 
111  spin_unlock(&cpuidle_driver_lock);
112  return drv;
113 }
114 
116 {
117  spin_lock(&cpuidle_driver_lock);
118 
119  if (!WARN_ON(cpuidle_driver_refcount <= 0))
121 
122  spin_unlock(&cpuidle_driver_lock);
123 }