2 * driver.c - driver support
4 * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
5 * Shaohua Li <shaohua.li@intel.com>
6 * Adam Belay <abelay@novell.com>
8 * This code is licenced under the GPL.
11 #include <linux/mutex.h>
12 #include <linux/module.h>
13 #include <linux/cpuidle.h>
17 DEFINE_SPINLOCK(cpuidle_driver_lock);
19 static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
20 static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
22 static void set_power_states(struct cpuidle_driver *drv)
27 * cpuidle driver should set the drv->power_specified bit
28 * before registering if the driver provides
29 * power_usage numbers.
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).
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
40 for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++)
41 drv->states[i].power_usage = -1 - i;
44 static void __cpuidle_driver_init(struct cpuidle_driver *drv)
48 if (!drv->power_specified)
49 set_power_states(drv);
52 static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
54 if (!drv || !drv->state_count)
57 if (cpuidle_disabled())
60 if (__cpuidle_get_cpu_driver(cpu))
63 __cpuidle_driver_init(drv);
65 __cpuidle_set_cpu_driver(drv, cpu);
70 static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
72 if (drv != __cpuidle_get_cpu_driver(cpu))
75 if (!WARN_ON(drv->refcnt > 0))
76 __cpuidle_set_cpu_driver(NULL, cpu);
79 #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
81 static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
83 static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
85 per_cpu(cpuidle_drivers, cpu) = drv;
88 static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
90 return per_cpu(cpuidle_drivers, cpu);
93 static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
96 for_each_present_cpu(cpu)
97 __cpuidle_unregister_driver(drv, cpu);
100 static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
105 for_each_present_cpu(cpu) {
106 ret = __cpuidle_register_driver(drv, cpu);
112 for_each_present_cpu(i) {
115 __cpuidle_unregister_driver(drv, i);
122 int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
126 spin_lock(&cpuidle_driver_lock);
127 ret = __cpuidle_register_driver(drv, cpu);
128 spin_unlock(&cpuidle_driver_lock);
133 void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
135 spin_lock(&cpuidle_driver_lock);
136 __cpuidle_unregister_driver(drv, cpu);
137 spin_unlock(&cpuidle_driver_lock);
141 * cpuidle_register_driver - registers a driver
144 int cpuidle_register_driver(struct cpuidle_driver *drv)
148 spin_lock(&cpuidle_driver_lock);
149 ret = __cpuidle_register_all_cpu_driver(drv);
150 spin_unlock(&cpuidle_driver_lock);
154 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
157 * cpuidle_unregister_driver - unregisters a driver
160 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
162 spin_lock(&cpuidle_driver_lock);
163 __cpuidle_unregister_all_cpu_driver(drv);
164 spin_unlock(&cpuidle_driver_lock);
166 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
170 static struct cpuidle_driver *cpuidle_curr_driver;
172 static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
174 cpuidle_curr_driver = drv;
177 static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
179 return cpuidle_curr_driver;
183 * cpuidle_register_driver - registers a driver
186 int cpuidle_register_driver(struct cpuidle_driver *drv)
191 spin_lock(&cpuidle_driver_lock);
192 ret = __cpuidle_register_driver(drv, cpu);
193 spin_unlock(&cpuidle_driver_lock);
198 EXPORT_SYMBOL_GPL(cpuidle_register_driver);
201 * cpuidle_unregister_driver - unregisters a driver
204 void cpuidle_unregister_driver(struct cpuidle_driver *drv)
209 spin_lock(&cpuidle_driver_lock);
210 __cpuidle_unregister_driver(drv, cpu);
211 spin_unlock(&cpuidle_driver_lock);
214 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
218 * cpuidle_get_driver - return the current driver
220 struct cpuidle_driver *cpuidle_get_driver(void)
222 struct cpuidle_driver *drv;
226 drv = __cpuidle_get_cpu_driver(cpu);
231 EXPORT_SYMBOL_GPL(cpuidle_get_driver);
234 * cpuidle_get_cpu_driver - return the driver tied with a cpu
236 struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
241 return __cpuidle_get_cpu_driver(dev->cpu);
243 EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
245 struct cpuidle_driver *cpuidle_driver_ref(void)
247 struct cpuidle_driver *drv;
249 spin_lock(&cpuidle_driver_lock);
251 drv = cpuidle_get_driver();
254 spin_unlock(&cpuidle_driver_lock);
258 void cpuidle_driver_unref(void)
260 struct cpuidle_driver *drv = cpuidle_get_driver();
262 spin_lock(&cpuidle_driver_lock);
264 if (drv && !WARN_ON(drv->refcnt <= 0))
267 spin_unlock(&cpuidle_driver_lock);