summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch')
-rw-r--r--recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch349
1 files changed, 349 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch
new file mode 100644
index 00000000..5042065c
--- /dev/null
+++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.24/0074-ntp-Fix-leap-second-hrtimer-livelock.patch
@@ -0,0 +1,349 @@
1From 19aeba1469884ed9a789b143cf73ce047663c095 Mon Sep 17 00:00:00 2001
2From: John Stultz <john.stultz@linaro.org>
3Date: Tue, 17 Jul 2012 03:05:14 -0400
4Subject: [PATCH 074/109] ntp: Fix leap-second hrtimer livelock
5
6This is a backport of 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
7
8This should have been backported when it was commited, but I
9mistook the problem as requiring the ntp_lock changes
10that landed in 3.4 in order for it to occur.
11
12Unfortunately the same issue can happen (with only one cpu)
13as follows:
14do_adjtimex()
15 write_seqlock_irq(&xtime_lock);
16 process_adjtimex_modes()
17 process_adj_status()
18 ntp_start_leap_timer()
19 hrtimer_start()
20 hrtimer_reprogram()
21 tick_program_event()
22 clockevents_program_event()
23 ktime_get()
24 seq = req_seqbegin(xtime_lock); [DEADLOCK]
25
26This deadlock will no always occur, as it requires the
27leap_timer to force a hrtimer_reprogram which only happens
28if its set and there's no sooner timer to expire.
29
30NOTE: This patch, being faithful to the original commit,
31introduces a bug (we don't update wall_to_monotonic),
32which will be resovled by backporting a following fix.
33
34Original commit message below:
35
36Since commit 7dffa3c673fbcf835cd7be80bb4aec8ad3f51168 the ntp
37subsystem has used an hrtimer for triggering the leapsecond
38adjustment. However, this can cause a potential livelock.
39
40Thomas diagnosed this as the following pattern:
41CPU 0 CPU 1
42do_adjtimex()
43 spin_lock_irq(&ntp_lock);
44 process_adjtimex_modes(); timer_interrupt()
45 process_adj_status(); do_timer()
46 ntp_start_leap_timer(); write_lock(&xtime_lock);
47 hrtimer_start(); update_wall_time();
48 hrtimer_reprogram(); ntp_tick_length()
49 tick_program_event() spin_lock(&ntp_lock);
50 clockevents_program_event()
51 ktime_get()
52 seq = req_seqbegin(xtime_lock);
53
54This patch tries to avoid the problem by reverting back to not using
55an hrtimer to inject leapseconds, and instead we handle the leapsecond
56processing in the second_overflow() function.
57
58The downside to this change is that on systems that support highres
59timers, the leap second processing will occur on a HZ tick boundary,
60(ie: ~1-10ms, depending on HZ) after the leap second instead of
61possibly sooner (~34us in my tests w/ x86_64 lapic).
62
63This patch applies on top of tip/timers/core.
64
65CC: Sasha Levin <levinsasha928@gmail.com>
66CC: Thomas Gleixner <tglx@linutronix.de>
67Reported-by: Sasha Levin <levinsasha928@gmail.com>
68Diagnoised-by: Thomas Gleixner <tglx@linutronix.de>
69Tested-by: Sasha Levin <levinsasha928@gmail.com>
70Cc: Prarit Bhargava <prarit@redhat.com>
71Cc: Thomas Gleixner <tglx@linutronix.de>
72Cc: Linux Kernel <linux-kernel@vger.kernel.org>
73Signed-off-by: John Stultz <john.stultz@linaro.org>
74Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
75---
76 include/linux/timex.h | 2 +-
77 kernel/time/ntp.c | 122 +++++++++++++++------------------------------
78 kernel/time/timekeeping.c | 18 +++----
79 3 files changed, 48 insertions(+), 94 deletions(-)
80
81diff --git a/include/linux/timex.h b/include/linux/timex.h
82index aa60fe7..08e90fb 100644
83--- a/include/linux/timex.h
84+++ b/include/linux/timex.h
85@@ -266,7 +266,7 @@ static inline int ntp_synced(void)
86 /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
87 extern u64 tick_length;
88
89-extern void second_overflow(void);
90+extern int second_overflow(unsigned long secs);
91 extern void update_ntp_one_tick(void);
92 extern int do_adjtimex(struct timex *);
93 extern void hardpps(const struct timespec *, const struct timespec *);
94diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
95index 4b85a7a..4508f7f 100644
96--- a/kernel/time/ntp.c
97+++ b/kernel/time/ntp.c
98@@ -31,8 +31,6 @@ unsigned long tick_nsec;
99 u64 tick_length;
100 static u64 tick_length_base;
101
102-static struct hrtimer leap_timer;
103-
104 #define MAX_TICKADJ 500LL /* usecs */
105 #define MAX_TICKADJ_SCALED \
106 (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
107@@ -350,60 +348,60 @@ void ntp_clear(void)
108 }
109
110 /*
111- * Leap second processing. If in leap-insert state at the end of the
112- * day, the system clock is set back one second; if in leap-delete
113- * state, the system clock is set ahead one second.
114+ * this routine handles the overflow of the microsecond field
115+ *
116+ * The tricky bits of code to handle the accurate clock support
117+ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
118+ * They were originally developed for SUN and DEC kernels.
119+ * All the kudos should go to Dave for this stuff.
120+ *
121+ * Also handles leap second processing, and returns leap offset
122 */
123-static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
124+int second_overflow(unsigned long secs)
125 {
126- enum hrtimer_restart res = HRTIMER_NORESTART;
127-
128- write_seqlock(&xtime_lock);
129+ int leap = 0;
130+ s64 delta;
131
132+ /*
133+ * Leap second processing. If in leap-insert state at the end of the
134+ * day, the system clock is set back one second; if in leap-delete
135+ * state, the system clock is set ahead one second.
136+ */
137 switch (time_state) {
138 case TIME_OK:
139+ if (time_status & STA_INS)
140+ time_state = TIME_INS;
141+ else if (time_status & STA_DEL)
142+ time_state = TIME_DEL;
143 break;
144 case TIME_INS:
145- timekeeping_leap_insert(-1);
146- time_state = TIME_OOP;
147- printk(KERN_NOTICE
148- "Clock: inserting leap second 23:59:60 UTC\n");
149- hrtimer_add_expires_ns(&leap_timer, NSEC_PER_SEC);
150- res = HRTIMER_RESTART;
151+ if (secs % 86400 == 0) {
152+ leap = -1;
153+ time_state = TIME_OOP;
154+ printk(KERN_NOTICE
155+ "Clock: inserting leap second 23:59:60 UTC\n");
156+ }
157 break;
158 case TIME_DEL:
159- timekeeping_leap_insert(1);
160- time_tai--;
161- time_state = TIME_WAIT;
162- printk(KERN_NOTICE
163- "Clock: deleting leap second 23:59:59 UTC\n");
164+ if ((secs + 1) % 86400 == 0) {
165+ leap = 1;
166+ time_tai--;
167+ time_state = TIME_WAIT;
168+ printk(KERN_NOTICE
169+ "Clock: deleting leap second 23:59:59 UTC\n");
170+ }
171 break;
172 case TIME_OOP:
173 time_tai++;
174 time_state = TIME_WAIT;
175- /* fall through */
176+ break;
177+
178 case TIME_WAIT:
179 if (!(time_status & (STA_INS | STA_DEL)))
180 time_state = TIME_OK;
181 break;
182 }
183
184- write_sequnlock(&xtime_lock);
185-
186- return res;
187-}
188-
189-/*
190- * this routine handles the overflow of the microsecond field
191- *
192- * The tricky bits of code to handle the accurate clock support
193- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
194- * They were originally developed for SUN and DEC kernels.
195- * All the kudos should go to Dave for this stuff.
196- */
197-void second_overflow(void)
198-{
199- s64 delta;
200
201 /* Bump the maxerror field */
202 time_maxerror += MAXFREQ / NSEC_PER_USEC;
203@@ -423,23 +421,25 @@ void second_overflow(void)
204 pps_dec_valid();
205
206 if (!time_adjust)
207- return;
208+ goto out;
209
210 if (time_adjust > MAX_TICKADJ) {
211 time_adjust -= MAX_TICKADJ;
212 tick_length += MAX_TICKADJ_SCALED;
213- return;
214+ goto out;
215 }
216
217 if (time_adjust < -MAX_TICKADJ) {
218 time_adjust += MAX_TICKADJ;
219 tick_length -= MAX_TICKADJ_SCALED;
220- return;
221+ goto out;
222 }
223
224 tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
225 << NTP_SCALE_SHIFT;
226 time_adjust = 0;
227+out:
228+ return leap;
229 }
230
231 #ifdef CONFIG_GENERIC_CMOS_UPDATE
232@@ -501,27 +501,6 @@ static void notify_cmos_timer(void)
233 static inline void notify_cmos_timer(void) { }
234 #endif
235
236-/*
237- * Start the leap seconds timer:
238- */
239-static inline void ntp_start_leap_timer(struct timespec *ts)
240-{
241- long now = ts->tv_sec;
242-
243- if (time_status & STA_INS) {
244- time_state = TIME_INS;
245- now += 86400 - now % 86400;
246- hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS);
247-
248- return;
249- }
250-
251- if (time_status & STA_DEL) {
252- time_state = TIME_DEL;
253- now += 86400 - (now + 1) % 86400;
254- hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS);
255- }
256-}
257
258 /*
259 * Propagate a new txc->status value into the NTP state:
260@@ -546,22 +525,6 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
261 time_status &= STA_RONLY;
262 time_status |= txc->status & ~STA_RONLY;
263
264- switch (time_state) {
265- case TIME_OK:
266- ntp_start_leap_timer(ts);
267- break;
268- case TIME_INS:
269- case TIME_DEL:
270- time_state = TIME_OK;
271- ntp_start_leap_timer(ts);
272- case TIME_WAIT:
273- if (!(time_status & (STA_INS | STA_DEL)))
274- time_state = TIME_OK;
275- break;
276- case TIME_OOP:
277- hrtimer_restart(&leap_timer);
278- break;
279- }
280 }
281 /*
282 * Called with the xtime lock held, so we can access and modify
283@@ -643,9 +606,6 @@ int do_adjtimex(struct timex *txc)
284 (txc->tick < 900000/USER_HZ ||
285 txc->tick > 1100000/USER_HZ))
286 return -EINVAL;
287-
288- if (txc->modes & ADJ_STATUS && time_state != TIME_OK)
289- hrtimer_cancel(&leap_timer);
290 }
291
292 if (txc->modes & ADJ_SETOFFSET) {
293@@ -967,6 +927,4 @@ __setup("ntp_tick_adj=", ntp_tick_adj_setup);
294 void __init ntp_init(void)
295 {
296 ntp_clear();
297- hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
298- leap_timer.function = ntp_leap_second;
299 }
300diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
301index 2378413..4780a7d 100644
302--- a/kernel/time/timekeeping.c
303+++ b/kernel/time/timekeeping.c
304@@ -169,15 +169,6 @@ static struct timespec raw_time;
305 /* flag for if timekeeping is suspended */
306 int __read_mostly timekeeping_suspended;
307
308-/* must hold xtime_lock */
309-void timekeeping_leap_insert(int leapsecond)
310-{
311- xtime.tv_sec += leapsecond;
312- wall_to_monotonic.tv_sec -= leapsecond;
313- update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
314- timekeeper.mult);
315-}
316-
317 /**
318 * timekeeping_forward_now - update clock to the current time
319 *
320@@ -942,9 +933,11 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
321
322 timekeeper.xtime_nsec += timekeeper.xtime_interval << shift;
323 while (timekeeper.xtime_nsec >= nsecps) {
324+ int leap;
325 timekeeper.xtime_nsec -= nsecps;
326 xtime.tv_sec++;
327- second_overflow();
328+ leap = second_overflow(xtime.tv_sec);
329+ xtime.tv_sec += leap;
330 }
331
332 /* Accumulate raw time */
333@@ -1050,9 +1043,12 @@ static void update_wall_time(void)
334 * xtime.tv_nsec isn't larger then NSEC_PER_SEC
335 */
336 if (unlikely(xtime.tv_nsec >= NSEC_PER_SEC)) {
337+ int leap;
338 xtime.tv_nsec -= NSEC_PER_SEC;
339 xtime.tv_sec++;
340- second_overflow();
341+ leap = second_overflow(xtime.tv_sec);
342+ xtime.tv_sec += leap;
343+
344 }
345
346 /* check to see if there is a new clocksource to use */
347--
3481.7.7.6
349