]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/cpuidle/driver.c
Merge tag 'v3.9-rc3' into next
[mirror_ubuntu-bionic-kernel.git] / drivers / cpuidle / driver.c
CommitLineData
4f86d3a8
LB
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
4f86d3a8
LB
17DEFINE_SPINLOCK(cpuidle_driver_lock);
18
bf4d1b5d
DL
19static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
20static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
21
13dd52f1
DL
22static void __cpuidle_driver_init(struct cpuidle_driver *drv)
23{
24 drv->refcnt = 0;
13dd52f1
DL
25}
26
bf4d1b5d 27static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
4f86d3a8 28{
fc850f39 29 if (!drv || !drv->state_count)
4f86d3a8
LB
30 return -EINVAL;
31
62027aea
LB
32 if (cpuidle_disabled())
33 return -ENODEV;
34
bf4d1b5d 35 if (__cpuidle_get_cpu_driver(cpu))
4f86d3a8 36 return -EBUSY;
ed953472 37
13dd52f1 38 __cpuidle_driver_init(drv);
ed953472 39
bf4d1b5d 40 __cpuidle_set_cpu_driver(drv, cpu);
42f67f2a 41
13dd52f1
DL
42 return 0;
43}
44
bf4d1b5d 45static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
13dd52f1 46{
bf4d1b5d 47 if (drv != __cpuidle_get_cpu_driver(cpu))
13dd52f1
DL
48 return;
49
50 if (!WARN_ON(drv->refcnt > 0))
bf4d1b5d
DL
51 __cpuidle_set_cpu_driver(NULL, cpu);
52}
53
54#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
55
56static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
57
58static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
59{
60 per_cpu(cpuidle_drivers, cpu) = drv;
61}
62
63static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
64{
65 return per_cpu(cpuidle_drivers, cpu);
66}
67
68static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
69{
70 int cpu;
71 for_each_present_cpu(cpu)
72 __cpuidle_unregister_driver(drv, cpu);
73}
74
75static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
76{
77 int ret = 0;
78 int i, cpu;
79
80 for_each_present_cpu(cpu) {
81 ret = __cpuidle_register_driver(drv, cpu);
82 if (ret)
83 break;
84 }
85
86 if (ret)
87 for_each_present_cpu(i) {
88 if (i == cpu)
89 break;
90 __cpuidle_unregister_driver(drv, i);
91 }
92
93
94 return ret;
95}
96
97int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
98{
99 int ret;
100
101 spin_lock(&cpuidle_driver_lock);
102 ret = __cpuidle_register_driver(drv, cpu);
103 spin_unlock(&cpuidle_driver_lock);
104
105 return ret;
106}
107
108void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
109{
110 spin_lock(&cpuidle_driver_lock);
111 __cpuidle_unregister_driver(drv, cpu);
112 spin_unlock(&cpuidle_driver_lock);
13dd52f1 113}
ed953472 114
13dd52f1
DL
115/**
116 * cpuidle_register_driver - registers a driver
117 * @drv: the driver
118 */
119int cpuidle_register_driver(struct cpuidle_driver *drv)
120{
121 int ret;
122
123 spin_lock(&cpuidle_driver_lock);
bf4d1b5d 124 ret = __cpuidle_register_all_cpu_driver(drv);
4f86d3a8
LB
125 spin_unlock(&cpuidle_driver_lock);
126
13dd52f1 127 return ret;
4f86d3a8 128}
4f86d3a8
LB
129EXPORT_SYMBOL_GPL(cpuidle_register_driver);
130
752138df 131/**
bf4d1b5d
DL
132 * cpuidle_unregister_driver - unregisters a driver
133 * @drv: the driver
752138df 134 */
bf4d1b5d
DL
135void cpuidle_unregister_driver(struct cpuidle_driver *drv)
136{
137 spin_lock(&cpuidle_driver_lock);
138 __cpuidle_unregister_all_cpu_driver(drv);
139 spin_unlock(&cpuidle_driver_lock);
140}
141EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
142
143#else
144
145static struct cpuidle_driver *cpuidle_curr_driver;
146
147static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
148{
149 cpuidle_curr_driver = drv;
150}
151
152static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
752138df
LB
153{
154 return cpuidle_curr_driver;
155}
bf4d1b5d
DL
156
157/**
158 * cpuidle_register_driver - registers a driver
159 * @drv: the driver
160 */
161int cpuidle_register_driver(struct cpuidle_driver *drv)
162{
163 int ret, cpu;
164
165 cpu = get_cpu();
166 spin_lock(&cpuidle_driver_lock);
167 ret = __cpuidle_register_driver(drv, cpu);
168 spin_unlock(&cpuidle_driver_lock);
169 put_cpu();
170
171 return ret;
172}
173EXPORT_SYMBOL_GPL(cpuidle_register_driver);
752138df 174
4f86d3a8
LB
175/**
176 * cpuidle_unregister_driver - unregisters a driver
177 * @drv: the driver
178 */
179void cpuidle_unregister_driver(struct cpuidle_driver *drv)
180{
bf4d1b5d
DL
181 int cpu;
182
183 cpu = get_cpu();
4f86d3a8 184 spin_lock(&cpuidle_driver_lock);
bf4d1b5d 185 __cpuidle_unregister_driver(drv, cpu);
4f86d3a8 186 spin_unlock(&cpuidle_driver_lock);
bf4d1b5d 187 put_cpu();
4f86d3a8 188}
4f86d3a8 189EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
bf4d1b5d
DL
190#endif
191
192/**
193 * cpuidle_get_driver - return the current driver
194 */
195struct cpuidle_driver *cpuidle_get_driver(void)
196{
197 struct cpuidle_driver *drv;
198 int cpu;
199
200 cpu = get_cpu();
201 drv = __cpuidle_get_cpu_driver(cpu);
202 put_cpu();
203
204 return drv;
205}
206EXPORT_SYMBOL_GPL(cpuidle_get_driver);
207
208/**
209 * cpuidle_get_cpu_driver - return the driver tied with a cpu
210 */
211struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
212{
bf4d1b5d
DL
213 if (!dev)
214 return NULL;
215
ac34d7c8 216 return __cpuidle_get_cpu_driver(dev->cpu);
bf4d1b5d
DL
217}
218EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
6e797a07
RW
219
220struct cpuidle_driver *cpuidle_driver_ref(void)
221{
222 struct cpuidle_driver *drv;
223
224 spin_lock(&cpuidle_driver_lock);
225
13dd52f1 226 drv = cpuidle_get_driver();
42f67f2a 227 drv->refcnt++;
6e797a07
RW
228
229 spin_unlock(&cpuidle_driver_lock);
230 return drv;
231}
232
233void cpuidle_driver_unref(void)
234{
13dd52f1 235 struct cpuidle_driver *drv = cpuidle_get_driver();
42f67f2a 236
6e797a07
RW
237 spin_lock(&cpuidle_driver_lock);
238
42f67f2a
DL
239 if (drv && !WARN_ON(drv->refcnt <= 0))
240 drv->refcnt--;
6e797a07
RW
241
242 spin_unlock(&cpuidle_driver_lock);
243}