]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/cpuidle/driver.c
regmap: debugfs: Fix seeking from the cache
[karo-tx-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 set_power_states(struct cpuidle_driver *drv)
23 {
24         int i;
25
26         /*
27          * cpuidle driver should set the drv->power_specified bit
28          * before registering if the driver provides
29          * power_usage numbers.
30          *
31          * If power_specified is not set,
32          * we fill in power_usage with decreasing values as the
33          * cpuidle code has an implicit assumption that state Cn
34          * uses less power than C(n-1).
35          *
36          * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned
37          * an power value of -1.  So we use -2, -3, etc, for other
38          * c-states.
39          */
40         for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
41                 drv->states[i].power_usage = -1 - i;
42 }
43
44 static void __cpuidle_driver_init(struct cpuidle_driver *drv)
45 {
46         drv->refcnt = 0;
47
48         if (!drv->power_specified)
49                 set_power_states(drv);
50 }
51
52 static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
53 {
54         if (!drv || !drv->state_count)
55                 return -EINVAL;
56
57         if (cpuidle_disabled())
58                 return -ENODEV;
59
60         if (__cpuidle_get_cpu_driver(cpu))
61                 return -EBUSY;
62
63         __cpuidle_driver_init(drv);
64
65         __cpuidle_set_cpu_driver(drv, cpu);
66
67         return 0;
68 }
69
70 static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
71 {
72         if (drv != __cpuidle_get_cpu_driver(cpu))
73                 return;
74
75         if (!WARN_ON(drv->refcnt > 0))
76                 __cpuidle_set_cpu_driver(NULL, cpu);
77 }
78
79 #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
80
81 static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
82
83 static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
84 {
85         per_cpu(cpuidle_drivers, cpu) = drv;
86 }
87
88 static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
89 {
90         return per_cpu(cpuidle_drivers, cpu);
91 }
92
93 static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
94 {
95         int cpu;
96         for_each_present_cpu(cpu)
97                 __cpuidle_unregister_driver(drv, cpu);
98 }
99
100 static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
101 {
102         int ret = 0;
103         int i, cpu;
104
105         for_each_present_cpu(cpu) {
106                 ret = __cpuidle_register_driver(drv, cpu);
107                 if (ret)
108                         break;
109         }
110
111         if (ret)
112                 for_each_present_cpu(i) {
113                         if (i == cpu)
114                                 break;
115                         __cpuidle_unregister_driver(drv, i);
116                 }
117
118
119         return ret;
120 }
121
122 int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
123 {
124         int ret;
125
126         spin_lock(&cpuidle_driver_lock);
127         ret = __cpuidle_register_driver(drv, cpu);
128         spin_unlock(&cpuidle_driver_lock);
129
130         return ret;
131 }
132
133 void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
134 {
135         spin_lock(&cpuidle_driver_lock);
136         __cpuidle_unregister_driver(drv, cpu);
137         spin_unlock(&cpuidle_driver_lock);
138 }
139
140 /**
141  * cpuidle_register_driver - registers a driver
142  * @drv: the driver
143  */
144 int cpuidle_register_driver(struct cpuidle_driver *drv)
145 {
146         int ret;
147
148         spin_lock(&cpuidle_driver_lock);
149         ret = __cpuidle_register_all_cpu_driver(drv);
150         spin_unlock(&cpuidle_driver_lock);
151
152         return ret;
153 }
154 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
155
156 /**
157  * cpuidle_unregister_driver - unregisters a driver
158  * @drv: the driver
159  */
160 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
161 {
162         spin_lock(&cpuidle_driver_lock);
163         __cpuidle_unregister_all_cpu_driver(drv);
164         spin_unlock(&cpuidle_driver_lock);
165 }
166 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
167
168 #else
169
170 static struct cpuidle_driver *cpuidle_curr_driver;
171
172 static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
173 {
174         cpuidle_curr_driver = drv;
175 }
176
177 static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
178 {
179         return cpuidle_curr_driver;
180 }
181
182 /**
183  * cpuidle_register_driver - registers a driver
184  * @drv: the driver
185  */
186 int cpuidle_register_driver(struct cpuidle_driver *drv)
187 {
188         int ret, cpu;
189
190         cpu = get_cpu();
191         spin_lock(&cpuidle_driver_lock);
192         ret = __cpuidle_register_driver(drv, cpu);
193         spin_unlock(&cpuidle_driver_lock);
194         put_cpu();
195
196         return ret;
197 }
198 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
199
200 /**
201  * cpuidle_unregister_driver - unregisters a driver
202  * @drv: the driver
203  */
204 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
205 {
206         int cpu;
207
208         cpu = get_cpu();
209         spin_lock(&cpuidle_driver_lock);
210         __cpuidle_unregister_driver(drv, cpu);
211         spin_unlock(&cpuidle_driver_lock);
212         put_cpu();
213 }
214 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
215 #endif
216
217 /**
218  * cpuidle_get_driver - return the current driver
219  */
220 struct cpuidle_driver *cpuidle_get_driver(void)
221 {
222         struct cpuidle_driver *drv;
223         int cpu;
224
225         cpu = get_cpu();
226         drv = __cpuidle_get_cpu_driver(cpu);
227         put_cpu();
228
229         return drv;
230 }
231 EXPORT_SYMBOL_GPL(cpuidle_get_driver);
232
233 /**
234  * cpuidle_get_cpu_driver - return the driver tied with a cpu
235  */
236 struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
237 {
238         struct cpuidle_driver *drv;
239
240         if (!dev)
241                 return NULL;
242
243         spin_lock(&cpuidle_driver_lock);
244         drv = __cpuidle_get_cpu_driver(dev->cpu);
245         spin_unlock(&cpuidle_driver_lock);
246
247         return drv;
248 }
249 EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
250
251 struct cpuidle_driver *cpuidle_driver_ref(void)
252 {
253         struct cpuidle_driver *drv;
254
255         spin_lock(&cpuidle_driver_lock);
256
257         drv = cpuidle_get_driver();
258         drv->refcnt++;
259
260         spin_unlock(&cpuidle_driver_lock);
261         return drv;
262 }
263
264 void cpuidle_driver_unref(void)
265 {
266         struct cpuidle_driver *drv = cpuidle_get_driver();
267
268         spin_lock(&cpuidle_driver_lock);
269
270         if (drv && !WARN_ON(drv->refcnt <= 0))
271                 drv->refcnt--;
272
273         spin_unlock(&cpuidle_driver_lock);
274 }