|
@@ -234,6 +234,11 @@ again:
|
|
|
goto again;
|
|
|
}
|
|
|
timer->base = new_base;
|
|
|
+ } else {
|
|
|
+ if (cpu != this_cpu && hrtimer_check_target(timer, new_base)) {
|
|
|
+ cpu = this_cpu;
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
}
|
|
|
return new_base;
|
|
|
}
|
|
@@ -569,6 +574,23 @@ hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal)
|
|
|
|
|
|
cpu_base->expires_next.tv64 = expires_next.tv64;
|
|
|
|
|
|
+ /*
|
|
|
+ * If a hang was detected in the last timer interrupt then we
|
|
|
+ * leave the hang delay active in the hardware. We want the
|
|
|
+ * system to make progress. That also prevents the following
|
|
|
+ * scenario:
|
|
|
+ * T1 expires 50ms from now
|
|
|
+ * T2 expires 5s from now
|
|
|
+ *
|
|
|
+ * T1 is removed, so this code is called and would reprogram
|
|
|
+ * the hardware to 5s from now. Any hrtimer_start after that
|
|
|
+ * will not reprogram the hardware due to hang_detected being
|
|
|
+ * set. So we'd effectivly block all timers until the T2 event
|
|
|
+ * fires.
|
|
|
+ */
|
|
|
+ if (cpu_base->hang_detected)
|
|
|
+ return;
|
|
|
+
|
|
|
if (cpu_base->expires_next.tv64 != KTIME_MAX)
|
|
|
tick_program_event(cpu_base->expires_next, 1);
|
|
|
}
|