diff options
Diffstat (limited to 'kernel/time/tick-broadcast.c')
| -rw-r--r-- | kernel/time/tick-broadcast.c | 24 | 
1 files changed, 24 insertions, 0 deletions
| diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 771d1e040303..ed58eebb4e8f 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -1148,6 +1148,30 @@ 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()) { +			struct tick_device *td = this_cpu_ptr(&tick_cpu_device); + +			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);  	} | 
