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>
14 #include <linux/cpumask.h>
15 #include <linux/clockchips.h>
19 DEFINE_SPINLOCK(cpuidle_driver_lock
);
21 static void __cpuidle_set_cpu_driver(struct cpuidle_driver
*drv
, int cpu
);
22 static struct cpuidle_driver
* __cpuidle_get_cpu_driver(int cpu
);
24 static void cpuidle_setup_broadcast_timer(void *arg
)
26 int cpu
= smp_processor_id();
27 clockevents_notify((long)(arg
), &cpu
);
30 static void __cpuidle_driver_init(struct cpuidle_driver
*drv
, int cpu
)
36 for (i
= drv
->state_count
- 1; i
>= 0 ; i
--) {
38 if (!(drv
->states
[i
].flags
& CPUIDLE_FLAG_TIMER_STOP
))
42 on_each_cpu_mask(get_cpu_mask(cpu
), cpuidle_setup_broadcast_timer
,
43 (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON
, 1);
48 static int __cpuidle_register_driver(struct cpuidle_driver
*drv
, int cpu
)
50 if (!drv
|| !drv
->state_count
)
53 if (cpuidle_disabled())
56 if (__cpuidle_get_cpu_driver(cpu
))
59 __cpuidle_driver_init(drv
, cpu
);
61 __cpuidle_set_cpu_driver(drv
, cpu
);
66 static void __cpuidle_unregister_driver(struct cpuidle_driver
*drv
, int cpu
)
68 if (drv
!= __cpuidle_get_cpu_driver(cpu
))
71 if (!WARN_ON(drv
->refcnt
> 0))
72 __cpuidle_set_cpu_driver(NULL
, cpu
);
76 on_each_cpu_mask(get_cpu_mask(cpu
), cpuidle_setup_broadcast_timer
,
77 (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF
, 1);
81 #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
83 static DEFINE_PER_CPU(struct cpuidle_driver
*, cpuidle_drivers
);
85 static void __cpuidle_set_cpu_driver(struct cpuidle_driver
*drv
, int cpu
)
87 per_cpu(cpuidle_drivers
, cpu
) = drv
;
90 static struct cpuidle_driver
*__cpuidle_get_cpu_driver(int cpu
)
92 return per_cpu(cpuidle_drivers
, cpu
);
95 static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver
*drv
)
98 for_each_present_cpu(cpu
)
99 __cpuidle_unregister_driver(drv
, cpu
);
102 static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver
*drv
)
107 for_each_present_cpu(cpu
) {
108 ret
= __cpuidle_register_driver(drv
, cpu
);
114 for_each_present_cpu(i
) {
117 __cpuidle_unregister_driver(drv
, i
);
124 int cpuidle_register_cpu_driver(struct cpuidle_driver
*drv
, int cpu
)
128 spin_lock(&cpuidle_driver_lock
);
129 ret
= __cpuidle_register_driver(drv
, cpu
);
130 spin_unlock(&cpuidle_driver_lock
);
135 void cpuidle_unregister_cpu_driver(struct cpuidle_driver
*drv
, int cpu
)
137 spin_lock(&cpuidle_driver_lock
);
138 __cpuidle_unregister_driver(drv
, cpu
);
139 spin_unlock(&cpuidle_driver_lock
);
143 * cpuidle_register_driver - registers a driver
146 int cpuidle_register_driver(struct cpuidle_driver
*drv
)
150 spin_lock(&cpuidle_driver_lock
);
151 ret
= __cpuidle_register_all_cpu_driver(drv
);
152 spin_unlock(&cpuidle_driver_lock
);
156 EXPORT_SYMBOL_GPL(cpuidle_register_driver
);
159 * cpuidle_unregister_driver - unregisters a driver
162 void cpuidle_unregister_driver(struct cpuidle_driver
*drv
)
164 spin_lock(&cpuidle_driver_lock
);
165 __cpuidle_unregister_all_cpu_driver(drv
);
166 spin_unlock(&cpuidle_driver_lock
);
168 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver
);
172 static struct cpuidle_driver
*cpuidle_curr_driver
;
174 static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver
*drv
, int cpu
)
176 cpuidle_curr_driver
= drv
;
179 static inline struct cpuidle_driver
*__cpuidle_get_cpu_driver(int cpu
)
181 return cpuidle_curr_driver
;
185 * cpuidle_register_driver - registers a driver
188 int cpuidle_register_driver(struct cpuidle_driver
*drv
)
193 spin_lock(&cpuidle_driver_lock
);
194 ret
= __cpuidle_register_driver(drv
, cpu
);
195 spin_unlock(&cpuidle_driver_lock
);
200 EXPORT_SYMBOL_GPL(cpuidle_register_driver
);
203 * cpuidle_unregister_driver - unregisters a driver
206 void cpuidle_unregister_driver(struct cpuidle_driver
*drv
)
211 spin_lock(&cpuidle_driver_lock
);
212 __cpuidle_unregister_driver(drv
, cpu
);
213 spin_unlock(&cpuidle_driver_lock
);
216 EXPORT_SYMBOL_GPL(cpuidle_unregister_driver
);
220 * cpuidle_get_driver - return the current driver
222 struct cpuidle_driver
*cpuidle_get_driver(void)
224 struct cpuidle_driver
*drv
;
228 drv
= __cpuidle_get_cpu_driver(cpu
);
233 EXPORT_SYMBOL_GPL(cpuidle_get_driver
);
236 * cpuidle_get_cpu_driver - return the driver tied with a cpu
238 struct cpuidle_driver
*cpuidle_get_cpu_driver(struct cpuidle_device
*dev
)
243 return __cpuidle_get_cpu_driver(dev
->cpu
);
245 EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver
);
247 struct cpuidle_driver
*cpuidle_driver_ref(void)
249 struct cpuidle_driver
*drv
;
251 spin_lock(&cpuidle_driver_lock
);
253 drv
= cpuidle_get_driver();
256 spin_unlock(&cpuidle_driver_lock
);
260 void cpuidle_driver_unref(void)
262 struct cpuidle_driver
*drv
= cpuidle_get_driver();
264 spin_lock(&cpuidle_driver_lock
);
266 if (drv
&& !WARN_ON(drv
->refcnt
<= 0))
269 spin_unlock(&cpuidle_driver_lock
);