aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/tick-broadcast.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2013-07-01 16:14:10 -0400
committerThomas Gleixner <tglx@linutronix.de>2013-07-02 08:26:45 -0400
commit07bd1172902e782f288e4d44b1fde7dec0f08b6f (patch)
treef5d0913e170ce7efff96512a90f310b3f43530f9 /kernel/time/tick-broadcast.c
parent1f73a9806bdd07a5106409bbcab3884078bd34fe (diff)
tick: Sanitize broadcast control logic
The recent implementation of a generic dummy timer resulted in a different registration order of per cpu local timers which made the broadcast control logic go belly up. If the dummy timer is the first clock event device which is registered for a CPU, then it is installed, the broadcast timer is initialized and the CPU is marked as broadcast target. If a real clock event device is installed after that, we can fail to take the CPU out of the broadcast mask. In the worst case we end up with two periodic timer events firing for the same CPU. One from the per cpu hardware device and one from the broadcast. Now the problem is that we have no way to distinguish whether the system is in a state which makes broadcasting necessary or the broadcast bit was set due to the nonfunctional dummy timer installment. To solve this we need to keep track of the system state seperately and provide a more detailed decision logic whether we keep the CPU in broadcast mode or not. The old decision logic only clears the broadcast mode, if the newly installed clock event device is not affected by power states. The new logic clears the broadcast mode if one of the following is true: - The new device is not affected by power states. - The system is not in a power state affected mode - The system has switched to oneshot mode. The oneshot broadcast is controlled from the deep idle state. The CPU is not in idle at this point, so it's safe to remove it from the mask. If we clear the broadcast bit for the CPU when a new device is installed, we also shutdown the broadcast device when this was the last CPU in the broadcast mask. If the broadcast bit is kept, then we leave the new device in shutdown state and rely on the broadcast to deliver the timer interrupts via the broadcast ipis. Reported-and-tested-by: Stehle Vincent-B46079 <B46079@freescale.com> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Cc: John Stultz <john.stultz@linaro.org>, Cc: Mark Rutland <mark.rutland@arm.com> Link: http://lkml.kernel.org/r/alpine.DEB.2.02.1307012153060.4013@ionos.tec.linutronix.de Cc: stable@vger.kernel.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
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);