aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle/driver.c
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2013-06-07 17:53:09 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-11 07:42:38 -0400
commit82467a5a885ddd9f80309682159da8db510e7832 (patch)
treed9a9e624e2fa4eca666d05182fc362eb8ce95830 /drivers/cpuidle/driver.c
parentbd2a337a25dd22bcd6b3fb1f99461f6991773e68 (diff)
cpuidle: simplify multiple driver support
Commit bf4d1b5 (cpuidle: support multiple drivers) introduced support for using multiple cpuidle drivers at the same time. It added a couple of new APIs to register the driver per CPU, but that led to some unnecessary code complexity related to the kernel config options deciding whether or not the multiple driver support is enabled. The code has to work as it did before when the multiple driver support is not enabled and the multiple driver support has to be compatible with the previously existing API. Remove the new API, not used by any driver in the tree yet (but needed for the HMP cpuidle drivers that will be submitted soon), and add a new cpumask pointer to the cpuidle driver structure that will point to the mask of CPUs handled by the given driver. That will allow the cpuidle_[un]register_driver() API to be used for the multiple driver support along with the cpuidle_[un]register() functions added recently. [rjw: Changelog] Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpuidle/driver.c')
-rw-r--r--drivers/cpuidle/driver.c192
1 files changed, 79 insertions, 113 deletions
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 8dfaaae94444..e75fa5472a91 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -18,167 +18,140 @@
18 18
19DEFINE_SPINLOCK(cpuidle_driver_lock); 19DEFINE_SPINLOCK(cpuidle_driver_lock);
20 20
21static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); 21#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
22static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
23 22
24static void cpuidle_setup_broadcast_timer(void *arg) 23static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
24
25static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
25{ 26{
26 int cpu = smp_processor_id(); 27 return per_cpu(cpuidle_drivers, cpu);
27 clockevents_notify((long)(arg), &cpu);
28} 28}
29 29
30static void __cpuidle_driver_init(struct cpuidle_driver *drv, int cpu) 30static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
31{ 31{
32 int i; 32 int cpu;
33
34 drv->refcnt = 0;
35 33
36 for (i = drv->state_count - 1; i >= 0 ; i--) { 34 for_each_cpu(cpu, drv->cpumask) {
37 35
38 if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP)) 36 if (drv != __cpuidle_get_cpu_driver(cpu))
39 continue; 37 continue;
40 38
41 drv->bctimer = 1; 39 per_cpu(cpuidle_drivers, cpu) = NULL;
42 on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer,
43 (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
44 break;
45 } 40 }
46} 41}
47 42
48static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) 43static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
49{ 44{
50 if (!drv || !drv->state_count) 45 int cpu;
51 return -EINVAL;
52
53 if (cpuidle_disabled())
54 return -ENODEV;
55 46
56 if (__cpuidle_get_cpu_driver(cpu)) 47 for_each_cpu(cpu, drv->cpumask) {
57 return -EBUSY;
58 48
59 __cpuidle_driver_init(drv, cpu); 49 if (__cpuidle_get_cpu_driver(cpu)) {
50 __cpuidle_unset_driver(drv);
51 return -EBUSY;
52 }
60 53
61 __cpuidle_set_cpu_driver(drv, cpu); 54 per_cpu(cpuidle_drivers, cpu) = drv;
55 }
62 56
63 return 0; 57 return 0;
64} 58}
65 59
66static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu) 60#else
67{
68 if (drv != __cpuidle_get_cpu_driver(cpu))
69 return;
70 61
71 if (!WARN_ON(drv->refcnt > 0)) 62static struct cpuidle_driver *cpuidle_curr_driver;
72 __cpuidle_set_cpu_driver(NULL, cpu);
73 63
74 if (drv->bctimer) { 64static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
75 drv->bctimer = 0; 65{
76 on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer, 66 return cpuidle_curr_driver;
77 (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
78 }
79} 67}
80 68
81#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS 69static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
70{
71 if (cpuidle_curr_driver)
72 return -EBUSY;
82 73
83static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers); 74 cpuidle_curr_driver = drv;
84 75
85static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu) 76 return 0;
86{
87 per_cpu(cpuidle_drivers, cpu) = drv;
88} 77}
89 78
90static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu) 79static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
91{ 80{
92 return per_cpu(cpuidle_drivers, cpu); 81 if (drv == cpuidle_curr_driver)
82 cpuidle_curr_driver = NULL;
93} 83}
94 84
95static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv) 85#endif
86
87static void cpuidle_setup_broadcast_timer(void *arg)
96{ 88{
97 int cpu; 89 int cpu = smp_processor_id();
98 for_each_present_cpu(cpu) 90 clockevents_notify((long)(arg), &cpu);
99 __cpuidle_unregister_driver(drv, cpu);
100} 91}
101 92
102static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv) 93static int __cpuidle_driver_init(struct cpuidle_driver *drv)
103{ 94{
104 int ret = 0; 95 int i;
105 int i, cpu;
106 96
107 for_each_present_cpu(cpu) { 97 drv->refcnt = 0;
108 ret = __cpuidle_register_driver(drv, cpu);
109 if (ret)
110 break;
111 }
112 98
113 if (ret) 99 if (!drv->cpumask)
114 for_each_present_cpu(i) { 100 drv->cpumask = (struct cpumask *)cpu_possible_mask;
115 if (i == cpu)
116 break;
117 __cpuidle_unregister_driver(drv, i);
118 }
119 101
102 for (i = drv->state_count - 1; i >= 0 ; i--) {
120 103
121 return ret; 104 if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP))
105 continue;
106
107 drv->bctimer = 1;
108 break;
109 }
110
111 return 0;
122} 112}
123 113
124int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu) 114static int __cpuidle_register_driver(struct cpuidle_driver *drv)
125{ 115{
126 int ret; 116 int ret;
127 117
128 spin_lock(&cpuidle_driver_lock); 118 if (!drv || !drv->state_count)
129 ret = __cpuidle_register_driver(drv, cpu); 119 return -EINVAL;
130 spin_unlock(&cpuidle_driver_lock);
131 120
132 return ret; 121 if (cpuidle_disabled())
133} 122 return -ENODEV;
134 123
135void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu) 124 ret = __cpuidle_driver_init(drv);
136{ 125 if (ret)
137 spin_lock(&cpuidle_driver_lock); 126 return ret;
138 __cpuidle_unregister_driver(drv, cpu);
139 spin_unlock(&cpuidle_driver_lock);
140}
141 127
142/** 128 ret = __cpuidle_set_driver(drv);
143 * cpuidle_register_driver - registers a driver 129 if (ret)
144 * @drv: the driver 130 return ret;
145 */
146int cpuidle_register_driver(struct cpuidle_driver *drv)
147{
148 int ret;
149 131
150 spin_lock(&cpuidle_driver_lock); 132 if (drv->bctimer)
151 ret = __cpuidle_register_all_cpu_driver(drv); 133 on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
152 spin_unlock(&cpuidle_driver_lock); 134 (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
153 135
154 return ret; 136 return 0;
155} 137}
156EXPORT_SYMBOL_GPL(cpuidle_register_driver);
157 138
158/** 139/**
159 * cpuidle_unregister_driver - unregisters a driver 140 * cpuidle_unregister_driver - unregisters a driver
160 * @drv: the driver 141 * @drv: the driver
161 */ 142 */
162void cpuidle_unregister_driver(struct cpuidle_driver *drv) 143static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
163{ 144{
164 spin_lock(&cpuidle_driver_lock); 145 if (WARN_ON(drv->refcnt > 0))
165 __cpuidle_unregister_all_cpu_driver(drv); 146 return;
166 spin_unlock(&cpuidle_driver_lock);
167}
168EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
169
170#else
171
172static struct cpuidle_driver *cpuidle_curr_driver;
173 147
174static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu) 148 if (drv->bctimer) {
175{ 149 drv->bctimer = 0;
176 cpuidle_curr_driver = drv; 150 on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
177} 151 (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
152 }
178 153
179static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu) 154 __cpuidle_unset_driver(drv);
180{
181 return cpuidle_curr_driver;
182} 155}
183 156
184/** 157/**
@@ -187,13 +160,11 @@ static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
187 */ 160 */
188int cpuidle_register_driver(struct cpuidle_driver *drv) 161int cpuidle_register_driver(struct cpuidle_driver *drv)
189{ 162{
190 int ret, cpu; 163 int ret;
191 164
192 cpu = get_cpu();
193 spin_lock(&cpuidle_driver_lock); 165 spin_lock(&cpuidle_driver_lock);
194 ret = __cpuidle_register_driver(drv, cpu); 166 ret = __cpuidle_register_driver(drv);
195 spin_unlock(&cpuidle_driver_lock); 167 spin_unlock(&cpuidle_driver_lock);
196 put_cpu();
197 168
198 return ret; 169 return ret;
199} 170}
@@ -205,16 +176,11 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver);
205 */ 176 */
206void cpuidle_unregister_driver(struct cpuidle_driver *drv) 177void cpuidle_unregister_driver(struct cpuidle_driver *drv)
207{ 178{
208 int cpu;
209
210 cpu = get_cpu();
211 spin_lock(&cpuidle_driver_lock); 179 spin_lock(&cpuidle_driver_lock);
212 __cpuidle_unregister_driver(drv, cpu); 180 __cpuidle_unregister_driver(drv);
213 spin_unlock(&cpuidle_driver_lock); 181 spin_unlock(&cpuidle_driver_lock);
214 put_cpu();
215} 182}
216EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); 183EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
217#endif
218 184
219/** 185/**
220 * cpuidle_get_driver - return the current driver 186 * cpuidle_get_driver - return the current driver