Browse Source

tick/broadcast: Check for hrtimer broadcast active early

If the current cpu is the one which has the hrtimer based broadcast
queued then we better return busy immediately instead of going through
loops and hoops to figure that out.

[ Split out from a larger combo patch ]

Tested-by: Sudeep Holla <sudeep.holla@arm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Suzuki Poulose <Suzuki.Poulose@arm.com>
Cc: Lorenzo Pieralisi <Lorenzo.Pieralisi@arm.com>
Cc: Catalin Marinas <Catalin.Marinas@arm.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@kernel.org>
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1507070929360.3916@nanos
Thomas Gleixner 10 years ago
parent
commit
d5113e13a5
1 changed files with 26 additions and 10 deletions
  1. 26 10
      kernel/time/tick-broadcast.c

+ 26 - 10
kernel/time/tick-broadcast.c

@@ -705,6 +705,17 @@ int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
 	cpu = smp_processor_id();
 	cpu = smp_processor_id();
 
 
 	if (state == TICK_BROADCAST_ENTER) {
 	if (state == TICK_BROADCAST_ENTER) {
+		/*
+		 * If the current CPU owns the hrtimer broadcast
+		 * mechanism, it cannot go deep idle and we do not add
+		 * the CPU to the broadcast mask. We don't have to go
+		 * through the EXIT path as the local timer is not
+		 * shutdown.
+		 */
+		ret = broadcast_needs_cpu(bc, cpu);
+		if (ret)
+			goto out;
+
 		/*
 		/*
 		 * If the broadcast device is in periodic mode, we
 		 * If the broadcast device is in periodic mode, we
 		 * return.
 		 * return.
@@ -718,7 +729,10 @@ int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
 
 
 		if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
 		if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
 			WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
 			WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
+
+			/* Conditionally shut down the local timer. */
 			broadcast_shutdown_local(bc, dev);
 			broadcast_shutdown_local(bc, dev);
+
 			/*
 			/*
 			 * We only reprogram the broadcast timer if we
 			 * We only reprogram the broadcast timer if we
 			 * did not mark ourself in the force mask and
 			 * did not mark ourself in the force mask and
@@ -733,18 +747,20 @@ int __tick_broadcast_oneshot_control(enum tick_broadcast_state state)
 				ret = -EBUSY;
 				ret = -EBUSY;
 			} else if (dev->next_event.tv64 < bc->next_event.tv64) {
 			} else if (dev->next_event.tv64 < bc->next_event.tv64) {
 				tick_broadcast_set_event(bc, cpu, dev->next_event);
 				tick_broadcast_set_event(bc, cpu, dev->next_event);
+				/*
+				 * In case of hrtimer broadcasts the
+				 * programming might have moved the
+				 * timer to this cpu. If yes, remove
+				 * us from the broadcast mask and
+				 * return busy.
+				 */
+				ret = broadcast_needs_cpu(bc, cpu);
+				if (ret) {
+					cpumask_clear_cpu(cpu,
+						tick_broadcast_oneshot_mask);
+				}
 			}
 			}
 		}
 		}
-		/*
-		 * If the current CPU owns the hrtimer broadcast
-		 * mechanism, it cannot go deep idle and we remove the
-		 * CPU from the broadcast mask. We don't have to go
-		 * through the EXIT path as the local timer is not
-		 * shutdown.
-		 */
-		ret = broadcast_needs_cpu(bc, cpu);
-		if (ret)
-			cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
 	} else {
 	} else {
 		if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
 		if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
 			clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
 			clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);