1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * driver.c - driver support
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
5*4882a593Smuzhiyun * Shaohua Li <shaohua.li@intel.com>
6*4882a593Smuzhiyun * Adam Belay <abelay@novell.com>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * This code is licenced under the GPL.
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/mutex.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/sched.h>
14*4882a593Smuzhiyun #include <linux/sched/idle.h>
15*4882a593Smuzhiyun #include <linux/cpuidle.h>
16*4882a593Smuzhiyun #include <linux/cpumask.h>
17*4882a593Smuzhiyun #include <linux/tick.h>
18*4882a593Smuzhiyun #include <linux/cpu.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "cpuidle.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun DEFINE_SPINLOCK(cpuidle_driver_lock);
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /**
29*4882a593Smuzhiyun * __cpuidle_get_cpu_driver - return the cpuidle driver tied to a CPU.
30*4882a593Smuzhiyun * @cpu: the CPU handled by the driver
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * Returns a pointer to struct cpuidle_driver or NULL if no driver has been
33*4882a593Smuzhiyun * registered for @cpu.
34*4882a593Smuzhiyun */
__cpuidle_get_cpu_driver(int cpu)35*4882a593Smuzhiyun static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun return per_cpu(cpuidle_drivers, cpu);
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /**
41*4882a593Smuzhiyun * __cpuidle_unset_driver - unset per CPU driver variables.
42*4882a593Smuzhiyun * @drv: a valid pointer to a struct cpuidle_driver
43*4882a593Smuzhiyun *
44*4882a593Smuzhiyun * For each CPU in the driver's CPU mask, unset the registered driver per CPU
45*4882a593Smuzhiyun * variable. If @drv is different from the registered driver, the corresponding
46*4882a593Smuzhiyun * variable is not cleared.
47*4882a593Smuzhiyun */
__cpuidle_unset_driver(struct cpuidle_driver * drv)48*4882a593Smuzhiyun static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun int cpu;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun for_each_cpu(cpu, drv->cpumask) {
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (drv != __cpuidle_get_cpu_driver(cpu))
55*4882a593Smuzhiyun continue;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun per_cpu(cpuidle_drivers, cpu) = NULL;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /**
62*4882a593Smuzhiyun * __cpuidle_set_driver - set per CPU driver variables for the given driver.
63*4882a593Smuzhiyun * @drv: a valid pointer to a struct cpuidle_driver
64*4882a593Smuzhiyun *
65*4882a593Smuzhiyun * Returns 0 on success, -EBUSY if any CPU in the cpumask have a driver
66*4882a593Smuzhiyun * different from drv already.
67*4882a593Smuzhiyun */
__cpuidle_set_driver(struct cpuidle_driver * drv)68*4882a593Smuzhiyun static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun int cpu;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun for_each_cpu(cpu, drv->cpumask) {
73*4882a593Smuzhiyun struct cpuidle_driver *old_drv;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun old_drv = __cpuidle_get_cpu_driver(cpu);
76*4882a593Smuzhiyun if (old_drv && old_drv != drv)
77*4882a593Smuzhiyun return -EBUSY;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun for_each_cpu(cpu, drv->cpumask)
81*4882a593Smuzhiyun per_cpu(cpuidle_drivers, cpu) = drv;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun #else
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun static struct cpuidle_driver *cpuidle_curr_driver;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /**
91*4882a593Smuzhiyun * __cpuidle_get_cpu_driver - return the global cpuidle driver pointer.
92*4882a593Smuzhiyun * @cpu: ignored without the multiple driver support
93*4882a593Smuzhiyun *
94*4882a593Smuzhiyun * Return a pointer to a struct cpuidle_driver object or NULL if no driver was
95*4882a593Smuzhiyun * previously registered.
96*4882a593Smuzhiyun */
__cpuidle_get_cpu_driver(int cpu)97*4882a593Smuzhiyun static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun return cpuidle_curr_driver;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /**
103*4882a593Smuzhiyun * __cpuidle_set_driver - assign the global cpuidle driver variable.
104*4882a593Smuzhiyun * @drv: pointer to a struct cpuidle_driver object
105*4882a593Smuzhiyun *
106*4882a593Smuzhiyun * Returns 0 on success, -EBUSY if the driver is already registered.
107*4882a593Smuzhiyun */
__cpuidle_set_driver(struct cpuidle_driver * drv)108*4882a593Smuzhiyun static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun if (cpuidle_curr_driver)
111*4882a593Smuzhiyun return -EBUSY;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun cpuidle_curr_driver = drv;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun return 0;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /**
119*4882a593Smuzhiyun * __cpuidle_unset_driver - unset the global cpuidle driver variable.
120*4882a593Smuzhiyun * @drv: a pointer to a struct cpuidle_driver
121*4882a593Smuzhiyun *
122*4882a593Smuzhiyun * Reset the global cpuidle variable to NULL. If @drv does not match the
123*4882a593Smuzhiyun * registered driver, do nothing.
124*4882a593Smuzhiyun */
__cpuidle_unset_driver(struct cpuidle_driver * drv)125*4882a593Smuzhiyun static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun if (drv == cpuidle_curr_driver)
128*4882a593Smuzhiyun cpuidle_curr_driver = NULL;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun #endif
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /**
134*4882a593Smuzhiyun * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer on a cpu
135*4882a593Smuzhiyun * @arg: a void pointer used to match the SMP cross call API
136*4882a593Smuzhiyun *
137*4882a593Smuzhiyun * If @arg is NULL broadcast is disabled otherwise enabled
138*4882a593Smuzhiyun *
139*4882a593Smuzhiyun * This function is executed per CPU by an SMP cross call. It's not
140*4882a593Smuzhiyun * supposed to be called directly.
141*4882a593Smuzhiyun */
cpuidle_setup_broadcast_timer(void * arg)142*4882a593Smuzhiyun static void cpuidle_setup_broadcast_timer(void *arg)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun if (arg)
145*4882a593Smuzhiyun tick_broadcast_enable();
146*4882a593Smuzhiyun else
147*4882a593Smuzhiyun tick_broadcast_disable();
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /**
151*4882a593Smuzhiyun * __cpuidle_driver_init - initialize the driver's internal data
152*4882a593Smuzhiyun * @drv: a valid pointer to a struct cpuidle_driver
153*4882a593Smuzhiyun */
__cpuidle_driver_init(struct cpuidle_driver * drv)154*4882a593Smuzhiyun static void __cpuidle_driver_init(struct cpuidle_driver *drv)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun int i;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /*
159*4882a593Smuzhiyun * Use all possible CPUs as the default, because if the kernel boots
160*4882a593Smuzhiyun * with some CPUs offline and then we online one of them, the CPU
161*4882a593Smuzhiyun * notifier has to know which driver to assign.
162*4882a593Smuzhiyun */
163*4882a593Smuzhiyun if (!drv->cpumask)
164*4882a593Smuzhiyun drv->cpumask = (struct cpumask *)cpu_possible_mask;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun for (i = 0; i < drv->state_count; i++) {
167*4882a593Smuzhiyun struct cpuidle_state *s = &drv->states[i];
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /*
170*4882a593Smuzhiyun * Look for the timer stop flag in the different states and if
171*4882a593Smuzhiyun * it is found, indicate that the broadcast timer has to be set
172*4882a593Smuzhiyun * up.
173*4882a593Smuzhiyun */
174*4882a593Smuzhiyun if (s->flags & CPUIDLE_FLAG_TIMER_STOP)
175*4882a593Smuzhiyun drv->bctimer = 1;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * The core will use the target residency and exit latency
179*4882a593Smuzhiyun * values in nanoseconds, but allow drivers to provide them in
180*4882a593Smuzhiyun * microseconds too.
181*4882a593Smuzhiyun */
182*4882a593Smuzhiyun if (s->target_residency > 0)
183*4882a593Smuzhiyun s->target_residency_ns = s->target_residency * NSEC_PER_USEC;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun if (s->exit_latency > 0)
186*4882a593Smuzhiyun s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /**
191*4882a593Smuzhiyun * __cpuidle_register_driver: register the driver
192*4882a593Smuzhiyun * @drv: a valid pointer to a struct cpuidle_driver
193*4882a593Smuzhiyun *
194*4882a593Smuzhiyun * Do some sanity checks, initialize the driver, assign the driver to the
195*4882a593Smuzhiyun * global cpuidle driver variable(s) and set up the broadcast timer if the
196*4882a593Smuzhiyun * cpuidle driver has some states that shut down the local timer.
197*4882a593Smuzhiyun *
198*4882a593Smuzhiyun * Returns 0 on success, a negative error code otherwise:
199*4882a593Smuzhiyun * * -EINVAL if the driver pointer is NULL or no idle states are available
200*4882a593Smuzhiyun * * -ENODEV if the cpuidle framework is disabled
201*4882a593Smuzhiyun * * -EBUSY if the driver is already assigned to the global variable(s)
202*4882a593Smuzhiyun */
__cpuidle_register_driver(struct cpuidle_driver * drv)203*4882a593Smuzhiyun static int __cpuidle_register_driver(struct cpuidle_driver *drv)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun int ret;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (!drv || !drv->state_count)
208*4882a593Smuzhiyun return -EINVAL;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun ret = cpuidle_coupled_state_verify(drv);
211*4882a593Smuzhiyun if (ret)
212*4882a593Smuzhiyun return ret;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun if (cpuidle_disabled())
215*4882a593Smuzhiyun return -ENODEV;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun __cpuidle_driver_init(drv);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun ret = __cpuidle_set_driver(drv);
220*4882a593Smuzhiyun if (ret)
221*4882a593Smuzhiyun return ret;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (drv->bctimer)
224*4882a593Smuzhiyun on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
225*4882a593Smuzhiyun (void *)1, 1);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun return 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /**
231*4882a593Smuzhiyun * __cpuidle_unregister_driver - unregister the driver
232*4882a593Smuzhiyun * @drv: a valid pointer to a struct cpuidle_driver
233*4882a593Smuzhiyun *
234*4882a593Smuzhiyun * Check if the driver is no longer in use, reset the global cpuidle driver
235*4882a593Smuzhiyun * variable(s) and disable the timer broadcast notification mechanism if it was
236*4882a593Smuzhiyun * in use.
237*4882a593Smuzhiyun *
238*4882a593Smuzhiyun */
__cpuidle_unregister_driver(struct cpuidle_driver * drv)239*4882a593Smuzhiyun static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun if (drv->bctimer) {
242*4882a593Smuzhiyun drv->bctimer = 0;
243*4882a593Smuzhiyun on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
244*4882a593Smuzhiyun NULL, 1);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun __cpuidle_unset_driver(drv);
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /**
251*4882a593Smuzhiyun * cpuidle_register_driver - registers a driver
252*4882a593Smuzhiyun * @drv: a pointer to a valid struct cpuidle_driver
253*4882a593Smuzhiyun *
254*4882a593Smuzhiyun * Register the driver under a lock to prevent concurrent attempts to
255*4882a593Smuzhiyun * [un]register the driver from occuring at the same time.
256*4882a593Smuzhiyun *
257*4882a593Smuzhiyun * Returns 0 on success, a negative error code (returned by
258*4882a593Smuzhiyun * __cpuidle_register_driver()) otherwise.
259*4882a593Smuzhiyun */
cpuidle_register_driver(struct cpuidle_driver * drv)260*4882a593Smuzhiyun int cpuidle_register_driver(struct cpuidle_driver *drv)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun struct cpuidle_governor *gov;
263*4882a593Smuzhiyun int ret;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun spin_lock(&cpuidle_driver_lock);
266*4882a593Smuzhiyun ret = __cpuidle_register_driver(drv);
267*4882a593Smuzhiyun spin_unlock(&cpuidle_driver_lock);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun if (!ret && !strlen(param_governor) && drv->governor &&
270*4882a593Smuzhiyun (cpuidle_get_driver() == drv)) {
271*4882a593Smuzhiyun mutex_lock(&cpuidle_lock);
272*4882a593Smuzhiyun gov = cpuidle_find_governor(drv->governor);
273*4882a593Smuzhiyun if (gov) {
274*4882a593Smuzhiyun cpuidle_prev_governor = cpuidle_curr_governor;
275*4882a593Smuzhiyun if (cpuidle_switch_governor(gov) < 0)
276*4882a593Smuzhiyun cpuidle_prev_governor = NULL;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun mutex_unlock(&cpuidle_lock);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun return ret;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cpuidle_register_driver);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun /**
286*4882a593Smuzhiyun * cpuidle_unregister_driver - unregisters a driver
287*4882a593Smuzhiyun * @drv: a pointer to a valid struct cpuidle_driver
288*4882a593Smuzhiyun *
289*4882a593Smuzhiyun * Unregisters the cpuidle driver under a lock to prevent concurrent attempts
290*4882a593Smuzhiyun * to [un]register the driver from occuring at the same time. @drv has to
291*4882a593Smuzhiyun * match the currently registered driver.
292*4882a593Smuzhiyun */
cpuidle_unregister_driver(struct cpuidle_driver * drv)293*4882a593Smuzhiyun void cpuidle_unregister_driver(struct cpuidle_driver *drv)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun bool enabled = (cpuidle_get_driver() == drv);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun spin_lock(&cpuidle_driver_lock);
298*4882a593Smuzhiyun __cpuidle_unregister_driver(drv);
299*4882a593Smuzhiyun spin_unlock(&cpuidle_driver_lock);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (!enabled)
302*4882a593Smuzhiyun return;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun mutex_lock(&cpuidle_lock);
305*4882a593Smuzhiyun if (cpuidle_prev_governor) {
306*4882a593Smuzhiyun if (!cpuidle_switch_governor(cpuidle_prev_governor))
307*4882a593Smuzhiyun cpuidle_prev_governor = NULL;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun mutex_unlock(&cpuidle_lock);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /**
314*4882a593Smuzhiyun * cpuidle_get_driver - return the driver tied to the current CPU.
315*4882a593Smuzhiyun *
316*4882a593Smuzhiyun * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered.
317*4882a593Smuzhiyun */
cpuidle_get_driver(void)318*4882a593Smuzhiyun struct cpuidle_driver *cpuidle_get_driver(void)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct cpuidle_driver *drv;
321*4882a593Smuzhiyun int cpu;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun cpu = get_cpu();
324*4882a593Smuzhiyun drv = __cpuidle_get_cpu_driver(cpu);
325*4882a593Smuzhiyun put_cpu();
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun return drv;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cpuidle_get_driver);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /**
332*4882a593Smuzhiyun * cpuidle_get_cpu_driver - return the driver registered for a CPU.
333*4882a593Smuzhiyun * @dev: a valid pointer to a struct cpuidle_device
334*4882a593Smuzhiyun *
335*4882a593Smuzhiyun * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered
336*4882a593Smuzhiyun * for the CPU associated with @dev.
337*4882a593Smuzhiyun */
cpuidle_get_cpu_driver(struct cpuidle_device * dev)338*4882a593Smuzhiyun struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun if (!dev)
341*4882a593Smuzhiyun return NULL;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun return __cpuidle_get_cpu_driver(dev->cpu);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun /**
348*4882a593Smuzhiyun * cpuidle_driver_state_disabled - Disable or enable an idle state
349*4882a593Smuzhiyun * @drv: cpuidle driver owning the state
350*4882a593Smuzhiyun * @idx: State index
351*4882a593Smuzhiyun * @disable: Whether or not to disable the state
352*4882a593Smuzhiyun */
cpuidle_driver_state_disabled(struct cpuidle_driver * drv,int idx,bool disable)353*4882a593Smuzhiyun void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,
354*4882a593Smuzhiyun bool disable)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun unsigned int cpu;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun mutex_lock(&cpuidle_lock);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun spin_lock(&cpuidle_driver_lock);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if (!drv->cpumask) {
363*4882a593Smuzhiyun drv->states[idx].flags |= CPUIDLE_FLAG_UNUSABLE;
364*4882a593Smuzhiyun goto unlock;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun for_each_cpu(cpu, drv->cpumask) {
368*4882a593Smuzhiyun struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (!dev)
371*4882a593Smuzhiyun continue;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (disable)
374*4882a593Smuzhiyun dev->states_usage[idx].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
375*4882a593Smuzhiyun else
376*4882a593Smuzhiyun dev->states_usage[idx].disable &= ~CPUIDLE_STATE_DISABLED_BY_DRIVER;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun unlock:
380*4882a593Smuzhiyun spin_unlock(&cpuidle_driver_lock);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun mutex_unlock(&cpuidle_lock);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cpuidle_driver_state_disabled);
385