diff --git a/kernel/time/tick-broadcast-hrtimer.c b/kernel/time/tick-broadcast-hrtimer.c index b8e79f8012f3e618aa88e14a0ec66104ed9fdea8..b5a65e212df2f9a1e4b55df717a7f97652b1ed61 100644 --- a/kernel/time/tick-broadcast-hrtimer.c +++ b/kernel/time/tick-broadcast-hrtimer.c @@ -42,8 +42,6 @@ static int bc_shutdown(struct clock_event_device *evt) */ static int bc_set_next(ktime_t expires, struct clock_event_device *bc) { - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); - /* * This is called either from enter/exit idle code or from the * broadcast handler. In all cases tick_broadcast_lock is held. @@ -64,18 +62,6 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc) * hrtimer_start() can call into tracing. */ RCU_NONIDLE( { - - /* - * This can be called from CPU offline operation to move broadcast - * assignment. If tick_broadcast_force_mask is set, the CPU local - * timer device may be disabled. And hrtimer_reprogram() will not - * called if the timer is not the first expiring timer. Reprogram - * the cpu local timer device to ensure we can take over the - * broadcast duty. - */ - if (tick_check_broadcast_expired() && expires >= dev->next_event) - clockevents_program_event(dev, dev->next_event, 1); - hrtimer_start(&bctimer, expires, HRTIMER_MODE_ABS_PINNED_HARD); /* * The core tick broadcast mode expects bc->bound_on to be set diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index a9530e866e5f1b755e5798a5de68577b58a31b4d..792ef33ba4874ce484513ef3039052f2c7351d42 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -944,6 +944,7 @@ void tick_broadcast_switch_to_oneshot(void) #ifdef CONFIG_HOTPLUG_CPU void hotplug_cpu__broadcast_tick_pull(int deadcpu) { + struct tick_device *td = this_cpu_ptr(&tick_cpu_device); struct clock_event_device *bc; unsigned long flags; @@ -951,6 +952,28 @@ void hotplug_cpu__broadcast_tick_pull(int deadcpu) bc = tick_broadcast_device.evtdev; if (bc && broadcast_needs_cpu(bc, deadcpu)) { + /* + * If the broadcast force bit of the current CPU is set, + * then the current CPU has not yet reprogrammed the local + * timer device to avoid a ping-pong race. See + * ___tick_broadcast_oneshot_control(). + * + * If the broadcast device is hrtimer based then + * programming the broadcast event below does not have any + * effect because the local clockevent device is not + * running and not programmed because the broadcast event + * is not earlier than the pending event of the local clock + * event device. As a consequence all CPUs waiting for a + * broadcast event are stuck forever. + * + * Detect this condition and reprogram the cpu local timer + * device to avoid the starvation. + */ + if (tick_check_broadcast_expired()) { + cpumask_clear_cpu(smp_processor_id(), tick_broadcast_force_mask); + tick_program_event(td->evtdev->next_event, 1); + } + /* This moves the broadcast assignment to this CPU: */ clockevents_program_event(bc, bc->next_event, 1); }