Branch data Line data Source code
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/sched.h>
14 : : #include <linux/cpuidle.h>
15 : : #include <linux/cpumask.h>
16 : : #include <linux/clockchips.h>
17 : :
18 : : #include "cpuidle.h"
19 : :
20 : : DEFINE_SPINLOCK(cpuidle_driver_lock);
21 : :
22 : : #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
23 : :
24 : : static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
25 : :
26 : : /**
27 : : * __cpuidle_get_cpu_driver - return the cpuidle driver tied to a CPU.
28 : : * @cpu: the CPU handled by the driver
29 : : *
30 : : * Returns a pointer to struct cpuidle_driver or NULL if no driver has been
31 : : * registered for @cpu.
32 : : */
33 : 0 : static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
34 : : {
35 : 8150992 : return per_cpu(cpuidle_drivers, cpu);
36 : : }
37 : :
38 : : /**
39 : : * __cpuidle_unset_driver - unset per CPU driver variables.
40 : : * @drv: a valid pointer to a struct cpuidle_driver
41 : : *
42 : : * For each CPU in the driver's CPU mask, unset the registered driver per CPU
43 : : * variable. If @drv is different from the registered driver, the corresponding
44 : : * variable is not cleared.
45 : : */
46 : : static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
47 : : {
48 : : int cpu;
49 : :
50 [ # # # # ]: 0 : for_each_cpu(cpu, drv->cpumask) {
51 : :
52 [ # # ][ # # ]: 0 : if (drv != __cpuidle_get_cpu_driver(cpu))
53 : 0 : continue;
54 : :
55 : 0 : per_cpu(cpuidle_drivers, cpu) = NULL;
56 : : }
57 : : }
58 : :
59 : : /**
60 : : * __cpuidle_set_driver - set per CPU driver variables for the given driver.
61 : : * @drv: a valid pointer to a struct cpuidle_driver
62 : : *
63 : : * For each CPU in the driver's cpumask, unset the registered driver per CPU
64 : : * to @drv.
65 : : *
66 : : * Returns 0 on success, -EBUSY if the CPUs have driver(s) already.
67 : : */
68 : : static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
69 : : {
70 : : int cpu;
71 : :
72 [ # # ]: 0 : for_each_cpu(cpu, drv->cpumask) {
73 : :
74 [ # # ]: 0 : if (__cpuidle_get_cpu_driver(cpu)) {
75 : : __cpuidle_unset_driver(drv);
76 : : return -EBUSY;
77 : : }
78 : :
79 : 0 : per_cpu(cpuidle_drivers, cpu) = drv;
80 : : }
81 : :
82 : : return 0;
83 : : }
84 : :
85 : : #else
86 : :
87 : : static struct cpuidle_driver *cpuidle_curr_driver;
88 : :
89 : : /**
90 : : * __cpuidle_get_cpu_driver - return the global cpuidle driver pointer.
91 : : * @cpu: ignored without the multiple driver support
92 : : *
93 : : * Return a pointer to a struct cpuidle_driver object or NULL if no driver was
94 : : * previously registered.
95 : : */
96 : : static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
97 : : {
98 : : return cpuidle_curr_driver;
99 : : }
100 : :
101 : : /**
102 : : * __cpuidle_set_driver - assign the global cpuidle driver variable.
103 : : * @drv: pointer to a struct cpuidle_driver object
104 : : *
105 : : * Returns 0 on success, -EBUSY if the driver is already registered.
106 : : */
107 : : static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
108 : : {
109 : : if (cpuidle_curr_driver)
110 : : return -EBUSY;
111 : :
112 : : cpuidle_curr_driver = drv;
113 : :
114 : : return 0;
115 : : }
116 : :
117 : : /**
118 : : * __cpuidle_unset_driver - unset the global cpuidle driver variable.
119 : : * @drv: a pointer to a struct cpuidle_driver
120 : : *
121 : : * Reset the global cpuidle variable to NULL. If @drv does not match the
122 : : * registered driver, do nothing.
123 : : */
124 : : static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
125 : : {
126 : : if (drv == cpuidle_curr_driver)
127 : : cpuidle_curr_driver = NULL;
128 : : }
129 : :
130 : : #endif
131 : :
132 : : /**
133 : : * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer
134 : : * @arg: a void pointer used to match the SMP cross call API
135 : : *
136 : : * @arg is used as a value of type 'long' with one of the two values:
137 : : * - CLOCK_EVT_NOTIFY_BROADCAST_ON
138 : : * - CLOCK_EVT_NOTIFY_BROADCAST_OFF
139 : : *
140 : : * Set the broadcast timer notification for the current CPU. This function
141 : : * is executed per CPU by an SMP cross call. It not supposed to be called
142 : : * directly.
143 : : */
144 : 0 : static void cpuidle_setup_broadcast_timer(void *arg)
145 : : {
146 : 0 : int cpu = smp_processor_id();
147 : 0 : clockevents_notify((long)(arg), &cpu);
148 : 0 : }
149 : :
150 : : /**
151 : : * __cpuidle_driver_init - initialize the driver's internal data
152 : : * @drv: a valid pointer to a struct cpuidle_driver
153 : : */
154 : : static void __cpuidle_driver_init(struct cpuidle_driver *drv)
155 : : {
156 : : int i;
157 : :
158 : 0 : drv->refcnt = 0;
159 : :
160 : : /*
161 : : * Use all possible CPUs as the default, because if the kernel boots
162 : : * with some CPUs offline and then we online one of them, the CPU
163 : : * notifier has to know which driver to assign.
164 : : */
165 [ # # ]: 0 : if (!drv->cpumask)
166 : 0 : drv->cpumask = (struct cpumask *)cpu_possible_mask;
167 : :
168 : : /*
169 : : * Look for the timer stop flag in the different states, so that we know
170 : : * if the broadcast timer has to be set up. The loop is in the reverse
171 : : * order, because usually one of the deeper states have this flag set.
172 : : */
173 [ # # ]: 0 : for (i = drv->state_count - 1; i >= 0 ; i--) {
174 [ # # ]: 0 : if (drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP) {
175 : 0 : drv->bctimer = 1;
176 : : break;
177 : : }
178 : : }
179 : : }
180 : :
181 : : #ifdef CONFIG_ARCH_HAS_CPU_RELAX
182 : : static int poll_idle(struct cpuidle_device *dev,
183 : : struct cpuidle_driver *drv, int index)
184 : : {
185 : : ktime_t t1, t2;
186 : : s64 diff;
187 : :
188 : : t1 = ktime_get();
189 : : local_irq_enable();
190 : : while (!need_resched())
191 : : cpu_relax();
192 : :
193 : : t2 = ktime_get();
194 : : diff = ktime_to_us(ktime_sub(t2, t1));
195 : : if (diff > INT_MAX)
196 : : diff = INT_MAX;
197 : :
198 : : dev->last_residency = (int) diff;
199 : :
200 : : return index;
201 : : }
202 : :
203 : : static void poll_idle_init(struct cpuidle_driver *drv)
204 : : {
205 : : struct cpuidle_state *state = &drv->states[0];
206 : :
207 : : snprintf(state->name, CPUIDLE_NAME_LEN, "POLL");
208 : : snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE");
209 : : state->exit_latency = 0;
210 : : state->target_residency = 0;
211 : : state->power_usage = -1;
212 : : state->flags = 0;
213 : : state->enter = poll_idle;
214 : : state->disabled = false;
215 : : }
216 : : #else
217 : : static void poll_idle_init(struct cpuidle_driver *drv) {}
218 : : #endif /* !CONFIG_ARCH_HAS_CPU_RELAX */
219 : :
220 : : /**
221 : : * __cpuidle_register_driver: register the driver
222 : : * @drv: a valid pointer to a struct cpuidle_driver
223 : : *
224 : : * Do some sanity checks, initialize the driver, assign the driver to the
225 : : * global cpuidle driver variable(s) and set up the broadcast timer if the
226 : : * cpuidle driver has some states that shut down the local timer.
227 : : *
228 : : * Returns 0 on success, a negative error code otherwise:
229 : : * * -EINVAL if the driver pointer is NULL or no idle states are available
230 : : * * -ENODEV if the cpuidle framework is disabled
231 : : * * -EBUSY if the driver is already assigned to the global variable(s)
232 : : */
233 : 0 : static int __cpuidle_register_driver(struct cpuidle_driver *drv)
234 : : {
235 : : int ret;
236 : :
237 [ # # ][ # # ]: 0 : if (!drv || !drv->state_count)
238 : : return -EINVAL;
239 : :
240 [ # # ]: 0 : if (cpuidle_disabled())
241 : : return -ENODEV;
242 : :
243 : : __cpuidle_driver_init(drv);
244 : :
245 : : ret = __cpuidle_set_driver(drv);
246 [ # # ]: 0 : if (ret)
247 : : return ret;
248 : :
249 [ # # ]: 0 : if (drv->bctimer)
250 : 0 : on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
251 : : (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
252 : :
253 : : poll_idle_init(drv);
254 : :
255 : : return 0;
256 : : }
257 : :
258 : : /**
259 : : * __cpuidle_unregister_driver - unregister the driver
260 : : * @drv: a valid pointer to a struct cpuidle_driver
261 : : *
262 : : * Check if the driver is no longer in use, reset the global cpuidle driver
263 : : * variable(s) and disable the timer broadcast notification mechanism if it was
264 : : * in use.
265 : : *
266 : : */
267 : 0 : static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
268 : : {
269 [ # # ][ # # ]: 0 : if (WARN_ON(drv->refcnt > 0))
270 : 0 : return;
271 : :
272 [ # # ]: 0 : if (drv->bctimer) {
273 : 0 : drv->bctimer = 0;
274 : 0 : on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
275 : : (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
276 : : }
277 : :
278 : : __cpuidle_unset_driver(drv);
279 : : }
280 : :
281 : : /**
282 : : * cpuidle_register_driver - registers a driver
283 : : * @drv: a pointer to a valid struct cpuidle_driver
284 : : *
285 : : * Register the driver under a lock to prevent concurrent attempts to
286 : : * [un]register the driver from occuring at the same time.
287 : : *
288 : : * Returns 0 on success, a negative error code (returned by
289 : : * __cpuidle_register_driver()) otherwise.
290 : : */
291 : 0 : int cpuidle_register_driver(struct cpuidle_driver *drv)
292 : : {
293 : : int ret;
294 : :
295 : : spin_lock(&cpuidle_driver_lock);
296 : 0 : ret = __cpuidle_register_driver(drv);
297 : : spin_unlock(&cpuidle_driver_lock);
298 : :
299 : 0 : return ret;
300 : : }
301 : : EXPORT_SYMBOL_GPL(cpuidle_register_driver);
302 : :
303 : : /**
304 : : * cpuidle_unregister_driver - unregisters a driver
305 : : * @drv: a pointer to a valid struct cpuidle_driver
306 : : *
307 : : * Unregisters the cpuidle driver under a lock to prevent concurrent attempts
308 : : * to [un]register the driver from occuring at the same time. @drv has to
309 : : * match the currently registered driver.
310 : : */
311 : 0 : void cpuidle_unregister_driver(struct cpuidle_driver *drv)
312 : : {
313 : : spin_lock(&cpuidle_driver_lock);
314 : 0 : __cpuidle_unregister_driver(drv);
315 : : spin_unlock(&cpuidle_driver_lock);
316 : 0 : }
317 : : EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
318 : :
319 : : /**
320 : : * cpuidle_get_driver - return the driver tied to the current CPU.
321 : : *
322 : : * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered.
323 : : */
324 : 0 : struct cpuidle_driver *cpuidle_get_driver(void)
325 : : {
326 : : struct cpuidle_driver *drv;
327 : : int cpu;
328 : :
329 : 0 : cpu = get_cpu();
330 : : drv = __cpuidle_get_cpu_driver(cpu);
331 : 0 : put_cpu();
332 : :
333 : 0 : return drv;
334 : : }
335 : : EXPORT_SYMBOL_GPL(cpuidle_get_driver);
336 : :
337 : : /**
338 : : * cpuidle_get_cpu_driver - return the driver registered for a CPU.
339 : : * @dev: a valid pointer to a struct cpuidle_device
340 : : *
341 : : * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered
342 : : * for the CPU associated with @dev.
343 : : */
344 : 0 : struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
345 : : {
346 [ + + ]: 8605607 : if (!dev)
347 : : return NULL;
348 : :
349 : 8150992 : return __cpuidle_get_cpu_driver(dev->cpu);
350 : : }
351 : : EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
352 : :
353 : : /**
354 : : * cpuidle_driver_ref - get a reference to the driver.
355 : : *
356 : : * Increment the reference counter of the cpuidle driver associated with
357 : : * the current CPU.
358 : : *
359 : : * Returns a pointer to the driver, or NULL if the current CPU has no driver.
360 : : */
361 : 0 : struct cpuidle_driver *cpuidle_driver_ref(void)
362 : : {
363 : : struct cpuidle_driver *drv;
364 : :
365 : : spin_lock(&cpuidle_driver_lock);
366 : :
367 : : drv = cpuidle_get_driver();
368 [ # # ]: 0 : if (drv)
369 : 0 : drv->refcnt++;
370 : :
371 : : spin_unlock(&cpuidle_driver_lock);
372 : 0 : return drv;
373 : : }
374 : :
375 : : /**
376 : : * cpuidle_driver_unref - puts down the refcount for the driver
377 : : *
378 : : * Decrement the reference counter of the cpuidle driver associated with
379 : : * the current CPU.
380 : : */
381 : 0 : void cpuidle_driver_unref(void)
382 : : {
383 : : struct cpuidle_driver *drv;
384 : :
385 : : spin_lock(&cpuidle_driver_lock);
386 : :
387 : : drv = cpuidle_get_driver();
388 [ # # ][ # # ]: 0 : if (drv && !WARN_ON(drv->refcnt <= 0))
[ # # ]
389 : 0 : drv->refcnt--;
390 : :
391 : : spin_unlock(&cpuidle_driver_lock);
392 : 0 : }
|