diff options
Diffstat (limited to 'kernel/time/tick-broadcast.c')
-rw-r--r-- | kernel/time/tick-broadcast.c | 70 |
1 files changed, 59 insertions, 11 deletions
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 248f80dba746..4430fa695b48 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | static struct tick_device tick_broadcast_device; | 31 | static struct tick_device tick_broadcast_device; |
32 | static cpumask_var_t tick_broadcast_mask; | 32 | static cpumask_var_t tick_broadcast_mask; |
33 | static cpumask_var_t tick_broadcast_on; | ||
33 | static cpumask_var_t tmpmask; | 34 | static cpumask_var_t tmpmask; |
34 | static DEFINE_RAW_SPINLOCK(tick_broadcast_lock); | 35 | static DEFINE_RAW_SPINLOCK(tick_broadcast_lock); |
35 | static int tick_broadcast_force; | 36 | static int tick_broadcast_force; |
@@ -140,8 +141,9 @@ static void tick_device_setup_broadcast_func(struct clock_event_device *dev) | |||
140 | */ | 141 | */ |
141 | int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) | 142 | int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) |
142 | { | 143 | { |
144 | struct clock_event_device *bc = tick_broadcast_device.evtdev; | ||
143 | unsigned long flags; | 145 | unsigned long flags; |
144 | int ret = 0; | 146 | int ret; |
145 | 147 | ||
146 | raw_spin_lock_irqsave(&tick_broadcast_lock, flags); | 148 | raw_spin_lock_irqsave(&tick_broadcast_lock, flags); |
147 | 149 | ||
@@ -155,20 +157,59 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) | |||
155 | dev->event_handler = tick_handle_periodic; | 157 | dev->event_handler = tick_handle_periodic; |
156 | tick_device_setup_broadcast_func(dev); | 158 | tick_device_setup_broadcast_func(dev); |
157 | cpumask_set_cpu(cpu, tick_broadcast_mask); | 159 | cpumask_set_cpu(cpu, tick_broadcast_mask); |
158 | tick_broadcast_start_periodic(tick_broadcast_device.evtdev); | 160 | tick_broadcast_start_periodic(bc); |
159 | ret = 1; | 161 | ret = 1; |
160 | } else { | 162 | } else { |
161 | /* | 163 | /* |
162 | * When the new device is not affected by the stop | 164 | * Clear the broadcast bit for this cpu if the |
163 | * feature and the cpu is marked in the broadcast mask | 165 | * device is not power state affected. |
164 | * then clear the broadcast bit. | ||
165 | */ | 166 | */ |
166 | if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { | 167 | if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) |
167 | int cpu = smp_processor_id(); | ||
168 | cpumask_clear_cpu(cpu, tick_broadcast_mask); | 168 | cpumask_clear_cpu(cpu, tick_broadcast_mask); |
169 | tick_broadcast_clear_oneshot(cpu); | 169 | else |
170 | } else { | ||
171 | tick_device_setup_broadcast_func(dev); | 170 | tick_device_setup_broadcast_func(dev); |
171 | |||
172 | /* | ||
173 | * Clear the broadcast bit if the CPU is not in | ||
174 | * periodic broadcast on state. | ||
175 | */ | ||
176 | if (!cpumask_test_cpu(cpu, tick_broadcast_on)) | ||
177 | cpumask_clear_cpu(cpu, tick_broadcast_mask); | ||
178 | |||
179 | switch (tick_broadcast_device.mode) { | ||
180 | case TICKDEV_MODE_ONESHOT: | ||
181 | /* | ||
182 | * If the system is in oneshot mode we can | ||
183 | * unconditionally clear the oneshot mask bit, | ||
184 | * because the CPU is running and therefore | ||
185 | * not in an idle state which causes the power | ||
186 | * state affected device to stop. Let the | ||
187 | * caller initialize the device. | ||
188 | */ | ||
189 | tick_broadcast_clear_oneshot(cpu); | ||
190 | ret = 0; | ||
191 | break; | ||
192 | |||
193 | case TICKDEV_MODE_PERIODIC: | ||
194 | /* | ||
195 | * If the system is in periodic mode, check | ||
196 | * whether the broadcast device can be | ||
197 | * switched off now. | ||
198 | */ | ||
199 | if (cpumask_empty(tick_broadcast_mask) && bc) | ||
200 | clockevents_shutdown(bc); | ||
201 | /* | ||
202 | * If we kept the cpu in the broadcast mask, | ||
203 | * tell the caller to leave the per cpu device | ||
204 | * in shutdown state. The periodic interrupt | ||
205 | * is delivered by the broadcast device. | ||
206 | */ | ||
207 | ret = cpumask_test_cpu(cpu, tick_broadcast_mask); | ||
208 | break; | ||
209 | default: | ||
210 | /* Nothing to do */ | ||
211 | ret = 0; | ||
212 | break; | ||
172 | } | 213 | } |
173 | } | 214 | } |
174 | raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); | 215 | raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags); |
@@ -298,6 +339,7 @@ static void tick_do_broadcast_on_off(unsigned long *reason) | |||
298 | switch (*reason) { | 339 | switch (*reason) { |
299 | case CLOCK_EVT_NOTIFY_BROADCAST_ON: | 340 | case CLOCK_EVT_NOTIFY_BROADCAST_ON: |
300 | case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: | 341 | case CLOCK_EVT_NOTIFY_BROADCAST_FORCE: |
342 | cpumask_set_cpu(cpu, tick_broadcast_on); | ||
301 | if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) { | 343 | if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) { |
302 | if (tick_broadcast_device.mode == | 344 | if (tick_broadcast_device.mode == |
303 | TICKDEV_MODE_PERIODIC) | 345 | TICKDEV_MODE_PERIODIC) |
@@ -307,8 +349,12 @@ static void tick_do_broadcast_on_off(unsigned long *reason) | |||
307 | tick_broadcast_force = 1; | 349 | tick_broadcast_force = 1; |
308 | break; | 350 | break; |
309 | case CLOCK_EVT_NOTIFY_BROADCAST_OFF: | 351 | case CLOCK_EVT_NOTIFY_BROADCAST_OFF: |
310 | if (!tick_broadcast_force && | 352 | if (tick_broadcast_force) |
311 | cpumask_test_and_clear_cpu(cpu, tick_broadcast_mask)) { | 353 | break; |
354 | cpumask_clear_cpu(cpu, tick_broadcast_on); | ||
355 | if (!tick_device_is_functional(dev)) | ||
356 | break; | ||
357 | if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_mask)) { | ||
312 | if (tick_broadcast_device.mode == | 358 | if (tick_broadcast_device.mode == |
313 | TICKDEV_MODE_PERIODIC) | 359 | TICKDEV_MODE_PERIODIC) |
314 | tick_setup_periodic(dev, 0); | 360 | tick_setup_periodic(dev, 0); |
@@ -366,6 +412,7 @@ void tick_shutdown_broadcast(unsigned int *cpup) | |||
366 | 412 | ||
367 | bc = tick_broadcast_device.evtdev; | 413 | bc = tick_broadcast_device.evtdev; |
368 | cpumask_clear_cpu(cpu, tick_broadcast_mask); | 414 | cpumask_clear_cpu(cpu, tick_broadcast_mask); |
415 | cpumask_clear_cpu(cpu, tick_broadcast_on); | ||
369 | 416 | ||
370 | if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) { | 417 | if (tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC) { |
371 | if (bc && cpumask_empty(tick_broadcast_mask)) | 418 | if (bc && cpumask_empty(tick_broadcast_mask)) |
@@ -821,6 +868,7 @@ bool tick_broadcast_oneshot_available(void) | |||
821 | void __init tick_broadcast_init(void) | 868 | void __init tick_broadcast_init(void) |
822 | { | 869 | { |
823 | zalloc_cpumask_var(&tick_broadcast_mask, GFP_NOWAIT); | 870 | zalloc_cpumask_var(&tick_broadcast_mask, GFP_NOWAIT); |
871 | zalloc_cpumask_var(&tick_broadcast_on, GFP_NOWAIT); | ||
824 | zalloc_cpumask_var(&tmpmask, GFP_NOWAIT); | 872 | zalloc_cpumask_var(&tmpmask, GFP_NOWAIT); |
825 | #ifdef CONFIG_TICK_ONESHOT | 873 | #ifdef CONFIG_TICK_ONESHOT |
826 | zalloc_cpumask_var(&tick_broadcast_oneshot_mask, GFP_NOWAIT); | 874 | zalloc_cpumask_var(&tick_broadcast_oneshot_mask, GFP_NOWAIT); |