Merge tag 'v3.8-rc7' into regulator-core
[deliverable/linux.git] / drivers / cpuidle / driver.c
1 /*
2 * driver.c - driver support
3 *
4 * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
5 * Shaohua Li <shaohua.li@intel.com>
6 * Adam Belay <abelay@novell.com>
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 DEFINE_SPINLOCK(cpuidle_driver_lock);
18
19 static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
20 static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
21
22 static void __cpuidle_driver_init(struct cpuidle_driver *drv)
23 {
24 drv->refcnt = 0;
25 }
26
27 static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
28 {
29 if (!drv || !drv->state_count)
30 return -EINVAL;
31
32 if (cpuidle_disabled())
33 return -ENODEV;
34
35 if (__cpuidle_get_cpu_driver(cpu))
36 return -EBUSY;
37
38 __cpuidle_driver_init(drv);
39
40 __cpuidle_set_cpu_driver(drv, cpu);
41
42 return 0;
43 }
44
45 static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
46 {
47 if (drv != __cpuidle_get_cpu_driver(cpu))
48 return;
49
50 if (!WARN_ON(drv->refcnt > 0))
51 __cpuidle_set_cpu_driver(NULL, cpu);
52 }
53
54 #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
55
56 static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
57
58 static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
59 {
60 per_cpu(cpuidle_drivers, cpu) = drv;
61 }
62
63 static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
64 {
65 return per_cpu(cpuidle_drivers, cpu);
66 }
67
68 static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
69 {
70 int cpu;
71 for_each_present_cpu(cpu)
72 __cpuidle_unregister_driver(drv, cpu);
73 }
74
75 static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
76 {
77 int ret = 0;
78 int i, cpu;
79
80 for_each_present_cpu(cpu) {
81 ret = __cpuidle_register_driver(drv, cpu);
82 if (ret)
83 break;
84 }
85
86 if (ret)
87 for_each_present_cpu(i) {
88 if (i == cpu)
89 break;
90 __cpuidle_unregister_driver(drv, i);
91 }
92
93
94 return ret;
95 }
96
97 int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
98 {
99 int ret;
100
101 spin_lock(&cpuidle_driver_lock);
102 ret = __cpuidle_register_driver(drv, cpu);
103 spin_unlock(&cpuidle_driver_lock);
104
105 return ret;
106 }
107
108 void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
109 {
110 spin_lock(&cpuidle_driver_lock);
111 __cpuidle_unregister_driver(drv, cpu);
112 spin_unlock(&cpuidle_driver_lock);
113 }
114
115 /**
116 * cpuidle_register_driver - registers a driver
117 * @drv: the driver
118 */
119 int cpuidle_register_driver(struct cpuidle_driver *drv)
120 {
121 int ret;
122
123 spin_lock(&cpuidle_driver_lock);
124 ret = __cpuidle_register_all_cpu_driver(drv);
125 spin_unlock(&cpuidle_driver_lock);
126
127 return ret;
128 }
129 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
130
131 /**
132 * cpuidle_unregister_driver - unregisters a driver
133 * @drv: the driver
134 */
135 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
136 {
137 spin_lock(&cpuidle_driver_lock);
138 __cpuidle_unregister_all_cpu_driver(drv);
139 spin_unlock(&cpuidle_driver_lock);
140 }
141 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
142
143 #else
144
145 static struct cpuidle_driver *cpuidle_curr_driver;
146
147 static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
148 {
149 cpuidle_curr_driver = drv;
150 }
151
152 static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
153 {
154 return cpuidle_curr_driver;
155 }
156
157 /**
158 * cpuidle_register_driver - registers a driver
159 * @drv: the driver
160 */
161 int cpuidle_register_driver(struct cpuidle_driver *drv)
162 {
163 int ret, cpu;
164
165 cpu = get_cpu();
166 spin_lock(&cpuidle_driver_lock);
167 ret = __cpuidle_register_driver(drv, cpu);
168 spin_unlock(&cpuidle_driver_lock);
169 put_cpu();
170
171 return ret;
172 }
173 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
174
175 /**
176 * cpuidle_unregister_driver - unregisters a driver
177 * @drv: the driver
178 */
179 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
180 {
181 int cpu;
182
183 cpu = get_cpu();
184 spin_lock(&cpuidle_driver_lock);
185 __cpuidle_unregister_driver(drv, cpu);
186 spin_unlock(&cpuidle_driver_lock);
187 put_cpu();
188 }
189 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
190 #endif
191
192 /**
193 * cpuidle_get_driver - return the current driver
194 */
195 struct cpuidle_driver *cpuidle_get_driver(void)
196 {
197 struct cpuidle_driver *drv;
198 int cpu;
199
200 cpu = get_cpu();
201 drv = __cpuidle_get_cpu_driver(cpu);
202 put_cpu();
203
204 return drv;
205 }
206 EXPORT_SYMBOL_GPL(cpuidle_get_driver);
207
208 /**
209 * cpuidle_get_cpu_driver - return the driver tied with a cpu
210 */
211 struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
212 {
213 if (!dev)
214 return NULL;
215
216 return __cpuidle_get_cpu_driver(dev->cpu);
217 }
218 EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
219
220 struct cpuidle_driver *cpuidle_driver_ref(void)
221 {
222 struct cpuidle_driver *drv;
223
224 spin_lock(&cpuidle_driver_lock);
225
226 drv = cpuidle_get_driver();
227 drv->refcnt++;
228
229 spin_unlock(&cpuidle_driver_lock);
230 return drv;
231 }
232
233 void cpuidle_driver_unref(void)
234 {
235 struct cpuidle_driver *drv = cpuidle_get_driver();
236
237 spin_lock(&cpuidle_driver_lock);
238
239 if (drv && !WARN_ON(drv->refcnt <= 0))
240 drv->refcnt--;
241
242 spin_unlock(&cpuidle_driver_lock);
243 }
This page took 0.041523 seconds and 5 git commands to generate.