aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-broadcast.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/time/tick-broadcast.c')
-rw-r--r--kernel/time/tick-broadcast.c70
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
31static struct tick_device tick_broadcast_device; 31static struct tick_device tick_broadcast_device;
32static cpumask_var_t tick_broadcast_mask; 32static cpumask_var_t tick_broadcast_mask;
33static cpumask_var_t tick_broadcast_on;
33static cpumask_var_t tmpmask; 34static cpumask_var_t tmpmask;
34static DEFINE_RAW_SPINLOCK(tick_broadcast_lock); 35static DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
35static int tick_broadcast_force; 36static int tick_broadcast_force;
@@ -140,8 +141,9 @@ static void tick_device_setup_broadcast_func(struct clock_event_device *dev)
140 */ 141 */
141int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) 142int 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)
821void __init tick_broadcast_init(void) 868void __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);