Diffstat (limited to 'recipes-kernel/linux/linux-toradex-rt-4.9-1.0.x/0003-timers-Forward-timer-base-before-migrating-timers.patch')
1 files changed, 88 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-toradex-rt-4.9-1.0.x/0003-timers-Forward-timer-base-before-migrating-timers.patch b/recipes-kernel/linux/linux-toradex-rt-4.9-1.0.x/0003-timers-Forward-timer-base-before-migrating-timers.patch
new file mode 100644
@@ -0,0 +1,88 @@
+From 030a2d50079f1a8c6319fa6a026c03e43c3f87f6 Mon Sep 17 00:00:00 2001
+From: Lingutla Chandrasekhar <firstname.lastname@example.org>
+Date: Thu, 18 Jan 2018 17:20:22 +0530
+Subject: [PATCH 3/3] timers: Forward timer base before migrating timers
+commit c52232a49e203a65a6e1a670cd5262f59e9364a0 upstream.
+On CPU hotunplug the enqueued timers of the unplugged CPU are migrated to a
+live CPU. This happens from the control thread which initiated the unplug.
+If the CPU on which the control thread runs came out from a longer idle
+period then the base clock of that CPU might be stale because the control
+thread runs prior to any event which forwards the clock.
+In such a case the timers from the unplugged CPU are queued on the live CPU
+based on the stale clock which can cause large delays due to increased
+granularity of the outer timer wheels which are far away from base:;clock.
+But there is a worse problem than that. The following sequence of events
+ - CPU0 timer1 is queued expires = 59969 and base->clk = 59131.
+ The timer is queued at wheel level 2, with resulting expiry time = 60032
+ (due to level granularity).
+ - CPU1 enters idle @60007, with next timer expiry @60020.
+ - CPU0 is hotplugged at @60009
+ - CPU1 exits idle and runs the control thread which migrates the
+ timers from CPU0
+ timer1 is now queued in level 0 for immediate handling in the next
+ softirq because the requested expiry time 59969 is before CPU1 base->clk
+ - CPU1 runs code which forwards the base clock which succeeds because the
+ next expiring timer. which was collected at idle entry time is still set
+ to 60020.
+ So it forwards beyond 60007 and therefore misses to expire the migrated
+ timer1. That timer gets expired when the wheel wraps around again, which
+ takes between 63 and 630ms depending on the HZ setting.
+Address both problems by invoking forward_timer_base() for the control CPUs
+timer base. All other places, which might run into a similar problem
+(mod_timer()/add_timer_on()) already invoke forward_timer_base() to avoid
+[ tglx: Massaged comment and changelog ]
+Fixes: a683f390b93f ("timers: Forward the wheel clock whenever possible")
+Co-developed-by: Neeraj Upadhyay <email@example.com>
+Signed-off-by: Neeraj Upadhyay <firstname.lastname@example.org>
+Signed-off-by: Lingutla Chandrasekhar <email@example.com>
+Signed-off-by: Thomas Gleixner <firstname.lastname@example.org>
+Cc: Anna-Maria Gleixner <email@example.com>
+Signed-off-by: Greg Kroah-Hartman <firstname.lastname@example.org>
+(cherry picked from commit 13e75c74cd69ca460778fad5ab902f0b20869267)
+ kernel/time/timer.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+diff --git a/kernel/time/timer.c b/kernel/time/timer.c
+index ec0169f49c39..00f3db2c6cca 100644
+@@ -1919,6 +1919,12 @@ int timers_dead_cpu(unsigned int cpu)
+ raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
++ * The current CPUs base clock might be stale. Update it
++ * before moving the timers over.
+ for (i = 0; i < WHEEL_SIZE; i++)