mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC PATCH v2] timekeeper latch synchronization
@ 2013-09-14 19:47 Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 1/7] Move ntp variables into struct timekeeper_ntp Mathieu Desnoyers
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:47 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel

Hi,

Here is my timekeeper latch synchronization series update, still as RFC.
It now passes the timetests provided by John Stultz
(https://github.com/johnstultz-work/timetests.git). See the changelog of
"Introduce timekeeper latch synchronization" to get a clear picture of
all the goodness introduced by this scheme. ;-)

Comments are welcome,

Thanks!

Mathieu


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/7] Move ntp variables into struct timekeeper_ntp
  2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
@ 2013-09-14 19:47 ` Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 2/7] Move PPS variables into struct timekeeper_pps Mathieu Desnoyers
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:47 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel
  Cc: Mathieu Desnoyers

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 include/linux/timekeeper_internal.h |   47 ++++++
 kernel/time/ntp.c                   |  318 +++++++++++++++--------------------
 2 files changed, 187 insertions(+), 178 deletions(-)

diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index c1825eb..eab26e0 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -10,6 +10,53 @@
 #include <linux/jiffies.h>
 #include <linux/time.h>
 
+/* structure holding internal NTP timekeeping values. */
+struct timekeeper_ntp {
+	/* USER_HZ period (usecs): */
+	unsigned long		tick_usec;
+
+	/* SHIFTED_HZ period (nsecs): */
+	unsigned long		tick_nsec;
+
+	u64			tick_length;
+	u64			tick_length_base;
+
+	/* phase-lock loop variables */
+
+	/*
+	 * clock synchronization status
+	 *
+	 * (TIME_ERROR prevents overwriting the CMOS clock)
+	 */
+	int			time_state;
+
+	/* clock status bits: */
+	int			time_status;
+
+	/* time adjustment (nsecs): */
+	s64			time_offset;
+
+	/* pll time constant: */
+	long			time_constant;
+
+	/* maximum error (usecs): */
+	long			time_maxerror;
+
+	/* estimated error (usecs): */
+	long			time_esterror;
+
+	/* frequency offset (scaled nsecs/secs): */
+	s64			time_freq;
+
+	/* time at last adjustment (secs): */
+	long			time_reftime;
+
+	long			time_adjust;
+
+	/* constant (boot-param configurable) NTP tick adjustment (upscaled) */
+	s64			ntp_tick_adj;
+};
+
 /* Structure holding internal timekeeping values. */
 struct timekeeper {
 	/* Current clocksource used for timekeeping. */
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index bb22151..983c212 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -16,66 +16,23 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
+#include <linux/timekeeper_internal.h>
 
 #include "tick-internal.h"
 #include "ntp_internal.h"
 
-/*
- * NTP timekeeping variables:
- *
- * Note: All of the NTP state is protected by the timekeeping locks.
- */
-
-
-/* USER_HZ period (usecs): */
-unsigned long			tick_usec = TICK_USEC;
-
-/* SHIFTED_HZ period (nsecs): */
-unsigned long			tick_nsec;
-
-static u64			tick_length;
-static u64			tick_length_base;
-
 #define MAX_TICKADJ		500LL		/* usecs */
 #define MAX_TICKADJ_SCALED \
 	(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
 
-/*
- * phase-lock loop variables
- */
-
-/*
- * clock synchronization status
- *
- * (TIME_ERROR prevents overwriting the CMOS clock)
- */
-static int			time_state = TIME_OK;
-
-/* clock status bits:							*/
-static int			time_status = STA_UNSYNC;
-
-/* time adjustment (nsecs):						*/
-static s64			time_offset;
-
-/* pll time constant:							*/
-static long			time_constant = 2;
-
-/* maximum error (usecs):						*/
-static long			time_maxerror = NTP_PHASE_LIMIT;
-
-/* estimated error (usecs):						*/
-static long			time_esterror = NTP_PHASE_LIMIT;
-
-/* frequency offset (scaled nsecs/secs):				*/
-static s64			time_freq;
-
-/* time at last adjustment (secs):					*/
-static long			time_reftime;
-
-static long			time_adjust;
-
-/* constant (boot-param configurable) NTP tick adjustment (upscaled)	*/
-static s64			ntp_tick_adj;
+static struct timekeeper_ntp tk_ntp = {
+	.tick_usec = TICK_USEC,
+	.time_state = TIME_OK,
+	.time_status = STA_UNSYNC,
+	.time_constant = 2,
+	.time_maxerror = NTP_PHASE_LIMIT,
+	.time_esterror = NTP_PHASE_LIMIT,
+};
 
 #ifdef CONFIG_NTP_PPS
 
@@ -116,10 +73,11 @@ static long pps_errcnt;		/* calibration errors */
  */
 static inline s64 ntp_offset_chunk(s64 offset)
 {
-	if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)
+	if (tk_ntp.time_status & STA_PPSTIME
+			&& tk_ntp.time_status & STA_PPSSIGNAL)
 		return offset;
 	else
-		return shift_right(offset, SHIFT_PLL + time_constant);
+		return shift_right(offset, SHIFT_PLL + tk_ntp.time_constant);
 }
 
 static inline void pps_reset_freq_interval(void)
@@ -152,7 +110,7 @@ static inline void pps_dec_valid(void)
 	if (pps_valid > 0)
 		pps_valid--;
 	else {
-		time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
+		tk_ntp.time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
 				 STA_PPSWANDER | STA_PPSERROR);
 		pps_clear();
 	}
@@ -165,21 +123,21 @@ static inline void pps_set_freq(s64 freq)
 
 static inline int is_error_status(int status)
 {
-	return (time_status & (STA_UNSYNC|STA_CLOCKERR))
+	return (tk_ntp.time_status & (STA_UNSYNC|STA_CLOCKERR))
 		/* PPS signal lost when either PPS time or
 		 * PPS frequency synchronization requested
 		 */
-		|| ((time_status & (STA_PPSFREQ|STA_PPSTIME))
-			&& !(time_status & STA_PPSSIGNAL))
+		|| ((tk_ntp.time_status & (STA_PPSFREQ|STA_PPSTIME))
+			&& !(tk_ntp.time_status & STA_PPSSIGNAL))
 		/* PPS jitter exceeded when
 		 * PPS time synchronization requested */
-		|| ((time_status & (STA_PPSTIME|STA_PPSJITTER))
+		|| ((tk_ntp.time_status & (STA_PPSTIME|STA_PPSJITTER))
 			== (STA_PPSTIME|STA_PPSJITTER))
 		/* PPS wander exceeded or calibration error when
 		 * PPS frequency synchronization requested
 		 */
-		|| ((time_status & STA_PPSFREQ)
-			&& (time_status & (STA_PPSWANDER|STA_PPSERROR)));
+		|| ((tk_ntp.time_status & STA_PPSFREQ)
+			&& (tk_ntp.time_status & (STA_PPSWANDER|STA_PPSERROR)));
 }
 
 static inline void pps_fill_timex(struct timex *txc)
@@ -187,7 +145,7 @@ static inline void pps_fill_timex(struct timex *txc)
 	txc->ppsfreq	   = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) *
 					 PPM_SCALE_INV, NTP_SCALE_SHIFT);
 	txc->jitter	   = pps_jitter;
-	if (!(time_status & STA_NANO))
+	if (!(tk_ntp.time_status & STA_NANO))
 		txc->jitter /= NSEC_PER_USEC;
 	txc->shift	   = pps_shift;
 	txc->stabil	   = pps_stabil;
@@ -201,7 +159,7 @@ static inline void pps_fill_timex(struct timex *txc)
 
 static inline s64 ntp_offset_chunk(s64 offset)
 {
-	return shift_right(offset, SHIFT_PLL + time_constant);
+	return shift_right(offset, SHIFT_PLL + tk_ntp.time_constant);
 }
 
 static inline void pps_reset_freq_interval(void) {}
@@ -236,7 +194,7 @@ static inline void pps_fill_timex(struct timex *txc)
  */
 static inline int ntp_synced(void)
 {
-	return !(time_status & STA_UNSYNC);
+	return !(tk_ntp.time_status & STA_UNSYNC);
 }
 
 
@@ -245,42 +203,42 @@ static inline int ntp_synced(void)
  */
 
 /*
- * Update (tick_length, tick_length_base, tick_nsec), based
- * on (tick_usec, ntp_tick_adj, time_freq):
+ * Update (tk_ntp.tick_length, tk_ntp.tick_length_base, tk_ntp.tick_nsec),
+ * based on (tk_ntp.tick_usec, tk_ntp.ntp_tick_adj, tk_ntp.time_freq):
  */
 static void ntp_update_frequency(void)
 {
 	u64 second_length;
 	u64 new_base;
 
-	second_length		 = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)
+	second_length = (u64)(tk_ntp.tick_usec * NSEC_PER_USEC * USER_HZ)
 						<< NTP_SCALE_SHIFT;
 
-	second_length		+= ntp_tick_adj;
-	second_length		+= time_freq;
+	second_length += tk_ntp.ntp_tick_adj;
+	second_length += tk_ntp.time_freq;
 
-	tick_nsec		 = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
-	new_base		 = div_u64(second_length, NTP_INTERVAL_FREQ);
+	tk_ntp.tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
+	new_base = div_u64(second_length, NTP_INTERVAL_FREQ);
 
 	/*
 	 * Don't wait for the next second_overflow, apply
 	 * the change to the tick length immediately:
 	 */
-	tick_length		+= new_base - tick_length_base;
-	tick_length_base	 = new_base;
+	tk_ntp.tick_length += new_base - tk_ntp.tick_length_base;
+	tk_ntp.tick_length_base = new_base;
 }
 
 static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
 {
-	time_status &= ~STA_MODE;
+	tk_ntp.time_status &= ~STA_MODE;
 
 	if (secs < MINSEC)
 		return 0;
 
-	if (!(time_status & STA_FLL) && (secs <= MAXSEC))
+	if (!(tk_ntp.time_status & STA_FLL) && (secs <= MAXSEC))
 		return 0;
 
-	time_status |= STA_MODE;
+	tk_ntp.time_status |= STA_MODE;
 
 	return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
 }
@@ -291,10 +249,10 @@ static void ntp_update_offset(long offset)
 	s64 offset64;
 	long secs;
 
-	if (!(time_status & STA_PLL))
+	if (!(tk_ntp.time_status & STA_PLL))
 		return;
 
-	if (!(time_status & STA_NANO))
+	if (!(tk_ntp.time_status & STA_NANO))
 		offset *= NSEC_PER_USEC;
 
 	/*
@@ -308,11 +266,11 @@ static void ntp_update_offset(long offset)
 	 * Select how the frequency is to be controlled
 	 * and in which mode (PLL or FLL).
 	 */
-	secs = get_seconds() - time_reftime;
-	if (unlikely(time_status & STA_FREQHOLD))
+	secs = get_seconds() - tk_ntp.time_reftime;
+	if (unlikely(tk_ntp.time_status & STA_FREQHOLD))
 		secs = 0;
 
-	time_reftime = get_seconds();
+	tk_ntp.time_reftime = get_seconds();
 
 	offset64    = offset;
 	freq_adj    = ntp_update_offset_fll(offset64, secs);
@@ -322,17 +280,18 @@ static void ntp_update_offset(long offset)
 	 * sampling rate (e.g. intermittent network connection)
 	 * to avoid instability.
 	 */
-	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + time_constant)))
-		secs = 1 << (SHIFT_PLL + 1 + time_constant);
+	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + tk_ntp.time_constant)))
+		secs = 1 << (SHIFT_PLL + 1 + tk_ntp.time_constant);
 
 	freq_adj    += (offset64 * secs) <<
-			(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant));
+		(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + tk_ntp.time_constant));
 
-	freq_adj    = min(freq_adj + time_freq, MAXFREQ_SCALED);
+	freq_adj    = min(freq_adj + tk_ntp.time_freq, MAXFREQ_SCALED);
 
-	time_freq   = max(freq_adj, -MAXFREQ_SCALED);
+	tk_ntp.time_freq   = max(freq_adj, -MAXFREQ_SCALED);
 
-	time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
+	tk_ntp.time_offset = div_s64(offset64 << NTP_SCALE_SHIFT,
+		NTP_INTERVAL_FREQ);
 }
 
 /**
@@ -340,15 +299,15 @@ static void ntp_update_offset(long offset)
  */
 void ntp_clear(void)
 {
-	time_adjust	= 0;		/* stop active adjtime() */
-	time_status	|= STA_UNSYNC;
-	time_maxerror	= NTP_PHASE_LIMIT;
-	time_esterror	= NTP_PHASE_LIMIT;
+	tk_ntp.time_adjust	= 0;		/* stop active adjtime() */
+	tk_ntp.time_status	|= STA_UNSYNC;
+	tk_ntp.time_maxerror	= NTP_PHASE_LIMIT;
+	tk_ntp.time_esterror	= NTP_PHASE_LIMIT;
 
 	ntp_update_frequency();
 
-	tick_length	= tick_length_base;
-	time_offset	= 0;
+	tk_ntp.tick_length	= tk_ntp.tick_length_base;
+	tk_ntp.time_offset	= 0;
 
 	/* Clear PPS state variables */
 	pps_clear();
@@ -357,7 +316,7 @@ void ntp_clear(void)
 
 u64 ntp_tick_length(void)
 {
-	return tick_length;
+	return tk_ntp.tick_length;
 }
 
 
@@ -381,79 +340,80 @@ int second_overflow(unsigned long secs)
 	 * day, the system clock is set back one second; if in leap-delete
 	 * state, the system clock is set ahead one second.
 	 */
-	switch (time_state) {
+	switch (tk_ntp.time_state) {
 	case TIME_OK:
-		if (time_status & STA_INS)
-			time_state = TIME_INS;
-		else if (time_status & STA_DEL)
-			time_state = TIME_DEL;
+		if (tk_ntp.time_status & STA_INS)
+			tk_ntp.time_state = TIME_INS;
+		else if (tk_ntp.time_status & STA_DEL)
+			tk_ntp.time_state = TIME_DEL;
 		break;
 	case TIME_INS:
-		if (!(time_status & STA_INS))
-			time_state = TIME_OK;
+		if (!(tk_ntp.time_status & STA_INS))
+			tk_ntp.time_state = TIME_OK;
 		else if (secs % 86400 == 0) {
 			leap = -1;
-			time_state = TIME_OOP;
+			tk_ntp.time_state = TIME_OOP;
 			printk(KERN_NOTICE
 				"Clock: inserting leap second 23:59:60 UTC\n");
 		}
 		break;
 	case TIME_DEL:
-		if (!(time_status & STA_DEL))
-			time_state = TIME_OK;
+		if (!(tk_ntp.time_status & STA_DEL))
+			tk_ntp.time_state = TIME_OK;
 		else if ((secs + 1) % 86400 == 0) {
 			leap = 1;
-			time_state = TIME_WAIT;
+			tk_ntp.time_state = TIME_WAIT;
 			printk(KERN_NOTICE
 				"Clock: deleting leap second 23:59:59 UTC\n");
 		}
 		break;
 	case TIME_OOP:
-		time_state = TIME_WAIT;
+		tk_ntp.time_state = TIME_WAIT;
 		break;
 
 	case TIME_WAIT:
-		if (!(time_status & (STA_INS | STA_DEL)))
-			time_state = TIME_OK;
+		if (!(tk_ntp.time_status & (STA_INS | STA_DEL)))
+			tk_ntp.time_state = TIME_OK;
 		break;
 	}
 
 
 	/* Bump the maxerror field */
-	time_maxerror += MAXFREQ / NSEC_PER_USEC;
-	if (time_maxerror > NTP_PHASE_LIMIT) {
-		time_maxerror = NTP_PHASE_LIMIT;
-		time_status |= STA_UNSYNC;
+	tk_ntp.time_maxerror += MAXFREQ / NSEC_PER_USEC;
+	if (tk_ntp.time_maxerror > NTP_PHASE_LIMIT) {
+		tk_ntp.time_maxerror = NTP_PHASE_LIMIT;
+		tk_ntp.time_status |= STA_UNSYNC;
 	}
 
 	/* Compute the phase adjustment for the next second */
-	tick_length	 = tick_length_base;
+	tk_ntp.tick_length = tk_ntp.tick_length_base;
 
-	delta		 = ntp_offset_chunk(time_offset);
-	time_offset	-= delta;
-	tick_length	+= delta;
+	delta = ntp_offset_chunk(tk_ntp.time_offset);
+	tk_ntp.time_offset -= delta;
+	tk_ntp.tick_length += delta;
 
 	/* Check PPS signal */
 	pps_dec_valid();
 
-	if (!time_adjust)
+	if (!tk_ntp.time_adjust)
 		goto out;
 
-	if (time_adjust > MAX_TICKADJ) {
-		time_adjust -= MAX_TICKADJ;
-		tick_length += MAX_TICKADJ_SCALED;
+	if (tk_ntp.time_adjust > MAX_TICKADJ) {
+		tk_ntp.time_adjust -= MAX_TICKADJ;
+		tk_ntp.tick_length += MAX_TICKADJ_SCALED;
 		goto out;
 	}
 
-	if (time_adjust < -MAX_TICKADJ) {
-		time_adjust += MAX_TICKADJ;
-		tick_length -= MAX_TICKADJ_SCALED;
+	if (tk_ntp.time_adjust < -MAX_TICKADJ) {
+		tk_ntp.time_adjust += MAX_TICKADJ;
+		tk_ntp.tick_length -= MAX_TICKADJ_SCALED;
 		goto out;
 	}
 
-	tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
+	tk_ntp.tick_length +=
+		(s64)(tk_ntp.time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
 							 << NTP_SCALE_SHIFT;
-	time_adjust = 0;
+	tk_ntp.time_adjust = 0;
 
 out:
 	return leap;
@@ -485,7 +445,7 @@ static void sync_cmos_clock(struct work_struct *work)
 	}
 
 	getnstimeofday(&now);
-	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2) {
+	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tk_ntp.tick_nsec / 2) {
 		struct timespec adjust = now;
 
 		fail = -ENODEV;
@@ -531,9 +491,9 @@ void ntp_notify_cmos_timer(void) { }
  */
 static inline void process_adj_status(struct timex *txc, struct timespec *ts)
 {
-	if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {
-		time_state = TIME_OK;
-		time_status = STA_UNSYNC;
+	if ((tk_ntp.time_status & STA_PLL) && !(txc->status & STA_PLL)) {
+		tk_ntp.time_state = TIME_OK;
+		tk_ntp.time_status = STA_UNSYNC;
 		/* restart PPS frequency calibration */
 		pps_reset_freq_interval();
 	}
@@ -542,12 +502,12 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
 	 * If we turn on PLL adjustments then reset the
 	 * reference time to current time.
 	 */
-	if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
-		time_reftime = get_seconds();
+	if (!(tk_ntp.time_status & STA_PLL) && (txc->status & STA_PLL))
+		tk_ntp.time_reftime = get_seconds();
 
 	/* only set allowed bits */
-	time_status &= STA_RONLY;
-	time_status |= txc->status & ~STA_RONLY;
+	tk_ntp.time_status &= STA_RONLY;
+	tk_ntp.time_status |= txc->status & ~STA_RONLY;
 }
 
 
@@ -559,31 +519,31 @@ static inline void process_adjtimex_modes(struct timex *txc,
 		process_adj_status(txc, ts);
 
 	if (txc->modes & ADJ_NANO)
-		time_status |= STA_NANO;
+		tk_ntp.time_status |= STA_NANO;
 
 	if (txc->modes & ADJ_MICRO)
-		time_status &= ~STA_NANO;
+		tk_ntp.time_status &= ~STA_NANO;
 
 	if (txc->modes & ADJ_FREQUENCY) {
-		time_freq = txc->freq * PPM_SCALE;
-		time_freq = min(time_freq, MAXFREQ_SCALED);
-		time_freq = max(time_freq, -MAXFREQ_SCALED);
+		tk_ntp.time_freq = txc->freq * PPM_SCALE;
+		tk_ntp.time_freq = min(tk_ntp.time_freq, MAXFREQ_SCALED);
+		tk_ntp.time_freq = max(tk_ntp.time_freq, -MAXFREQ_SCALED);
 		/* update pps_freq */
-		pps_set_freq(time_freq);
+		pps_set_freq(tk_ntp.time_freq);
 	}
 
 	if (txc->modes & ADJ_MAXERROR)
-		time_maxerror = txc->maxerror;
+		tk_ntp.time_maxerror = txc->maxerror;
 
 	if (txc->modes & ADJ_ESTERROR)
-		time_esterror = txc->esterror;
+		tk_ntp.time_esterror = txc->esterror;
 
 	if (txc->modes & ADJ_TIMECONST) {
-		time_constant = txc->constant;
-		if (!(time_status & STA_NANO))
-			time_constant += 4;
-		time_constant = min(time_constant, (long)MAXTC);
-		time_constant = max(time_constant, 0l);
+		tk_ntp.time_constant = txc->constant;
+		if (!(tk_ntp.time_status & STA_NANO))
+			tk_ntp.time_constant += 4;
+		tk_ntp.time_constant = min(tk_ntp.time_constant, (long)MAXTC);
+		tk_ntp.time_constant = max(tk_ntp.time_constant, 0l);
 	}
 
 	if (txc->modes & ADJ_TAI && txc->constant > 0)
@@ -593,7 +553,7 @@ static inline void process_adjtimex_modes(struct timex *txc,
 		ntp_update_offset(txc->offset);
 
 	if (txc->modes & ADJ_TICK)
-		tick_usec = txc->tick;
+		tk_ntp.tick_usec = txc->tick;
 
 	if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
 		ntp_update_frequency();
@@ -643,11 +603,11 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
 	int result;
 
 	if (txc->modes & ADJ_ADJTIME) {
-		long save_adjust = time_adjust;
+		long save_adjust = tk_ntp.time_adjust;
 
 		if (!(txc->modes & ADJ_OFFSET_READONLY)) {
 			/* adjtime() is independent from ntp_adjtime() */
-			time_adjust = txc->offset;
+			tk_ntp.time_adjust = txc->offset;
 			ntp_update_frequency();
 		}
 		txc->offset = save_adjust;
@@ -657,34 +617,35 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
 		if (txc->modes)
 			process_adjtimex_modes(txc, ts, time_tai);
 
-		txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
+		txc->offset =
+			shift_right(tk_ntp.time_offset * NTP_INTERVAL_FREQ,
 				  NTP_SCALE_SHIFT);
-		if (!(time_status & STA_NANO))
+		if (!(tk_ntp.time_status & STA_NANO))
 			txc->offset /= NSEC_PER_USEC;
 	}
 
-	result = time_state;	/* mostly `TIME_OK' */
+	result = tk_ntp.time_state;	/* mostly `TIME_OK' */
 	/* check for errors */
-	if (is_error_status(time_status))
+	if (is_error_status(tk_ntp.time_status))
 		result = TIME_ERROR;
 
-	txc->freq	   = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) *
-					 PPM_SCALE_INV, NTP_SCALE_SHIFT);
-	txc->maxerror	   = time_maxerror;
-	txc->esterror	   = time_esterror;
-	txc->status	   = time_status;
-	txc->constant	   = time_constant;
-	txc->precision	   = 1;
-	txc->tolerance	   = MAXFREQ_SCALED / PPM_SCALE;
-	txc->tick	   = tick_usec;
-	txc->tai	   = *time_tai;
+	txc->freq = shift_right((tk_ntp.time_freq >> PPM_SCALE_INV_SHIFT) *
+		PPM_SCALE_INV, NTP_SCALE_SHIFT);
+	txc->maxerror = tk_ntp.time_maxerror;
+	txc->esterror = tk_ntp.time_esterror;
+	txc->status = tk_ntp.time_status;
+	txc->constant = tk_ntp.time_constant;
+	txc->precision = 1;
+	txc->tolerance = MAXFREQ_SCALED / PPM_SCALE;
+	txc->tick = tk_ntp.tick_usec;
+	txc->tai = *time_tai;
 
 	/* fill PPS status fields */
 	pps_fill_timex(txc);
 
 	txc->time.tv_sec = ts->tv_sec;
 	txc->time.tv_usec = ts->tv_nsec;
-	if (!(time_status & STA_NANO))
+	if (!(tk_ntp.time_status & STA_NANO))
 		txc->time.tv_usec /= NSEC_PER_USEC;
 
 	return result;
@@ -781,7 +742,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 
 	/* check if the frequency interval was too long */
 	if (freq_norm.sec > (2 << pps_shift)) {
-		time_status |= STA_PPSERROR;
+		tk_ntp.time_status |= STA_PPSERROR;
 		pps_errcnt++;
 		pps_dec_freq_interval();
 		pr_err("hardpps: PPSERROR: interval too long - %ld s\n",
@@ -799,7 +760,7 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	pps_freq = ftemp;
 	if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
 		pr_warning("hardpps: PPSWANDER: change=%ld\n", delta);
-		time_status |= STA_PPSWANDER;
+		tk_ntp.time_status |= STA_PPSWANDER;
 		pps_stbcnt++;
 		pps_dec_freq_interval();
 	} else {	/* good sample */
@@ -818,9 +779,9 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 				NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
 
 	/* if enabled, the system clock frequency is updated */
-	if ((time_status & STA_PPSFREQ) != 0 &&
-	    (time_status & STA_FREQHOLD) == 0) {
-		time_freq = pps_freq;
+	if ((tk_ntp.time_status & STA_PPSFREQ) != 0 &&
+	    (tk_ntp.time_status & STA_FREQHOLD) == 0) {
+		tk_ntp.time_freq = pps_freq;
 		ntp_update_frequency();
 	}
 
@@ -844,14 +805,15 @@ static void hardpps_update_phase(long error)
 	if (jitter > (pps_jitter << PPS_POPCORN)) {
 		pr_warning("hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
 		       jitter, (pps_jitter << PPS_POPCORN));
-		time_status |= STA_PPSJITTER;
+		tk_ntp.time_status |= STA_PPSJITTER;
 		pps_jitcnt++;
-	} else if (time_status & STA_PPSTIME) {
+	} else if (tk_ntp.time_status & STA_PPSTIME) {
 		/* correct the time using the phase offset */
-		time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT,
+		tk_ntp.time_offset =
+			div_s64(((s64)correction) << NTP_SCALE_SHIFT,
 				NTP_INTERVAL_FREQ);
 		/* cancel running adjtime() */
-		time_adjust = 0;
+		tk_ntp.time_adjust = 0;
 	}
 	/* update jitter */
 	pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN;
@@ -876,10 +838,10 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 	pts_norm = pps_normalize_ts(*phase_ts);
 
 	/* clear the error bits, they will be set again if needed */
-	time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
+	tk_ntp.time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
 
 	/* indicate signal presence */
-	time_status |= STA_PPSSIGNAL;
+	tk_ntp.time_status |= STA_PPSSIGNAL;
 	pps_valid = PPS_VALID;
 
 	/* when called for the first time,
@@ -897,7 +859,7 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 	if ((freq_norm.sec == 0) ||
 			(freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
 			(freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
-		time_status |= STA_PPSJITTER;
+		tk_ntp.time_status |= STA_PPSJITTER;
 		/* restart the frequency calibration interval */
 		pps_fbase = *raw_ts;
 		pr_err("hardpps: PPSJITTER: bad pulse\n");
@@ -921,8 +883,8 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 
 static int __init ntp_tick_adj_setup(char *str)
 {
-	ntp_tick_adj = simple_strtol(str, NULL, 0);
-	ntp_tick_adj <<= NTP_SCALE_SHIFT;
+	tk_ntp.ntp_tick_adj = simple_strtol(str, NULL, 0);
+	tk_ntp.ntp_tick_adj <<= NTP_SCALE_SHIFT;
 
 	return 1;
 }
-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/7] Move PPS variables into struct timekeeper_pps
  2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 1/7] Move ntp variables into struct timekeeper_ntp Mathieu Desnoyers
@ 2013-09-14 19:47 ` Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 3/7] Move ntp structure into struct timekeeper Mathieu Desnoyers
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:47 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel
  Cc: Mathieu Desnoyers

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 include/linux/timekeeper_internal.h |   31 ++++++++
 kernel/time/ntp.c                   |  134 +++++++++++++++--------------------
 2 files changed, 87 insertions(+), 78 deletions(-)

diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index eab26e0..02c25c0 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -10,6 +10,32 @@
 #include <linux/jiffies.h>
 #include <linux/time.h>
 
+#ifdef CONFIG_NTP_PPS
+/*
+ * The following variables are used when a pulse-per-second (PPS) signal
+ * is available. They establish the engineering parameters of the clock
+ * discipline loop when controlled by the PPS signal.
+ */
+struct timekeeper_pps {
+	int valid;		/* signal watchdog counter */
+	long tf[3];		/* phase median filter */
+	long jitter;		/* current jitter (ns) */
+	struct timespec fbase;	/* beginning of the last freq interval */
+	int shift;		/* current interval duration (s) (shift) */
+	int intcnt;		/* interval counter */
+	s64 freq;		/* frequency offset (scaled ns/s) */
+	long stabil;		/* current stability (scaled ns/s) */
+
+	/*
+	 * PPS signal quality monitors
+	 */
+	long calcnt;		/* calibration intervals */
+	long jitcnt;		/* jitter limit exceeded */
+	long stbcnt;		/* stability limit exceeded */
+	long errcnt;		/* calibration errors */
+};
+#endif /* !CONFIG_NTP_PPS */
+
 /* structure holding internal NTP timekeeping values. */
 struct timekeeper_ntp {
 	/* USER_HZ period (usecs): */
@@ -55,6 +81,11 @@ struct timekeeper_ntp {
 
 	/* constant (boot-param configurable) NTP tick adjustment (upscaled) */
 	s64			ntp_tick_adj;
+
+#ifdef CONFIG_NTP_PPS
+	/* PPS variables */
+	struct timekeeper_pps   pps;
+#endif /* CONFIG_NTP_PPS */
 };
 
 /* Structure holding internal timekeeping values. */
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 983c212..b095070 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -36,11 +36,6 @@ static struct timekeeper_ntp tk_ntp = {
 
 #ifdef CONFIG_NTP_PPS
 
-/*
- * The following variables are used when a pulse-per-second (PPS) signal
- * is available. They establish the engineering parameters of the clock
- * discipline loop when controlled by the PPS signal.
- */
 #define PPS_VALID	10	/* PPS signal watchdog max (s) */
 #define PPS_POPCORN	4	/* popcorn spike threshold (shift) */
 #define PPS_INTMIN	2	/* min freq interval (s) (shift) */
@@ -50,24 +45,6 @@ static struct timekeeper_ntp tk_ntp = {
 				   intervals to decrease it */
 #define PPS_MAXWANDER	100000	/* max PPS freq wander (ns/s) */
 
-static int pps_valid;		/* signal watchdog counter */
-static long pps_tf[3];		/* phase median filter */
-static long pps_jitter;		/* current jitter (ns) */
-static struct timespec pps_fbase; /* beginning of the last freq interval */
-static int pps_shift;		/* current interval duration (s) (shift) */
-static int pps_intcnt;		/* interval counter */
-static s64 pps_freq;		/* frequency offset (scaled ns/s) */
-static long pps_stabil;		/* current stability (scaled ns/s) */
-
-/*
- * PPS signal quality monitors
- */
-static long pps_calcnt;		/* calibration intervals */
-static long pps_jitcnt;		/* jitter limit exceeded */
-static long pps_stbcnt;		/* stability limit exceeded */
-static long pps_errcnt;		/* calibration errors */
-
-
 /* PPS kernel consumer compensates the whole phase error immediately.
  * Otherwise, reduce the offset by a fixed factor times the time constant.
  */
@@ -84,8 +61,8 @@ static inline void pps_reset_freq_interval(void)
 {
 	/* the PPS calibration interval may end
 	   surprisingly early */
-	pps_shift = PPS_INTMIN;
-	pps_intcnt = 0;
+	tk_ntp.pps.shift = PPS_INTMIN;
+	tk_ntp.pps.intcnt = 0;
 }
 
 /**
@@ -94,11 +71,11 @@ static inline void pps_reset_freq_interval(void)
 static inline void pps_clear(void)
 {
 	pps_reset_freq_interval();
-	pps_tf[0] = 0;
-	pps_tf[1] = 0;
-	pps_tf[2] = 0;
-	pps_fbase.tv_sec = pps_fbase.tv_nsec = 0;
-	pps_freq = 0;
+	tk_ntp.pps.tf[0] = 0;
+	tk_ntp.pps.tf[1] = 0;
+	tk_ntp.pps.tf[2] = 0;
+	tk_ntp.pps.fbase.tv_sec = tk_ntp.pps.fbase.tv_nsec = 0;
+	tk_ntp.pps.freq = 0;
 }
 
 /* Decrease pps_valid to indicate that another second has passed since
@@ -107,8 +84,8 @@ static inline void pps_clear(void)
  */
 static inline void pps_dec_valid(void)
 {
-	if (pps_valid > 0)
-		pps_valid--;
+	if (tk_ntp.pps.valid > 0)
+		tk_ntp.pps.valid--;
 	else {
 		tk_ntp.time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
 				 STA_PPSWANDER | STA_PPSERROR);
@@ -118,7 +95,7 @@ static inline void pps_dec_valid(void)
 
 static inline void pps_set_freq(s64 freq)
 {
-	pps_freq = freq;
+	tk_ntp.pps.freq = freq;
 }
 
 static inline int is_error_status(int status)
@@ -142,17 +119,17 @@ static inline int is_error_status(int status)
 
 static inline void pps_fill_timex(struct timex *txc)
 {
-	txc->ppsfreq	   = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) *
+	txc->ppsfreq = shift_right((tk_ntp.pps.freq >> PPM_SCALE_INV_SHIFT) *
 					 PPM_SCALE_INV, NTP_SCALE_SHIFT);
-	txc->jitter	   = pps_jitter;
+	txc->jitter = tk_ntp.pps.jitter;
 	if (!(tk_ntp.time_status & STA_NANO))
 		txc->jitter /= NSEC_PER_USEC;
-	txc->shift	   = pps_shift;
-	txc->stabil	   = pps_stabil;
-	txc->jitcnt	   = pps_jitcnt;
-	txc->calcnt	   = pps_calcnt;
-	txc->errcnt	   = pps_errcnt;
-	txc->stbcnt	   = pps_stbcnt;
+	txc->shift = tk_ntp.pps.shift;
+	txc->stabil = tk_ntp.pps.stabil;
+	txc->jitcnt = tk_ntp.pps.jitcnt;
+	txc->calcnt = tk_ntp.pps.calcnt;
+	txc->errcnt = tk_ntp.pps.errcnt;
+	txc->stbcnt = tk_ntp.pps.stbcnt;
 }
 
 #else /* !CONFIG_NTP_PPS */
@@ -528,7 +505,7 @@ static inline void process_adjtimex_modes(struct timex *txc,
 		tk_ntp.time_freq = txc->freq * PPM_SCALE;
 		tk_ntp.time_freq = min(tk_ntp.time_freq, MAXFREQ_SCALED);
 		tk_ntp.time_freq = max(tk_ntp.time_freq, -MAXFREQ_SCALED);
-		/* update pps_freq */
+		/* update tk_ntp.pps.freq */
 		pps_set_freq(tk_ntp.time_freq);
 	}
 
@@ -682,20 +659,20 @@ static inline struct pps_normtime pps_normalize_ts(struct timespec ts)
 /* get current phase correction and jitter */
 static inline long pps_phase_filter_get(long *jitter)
 {
-	*jitter = pps_tf[0] - pps_tf[1];
+	*jitter = tk_ntp.pps.tf[0] - tk_ntp.pps.tf[1];
 	if (*jitter < 0)
 		*jitter = -*jitter;
 
 	/* TODO: test various filters */
-	return pps_tf[0];
+	return tk_ntp.pps.tf[0];
 }
 
 /* add the sample to the phase filter */
 static inline void pps_phase_filter_add(long err)
 {
-	pps_tf[2] = pps_tf[1];
-	pps_tf[1] = pps_tf[0];
-	pps_tf[0] = err;
+	tk_ntp.pps.tf[2] = tk_ntp.pps.tf[1];
+	tk_ntp.pps.tf[1] = tk_ntp.pps.tf[0];
+	tk_ntp.pps.tf[0] = err;
 }
 
 /* decrease frequency calibration interval length.
@@ -703,11 +680,11 @@ static inline void pps_phase_filter_add(long err)
  */
 static inline void pps_dec_freq_interval(void)
 {
-	if (--pps_intcnt <= -PPS_INTCOUNT) {
-		pps_intcnt = -PPS_INTCOUNT;
-		if (pps_shift > PPS_INTMIN) {
-			pps_shift--;
-			pps_intcnt = 0;
+	if (--tk_ntp.pps.intcnt <= -PPS_INTCOUNT) {
+		tk_ntp.pps.intcnt = -PPS_INTCOUNT;
+		if (tk_ntp.pps.shift > PPS_INTMIN) {
+			tk_ntp.pps.shift--;
+			tk_ntp.pps.intcnt = 0;
 		}
 	}
 }
@@ -717,11 +694,11 @@ static inline void pps_dec_freq_interval(void)
  */
 static inline void pps_inc_freq_interval(void)
 {
-	if (++pps_intcnt >= PPS_INTCOUNT) {
-		pps_intcnt = PPS_INTCOUNT;
-		if (pps_shift < PPS_INTMAX) {
-			pps_shift++;
-			pps_intcnt = 0;
+	if (++tk_ntp.pps.intcnt >= PPS_INTCOUNT) {
+		tk_ntp.pps.intcnt = PPS_INTCOUNT;
+		if (tk_ntp.pps.shift < PPS_INTMAX) {
+			tk_ntp.pps.shift++;
+			tk_ntp.pps.intcnt = 0;
 		}
 	}
 }
@@ -741,9 +718,9 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	s64 ftemp;
 
 	/* check if the frequency interval was too long */
-	if (freq_norm.sec > (2 << pps_shift)) {
+	if (freq_norm.sec > (2 << tk_ntp.pps.shift)) {
 		tk_ntp.time_status |= STA_PPSERROR;
-		pps_errcnt++;
+		tk_ntp.pps.errcnt++;
 		pps_dec_freq_interval();
 		pr_err("hardpps: PPSERROR: interval too long - %ld s\n",
 				freq_norm.sec);
@@ -756,12 +733,12 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	 */
 	ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT,
 			freq_norm.sec);
-	delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT);
-	pps_freq = ftemp;
+	delta = shift_right(ftemp - tk_ntp.pps.freq, NTP_SCALE_SHIFT);
+	tk_ntp.pps.freq = ftemp;
 	if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
 		pr_warning("hardpps: PPSWANDER: change=%ld\n", delta);
 		tk_ntp.time_status |= STA_PPSWANDER;
-		pps_stbcnt++;
+		tk_ntp.pps.stbcnt++;
 		pps_dec_freq_interval();
 	} else {	/* good sample */
 		pps_inc_freq_interval();
@@ -774,14 +751,14 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	delta_mod = delta;
 	if (delta_mod < 0)
 		delta_mod = -delta_mod;
-	pps_stabil += (div_s64(((s64)delta_mod) <<
-				(NTP_SCALE_SHIFT - SHIFT_USEC),
-				NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
+	tk_ntp.pps.stabil += (div_s64(((s64)delta_mod) <<
+		(NTP_SCALE_SHIFT - SHIFT_USEC),
+		NSEC_PER_USEC) - tk_ntp.pps.stabil) >> PPS_INTMIN;
 
 	/* if enabled, the system clock frequency is updated */
 	if ((tk_ntp.time_status & STA_PPSFREQ) != 0 &&
 	    (tk_ntp.time_status & STA_FREQHOLD) == 0) {
-		tk_ntp.time_freq = pps_freq;
+		tk_ntp.time_freq = tk_ntp.pps.freq;
 		ntp_update_frequency();
 	}
 
@@ -802,11 +779,11 @@ static void hardpps_update_phase(long error)
 	 * threshold, the sample is discarded; otherwise, if so enabled,
 	 * the time offset is updated.
 	 */
-	if (jitter > (pps_jitter << PPS_POPCORN)) {
+	if (jitter > (tk_ntp.pps.jitter << PPS_POPCORN)) {
 		pr_warning("hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
-		       jitter, (pps_jitter << PPS_POPCORN));
+		       jitter, (tk_ntp.pps.jitter << PPS_POPCORN));
 		tk_ntp.time_status |= STA_PPSJITTER;
-		pps_jitcnt++;
+		tk_ntp.pps.jitcnt++;
 	} else if (tk_ntp.time_status & STA_PPSTIME) {
 		/* correct the time using the phase offset */
 		tk_ntp.time_offset =
@@ -816,7 +793,7 @@ static void hardpps_update_phase(long error)
 		tk_ntp.time_adjust = 0;
 	}
 	/* update jitter */
-	pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN;
+	tk_ntp.pps.jitter += (jitter - tk_ntp.pps.jitter) >> PPS_INTMIN;
 }
 
 /*
@@ -842,17 +819,18 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 
 	/* indicate signal presence */
 	tk_ntp.time_status |= STA_PPSSIGNAL;
-	pps_valid = PPS_VALID;
+	tk_ntp.pps.valid = PPS_VALID;
 
 	/* when called for the first time,
 	 * just start the frequency interval */
-	if (unlikely(pps_fbase.tv_sec == 0)) {
-		pps_fbase = *raw_ts;
+	if (unlikely(tk_ntp.pps.fbase.tv_sec == 0)) {
+		tk_ntp.pps.fbase = *raw_ts;
 		return;
 	}
 
 	/* ok, now we have a base for frequency calculation */
-	freq_norm = pps_normalize_ts(timespec_sub(*raw_ts, pps_fbase));
+	freq_norm = pps_normalize_ts(timespec_sub(*raw_ts,
+		tk_ntp.pps.fbase));
 
 	/* check that the signal is in the range
 	 * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */
@@ -861,7 +839,7 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 			(freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
 		tk_ntp.time_status |= STA_PPSJITTER;
 		/* restart the frequency calibration interval */
-		pps_fbase = *raw_ts;
+		tk_ntp.pps.fbase = *raw_ts;
 		pr_err("hardpps: PPSJITTER: bad pulse\n");
 		return;
 	}
@@ -869,10 +847,10 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 	/* signal is ok */
 
 	/* check if the current frequency interval is finished */
-	if (freq_norm.sec >= (1 << pps_shift)) {
-		pps_calcnt++;
+	if (freq_norm.sec >= (1 << tk_ntp.pps.shift)) {
+		tk_ntp.pps.calcnt++;
 		/* restart the frequency calibration interval */
-		pps_fbase = *raw_ts;
+		tk_ntp.pps.fbase = *raw_ts;
 		hardpps_update_freq(freq_norm);
 	}
 
-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/7] Move ntp structure into struct timekeeper
  2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 1/7] Move ntp variables into struct timekeeper_ntp Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 2/7] Move PPS variables into struct timekeeper_pps Mathieu Desnoyers
@ 2013-09-14 19:47 ` Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 4/7] Pass struct timekeeper_ntp as parameter from timekeeper to ntp Mathieu Desnoyers
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:47 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel
  Cc: Mathieu Desnoyers

This is in preparation for the latch synchronization scheme.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 include/linux/timekeeper_internal.h |    4 +
 kernel/time/ntp.c                   |  361 +++++++++++++++++------------------
 kernel/time/timekeeping.c           |   12 +-
 3 files changed, 191 insertions(+), 186 deletions(-)

diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 02c25c0..6f0532d 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -147,8 +147,12 @@ struct timekeeper {
 	/* Offset clock monotonic -> clock tai */
 	ktime_t			offs_tai;
 
+	/* NTP variables */
+	struct timekeeper_ntp	ntp;
 };
 
+extern struct timekeeper timekeeper;
+
 static inline struct timespec tk_xtime(struct timekeeper *tk)
 {
 	struct timespec ts;
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index b095070..d61e700 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -25,15 +25,6 @@
 #define MAX_TICKADJ_SCALED \
 	(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
 
-static struct timekeeper_ntp tk_ntp = {
-	.tick_usec = TICK_USEC,
-	.time_state = TIME_OK,
-	.time_status = STA_UNSYNC,
-	.time_constant = 2,
-	.time_maxerror = NTP_PHASE_LIMIT,
-	.time_esterror = NTP_PHASE_LIMIT,
-};
-
 #ifdef CONFIG_NTP_PPS
 
 #define PPS_VALID	10	/* PPS signal watchdog max (s) */
@@ -50,19 +41,19 @@ static struct timekeeper_ntp tk_ntp = {
  */
 static inline s64 ntp_offset_chunk(s64 offset)
 {
-	if (tk_ntp.time_status & STA_PPSTIME
-			&& tk_ntp.time_status & STA_PPSSIGNAL)
+	if (timekeeper.ntp.time_status & STA_PPSTIME
+			&& timekeeper.ntp.time_status & STA_PPSSIGNAL)
 		return offset;
 	else
-		return shift_right(offset, SHIFT_PLL + tk_ntp.time_constant);
+		return shift_right(offset, SHIFT_PLL + timekeeper.ntp.time_constant);
 }
 
 static inline void pps_reset_freq_interval(void)
 {
 	/* the PPS calibration interval may end
 	   surprisingly early */
-	tk_ntp.pps.shift = PPS_INTMIN;
-	tk_ntp.pps.intcnt = 0;
+	timekeeper.ntp.pps.shift = PPS_INTMIN;
+	timekeeper.ntp.pps.intcnt = 0;
 }
 
 /**
@@ -71,11 +62,11 @@ static inline void pps_reset_freq_interval(void)
 static inline void pps_clear(void)
 {
 	pps_reset_freq_interval();
-	tk_ntp.pps.tf[0] = 0;
-	tk_ntp.pps.tf[1] = 0;
-	tk_ntp.pps.tf[2] = 0;
-	tk_ntp.pps.fbase.tv_sec = tk_ntp.pps.fbase.tv_nsec = 0;
-	tk_ntp.pps.freq = 0;
+	timekeeper.ntp.pps.tf[0] = 0;
+	timekeeper.ntp.pps.tf[1] = 0;
+	timekeeper.ntp.pps.tf[2] = 0;
+	timekeeper.ntp.pps.fbase.tv_sec = timekeeper.ntp.pps.fbase.tv_nsec = 0;
+	timekeeper.ntp.pps.freq = 0;
 }
 
 /* Decrease pps_valid to indicate that another second has passed since
@@ -84,10 +75,10 @@ static inline void pps_clear(void)
  */
 static inline void pps_dec_valid(void)
 {
-	if (tk_ntp.pps.valid > 0)
-		tk_ntp.pps.valid--;
+	if (timekeeper.ntp.pps.valid > 0)
+		timekeeper.ntp.pps.valid--;
 	else {
-		tk_ntp.time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
+		timekeeper.ntp.time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
 				 STA_PPSWANDER | STA_PPSERROR);
 		pps_clear();
 	}
@@ -95,48 +86,48 @@ static inline void pps_dec_valid(void)
 
 static inline void pps_set_freq(s64 freq)
 {
-	tk_ntp.pps.freq = freq;
+	timekeeper.ntp.pps.freq = freq;
 }
 
 static inline int is_error_status(int status)
 {
-	return (tk_ntp.time_status & (STA_UNSYNC|STA_CLOCKERR))
+	return (timekeeper.ntp.time_status & (STA_UNSYNC|STA_CLOCKERR))
 		/* PPS signal lost when either PPS time or
 		 * PPS frequency synchronization requested
 		 */
-		|| ((tk_ntp.time_status & (STA_PPSFREQ|STA_PPSTIME))
-			&& !(tk_ntp.time_status & STA_PPSSIGNAL))
+		|| ((timekeeper.ntp.time_status & (STA_PPSFREQ|STA_PPSTIME))
+			&& !(timekeeper.ntp.time_status & STA_PPSSIGNAL))
 		/* PPS jitter exceeded when
 		 * PPS time synchronization requested */
-		|| ((tk_ntp.time_status & (STA_PPSTIME|STA_PPSJITTER))
+		|| ((timekeeper.ntp.time_status & (STA_PPSTIME|STA_PPSJITTER))
 			== (STA_PPSTIME|STA_PPSJITTER))
 		/* PPS wander exceeded or calibration error when
 		 * PPS frequency synchronization requested
 		 */
-		|| ((tk_ntp.time_status & STA_PPSFREQ)
-			&& (tk_ntp.time_status & (STA_PPSWANDER|STA_PPSERROR)));
+		|| ((timekeeper.ntp.time_status & STA_PPSFREQ)
+			&& (timekeeper.ntp.time_status & (STA_PPSWANDER|STA_PPSERROR)));
 }
 
 static inline void pps_fill_timex(struct timex *txc)
 {
-	txc->ppsfreq = shift_right((tk_ntp.pps.freq >> PPM_SCALE_INV_SHIFT) *
+	txc->ppsfreq = shift_right((timekeeper.ntp.pps.freq >> PPM_SCALE_INV_SHIFT) *
 					 PPM_SCALE_INV, NTP_SCALE_SHIFT);
-	txc->jitter = tk_ntp.pps.jitter;
-	if (!(tk_ntp.time_status & STA_NANO))
+	txc->jitter = timekeeper.ntp.pps.jitter;
+	if (!(timekeeper.ntp.time_status & STA_NANO))
 		txc->jitter /= NSEC_PER_USEC;
-	txc->shift = tk_ntp.pps.shift;
-	txc->stabil = tk_ntp.pps.stabil;
-	txc->jitcnt = tk_ntp.pps.jitcnt;
-	txc->calcnt = tk_ntp.pps.calcnt;
-	txc->errcnt = tk_ntp.pps.errcnt;
-	txc->stbcnt = tk_ntp.pps.stbcnt;
+	txc->shift = timekeeper.ntp.pps.shift;
+	txc->stabil = timekeeper.ntp.pps.stabil;
+	txc->jitcnt = timekeeper.ntp.pps.jitcnt;
+	txc->calcnt = timekeeper.ntp.pps.calcnt;
+	txc->errcnt = timekeeper.ntp.pps.errcnt;
+	txc->stbcnt = timekeeper.ntp.pps.stbcnt;
 }
 
 #else /* !CONFIG_NTP_PPS */
 
 static inline s64 ntp_offset_chunk(s64 offset)
 {
-	return shift_right(offset, SHIFT_PLL + tk_ntp.time_constant);
+	return shift_right(offset, SHIFT_PLL + timekeeper.ntp.time_constant);
 }
 
 static inline void pps_reset_freq_interval(void) {}
@@ -171,7 +162,7 @@ static inline void pps_fill_timex(struct timex *txc)
  */
 static inline int ntp_synced(void)
 {
-	return !(tk_ntp.time_status & STA_UNSYNC);
+	return !(timekeeper.ntp.time_status & STA_UNSYNC);
 }
 
 
@@ -180,42 +171,42 @@ static inline int ntp_synced(void)
  */
 
 /*
- * Update (tk_ntp.tick_length, tk_ntp.tick_length_base, tk_ntp.tick_nsec),
- * based on (tk_ntp.tick_usec, tk_ntp.ntp_tick_adj, tk_ntp.time_freq):
+ * Update (timekeeper.ntp.tick_length, timekeeper.ntp.tick_length_base, timekeeper.ntp.tick_nsec),
+ * based on (timekeeper.ntp.tick_usec, timekeeper.ntp.ntp_tick_adj, timekeeper.ntp.time_freq):
  */
 static void ntp_update_frequency(void)
 {
 	u64 second_length;
 	u64 new_base;
 
-	second_length = (u64)(tk_ntp.tick_usec * NSEC_PER_USEC * USER_HZ)
+	second_length = (u64)(timekeeper.ntp.tick_usec * NSEC_PER_USEC * USER_HZ)
 						<< NTP_SCALE_SHIFT;
 
-	second_length += tk_ntp.ntp_tick_adj;
-	second_length += tk_ntp.time_freq;
+	second_length += timekeeper.ntp.ntp_tick_adj;
+	second_length += timekeeper.ntp.time_freq;
 
-	tk_ntp.tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
+	timekeeper.ntp.tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
 	new_base = div_u64(second_length, NTP_INTERVAL_FREQ);
 
 	/*
 	 * Don't wait for the next second_overflow, apply
 	 * the change to the tick length immediately:
 	 */
-	tk_ntp.tick_length += new_base - tk_ntp.tick_length_base;
-	tk_ntp.tick_length_base = new_base;
+	timekeeper.ntp.tick_length += new_base - timekeeper.ntp.tick_length_base;
+	timekeeper.ntp.tick_length_base = new_base;
 }
 
 static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
 {
-	tk_ntp.time_status &= ~STA_MODE;
+	timekeeper.ntp.time_status &= ~STA_MODE;
 
 	if (secs < MINSEC)
 		return 0;
 
-	if (!(tk_ntp.time_status & STA_FLL) && (secs <= MAXSEC))
+	if (!(timekeeper.ntp.time_status & STA_FLL) && (secs <= MAXSEC))
 		return 0;
 
-	tk_ntp.time_status |= STA_MODE;
+	timekeeper.ntp.time_status |= STA_MODE;
 
 	return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
 }
@@ -226,10 +217,10 @@ static void ntp_update_offset(long offset)
 	s64 offset64;
 	long secs;
 
-	if (!(tk_ntp.time_status & STA_PLL))
+	if (!(timekeeper.ntp.time_status & STA_PLL))
 		return;
 
-	if (!(tk_ntp.time_status & STA_NANO))
+	if (!(timekeeper.ntp.time_status & STA_NANO))
 		offset *= NSEC_PER_USEC;
 
 	/*
@@ -243,11 +234,11 @@ static void ntp_update_offset(long offset)
 	 * Select how the frequency is to be controlled
 	 * and in which mode (PLL or FLL).
 	 */
-	secs = get_seconds() - tk_ntp.time_reftime;
-	if (unlikely(tk_ntp.time_status & STA_FREQHOLD))
+	secs = get_seconds() - timekeeper.ntp.time_reftime;
+	if (unlikely(timekeeper.ntp.time_status & STA_FREQHOLD))
 		secs = 0;
 
-	tk_ntp.time_reftime = get_seconds();
+	timekeeper.ntp.time_reftime = get_seconds();
 
 	offset64    = offset;
 	freq_adj    = ntp_update_offset_fll(offset64, secs);
@@ -257,17 +248,17 @@ static void ntp_update_offset(long offset)
 	 * sampling rate (e.g. intermittent network connection)
 	 * to avoid instability.
 	 */
-	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + tk_ntp.time_constant)))
-		secs = 1 << (SHIFT_PLL + 1 + tk_ntp.time_constant);
+	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + timekeeper.ntp.time_constant)))
+		secs = 1 << (SHIFT_PLL + 1 + timekeeper.ntp.time_constant);
 
 	freq_adj    += (offset64 * secs) <<
-		(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + tk_ntp.time_constant));
+		(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + timekeeper.ntp.time_constant));
 
-	freq_adj    = min(freq_adj + tk_ntp.time_freq, MAXFREQ_SCALED);
+	freq_adj    = min(freq_adj + timekeeper.ntp.time_freq, MAXFREQ_SCALED);
 
-	tk_ntp.time_freq   = max(freq_adj, -MAXFREQ_SCALED);
+	timekeeper.ntp.time_freq   = max(freq_adj, -MAXFREQ_SCALED);
 
-	tk_ntp.time_offset = div_s64(offset64 << NTP_SCALE_SHIFT,
+	timekeeper.ntp.time_offset = div_s64(offset64 << NTP_SCALE_SHIFT,
 		NTP_INTERVAL_FREQ);
 }
 
@@ -276,15 +267,15 @@ static void ntp_update_offset(long offset)
  */
 void ntp_clear(void)
 {
-	tk_ntp.time_adjust	= 0;		/* stop active adjtime() */
-	tk_ntp.time_status	|= STA_UNSYNC;
-	tk_ntp.time_maxerror	= NTP_PHASE_LIMIT;
-	tk_ntp.time_esterror	= NTP_PHASE_LIMIT;
+	timekeeper.ntp.time_adjust	= 0;		/* stop active adjtime() */
+	timekeeper.ntp.time_status	|= STA_UNSYNC;
+	timekeeper.ntp.time_maxerror	= NTP_PHASE_LIMIT;
+	timekeeper.ntp.time_esterror	= NTP_PHASE_LIMIT;
 
 	ntp_update_frequency();
 
-	tk_ntp.tick_length	= tk_ntp.tick_length_base;
-	tk_ntp.time_offset	= 0;
+	timekeeper.ntp.tick_length	= timekeeper.ntp.tick_length_base;
+	timekeeper.ntp.time_offset	= 0;
 
 	/* Clear PPS state variables */
 	pps_clear();
@@ -293,7 +284,7 @@ void ntp_clear(void)
 
 u64 ntp_tick_length(void)
 {
-	return tk_ntp.tick_length;
+	return timekeeper.ntp.tick_length;
 }
 
 
@@ -317,80 +308,80 @@ int second_overflow(unsigned long secs)
 	 * day, the system clock is set back one second; if in leap-delete
 	 * state, the system clock is set ahead one second.
 	 */
-	switch (tk_ntp.time_state) {
+	switch (timekeeper.ntp.time_state) {
 	case TIME_OK:
-		if (tk_ntp.time_status & STA_INS)
-			tk_ntp.time_state = TIME_INS;
-		else if (tk_ntp.time_status & STA_DEL)
-			tk_ntp.time_state = TIME_DEL;
+		if (timekeeper.ntp.time_status & STA_INS)
+			timekeeper.ntp.time_state = TIME_INS;
+		else if (timekeeper.ntp.time_status & STA_DEL)
+			timekeeper.ntp.time_state = TIME_DEL;
 		break;
 	case TIME_INS:
-		if (!(tk_ntp.time_status & STA_INS))
-			tk_ntp.time_state = TIME_OK;
+		if (!(timekeeper.ntp.time_status & STA_INS))
+			timekeeper.ntp.time_state = TIME_OK;
 		else if (secs % 86400 == 0) {
 			leap = -1;
-			tk_ntp.time_state = TIME_OOP;
+			timekeeper.ntp.time_state = TIME_OOP;
 			printk(KERN_NOTICE
 				"Clock: inserting leap second 23:59:60 UTC\n");
 		}
 		break;
 	case TIME_DEL:
-		if (!(tk_ntp.time_status & STA_DEL))
-			tk_ntp.time_state = TIME_OK;
+		if (!(timekeeper.ntp.time_status & STA_DEL))
+			timekeeper.ntp.time_state = TIME_OK;
 		else if ((secs + 1) % 86400 == 0) {
 			leap = 1;
-			tk_ntp.time_state = TIME_WAIT;
+			timekeeper.ntp.time_state = TIME_WAIT;
 			printk(KERN_NOTICE
 				"Clock: deleting leap second 23:59:59 UTC\n");
 		}
 		break;
 	case TIME_OOP:
-		tk_ntp.time_state = TIME_WAIT;
+		timekeeper.ntp.time_state = TIME_WAIT;
 		break;
 
 	case TIME_WAIT:
-		if (!(tk_ntp.time_status & (STA_INS | STA_DEL)))
-			tk_ntp.time_state = TIME_OK;
+		if (!(timekeeper.ntp.time_status & (STA_INS | STA_DEL)))
+			timekeeper.ntp.time_state = TIME_OK;
 		break;
 	}
 
 
 	/* Bump the maxerror field */
-	tk_ntp.time_maxerror += MAXFREQ / NSEC_PER_USEC;
-	if (tk_ntp.time_maxerror > NTP_PHASE_LIMIT) {
-		tk_ntp.time_maxerror = NTP_PHASE_LIMIT;
-		tk_ntp.time_status |= STA_UNSYNC;
+	timekeeper.ntp.time_maxerror += MAXFREQ / NSEC_PER_USEC;
+	if (timekeeper.ntp.time_maxerror > NTP_PHASE_LIMIT) {
+		timekeeper.ntp.time_maxerror = NTP_PHASE_LIMIT;
+		timekeeper.ntp.time_status |= STA_UNSYNC;
 	}
 
 	/* Compute the phase adjustment for the next second */
-	tk_ntp.tick_length = tk_ntp.tick_length_base;
+	timekeeper.ntp.tick_length = timekeeper.ntp.tick_length_base;
 
-	delta = ntp_offset_chunk(tk_ntp.time_offset);
-	tk_ntp.time_offset -= delta;
-	tk_ntp.tick_length += delta;
+	delta = ntp_offset_chunk(timekeeper.ntp.time_offset);
+	timekeeper.ntp.time_offset -= delta;
+	timekeeper.ntp.tick_length += delta;
 
 	/* Check PPS signal */
 	pps_dec_valid();
 
-	if (!tk_ntp.time_adjust)
+	if (!timekeeper.ntp.time_adjust)
 		goto out;
 
-	if (tk_ntp.time_adjust > MAX_TICKADJ) {
-		tk_ntp.time_adjust -= MAX_TICKADJ;
-		tk_ntp.tick_length += MAX_TICKADJ_SCALED;
+	if (timekeeper.ntp.time_adjust > MAX_TICKADJ) {
+		timekeeper.ntp.time_adjust -= MAX_TICKADJ;
+		timekeeper.ntp.tick_length += MAX_TICKADJ_SCALED;
 		goto out;
 	}
 
-	if (tk_ntp.time_adjust < -MAX_TICKADJ) {
-		tk_ntp.time_adjust += MAX_TICKADJ;
-		tk_ntp.tick_length -= MAX_TICKADJ_SCALED;
+	if (timekeeper.ntp.time_adjust < -MAX_TICKADJ) {
+		timekeeper.ntp.time_adjust += MAX_TICKADJ;
+		timekeeper.ntp.tick_length -= MAX_TICKADJ_SCALED;
 		goto out;
 	}
 
-	tk_ntp.tick_length +=
-		(s64)(tk_ntp.time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
+	timekeeper.ntp.tick_length +=
+		(s64)(timekeeper.ntp.time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
 							 << NTP_SCALE_SHIFT;
-	tk_ntp.time_adjust = 0;
+	timekeeper.ntp.time_adjust = 0;
 
 out:
 	return leap;
@@ -422,7 +413,7 @@ static void sync_cmos_clock(struct work_struct *work)
 	}
 
 	getnstimeofday(&now);
-	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tk_ntp.tick_nsec / 2) {
+	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= timekeeper.ntp.tick_nsec / 2) {
 		struct timespec adjust = now;
 
 		fail = -ENODEV;
@@ -468,9 +459,9 @@ void ntp_notify_cmos_timer(void) { }
  */
 static inline void process_adj_status(struct timex *txc, struct timespec *ts)
 {
-	if ((tk_ntp.time_status & STA_PLL) && !(txc->status & STA_PLL)) {
-		tk_ntp.time_state = TIME_OK;
-		tk_ntp.time_status = STA_UNSYNC;
+	if ((timekeeper.ntp.time_status & STA_PLL) && !(txc->status & STA_PLL)) {
+		timekeeper.ntp.time_state = TIME_OK;
+		timekeeper.ntp.time_status = STA_UNSYNC;
 		/* restart PPS frequency calibration */
 		pps_reset_freq_interval();
 	}
@@ -479,12 +470,12 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
 	 * If we turn on PLL adjustments then reset the
 	 * reference time to current time.
 	 */
-	if (!(tk_ntp.time_status & STA_PLL) && (txc->status & STA_PLL))
-		tk_ntp.time_reftime = get_seconds();
+	if (!(timekeeper.ntp.time_status & STA_PLL) && (txc->status & STA_PLL))
+		timekeeper.ntp.time_reftime = get_seconds();
 
 	/* only set allowed bits */
-	tk_ntp.time_status &= STA_RONLY;
-	tk_ntp.time_status |= txc->status & ~STA_RONLY;
+	timekeeper.ntp.time_status &= STA_RONLY;
+	timekeeper.ntp.time_status |= txc->status & ~STA_RONLY;
 }
 
 
@@ -496,31 +487,31 @@ static inline void process_adjtimex_modes(struct timex *txc,
 		process_adj_status(txc, ts);
 
 	if (txc->modes & ADJ_NANO)
-		tk_ntp.time_status |= STA_NANO;
+		timekeeper.ntp.time_status |= STA_NANO;
 
 	if (txc->modes & ADJ_MICRO)
-		tk_ntp.time_status &= ~STA_NANO;
+		timekeeper.ntp.time_status &= ~STA_NANO;
 
 	if (txc->modes & ADJ_FREQUENCY) {
-		tk_ntp.time_freq = txc->freq * PPM_SCALE;
-		tk_ntp.time_freq = min(tk_ntp.time_freq, MAXFREQ_SCALED);
-		tk_ntp.time_freq = max(tk_ntp.time_freq, -MAXFREQ_SCALED);
-		/* update tk_ntp.pps.freq */
-		pps_set_freq(tk_ntp.time_freq);
+		timekeeper.ntp.time_freq = txc->freq * PPM_SCALE;
+		timekeeper.ntp.time_freq = min(timekeeper.ntp.time_freq, MAXFREQ_SCALED);
+		timekeeper.ntp.time_freq = max(timekeeper.ntp.time_freq, -MAXFREQ_SCALED);
+		/* update timekeeper.ntp.pps.freq */
+		pps_set_freq(timekeeper.ntp.time_freq);
 	}
 
 	if (txc->modes & ADJ_MAXERROR)
-		tk_ntp.time_maxerror = txc->maxerror;
+		timekeeper.ntp.time_maxerror = txc->maxerror;
 
 	if (txc->modes & ADJ_ESTERROR)
-		tk_ntp.time_esterror = txc->esterror;
+		timekeeper.ntp.time_esterror = txc->esterror;
 
 	if (txc->modes & ADJ_TIMECONST) {
-		tk_ntp.time_constant = txc->constant;
-		if (!(tk_ntp.time_status & STA_NANO))
-			tk_ntp.time_constant += 4;
-		tk_ntp.time_constant = min(tk_ntp.time_constant, (long)MAXTC);
-		tk_ntp.time_constant = max(tk_ntp.time_constant, 0l);
+		timekeeper.ntp.time_constant = txc->constant;
+		if (!(timekeeper.ntp.time_status & STA_NANO))
+			timekeeper.ntp.time_constant += 4;
+		timekeeper.ntp.time_constant = min(timekeeper.ntp.time_constant, (long)MAXTC);
+		timekeeper.ntp.time_constant = max(timekeeper.ntp.time_constant, 0l);
 	}
 
 	if (txc->modes & ADJ_TAI && txc->constant > 0)
@@ -530,7 +521,7 @@ static inline void process_adjtimex_modes(struct timex *txc,
 		ntp_update_offset(txc->offset);
 
 	if (txc->modes & ADJ_TICK)
-		tk_ntp.tick_usec = txc->tick;
+		timekeeper.ntp.tick_usec = txc->tick;
 
 	if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
 		ntp_update_frequency();
@@ -580,11 +571,11 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
 	int result;
 
 	if (txc->modes & ADJ_ADJTIME) {
-		long save_adjust = tk_ntp.time_adjust;
+		long save_adjust = timekeeper.ntp.time_adjust;
 
 		if (!(txc->modes & ADJ_OFFSET_READONLY)) {
 			/* adjtime() is independent from ntp_adjtime() */
-			tk_ntp.time_adjust = txc->offset;
+			timekeeper.ntp.time_adjust = txc->offset;
 			ntp_update_frequency();
 		}
 		txc->offset = save_adjust;
@@ -595,26 +586,26 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
 			process_adjtimex_modes(txc, ts, time_tai);
 
 		txc->offset =
-			shift_right(tk_ntp.time_offset * NTP_INTERVAL_FREQ,
+			shift_right(timekeeper.ntp.time_offset * NTP_INTERVAL_FREQ,
 				  NTP_SCALE_SHIFT);
-		if (!(tk_ntp.time_status & STA_NANO))
+		if (!(timekeeper.ntp.time_status & STA_NANO))
 			txc->offset /= NSEC_PER_USEC;
 	}
 
-	result = tk_ntp.time_state;	/* mostly `TIME_OK' */
+	result = timekeeper.ntp.time_state;	/* mostly `TIME_OK' */
 	/* check for errors */
-	if (is_error_status(tk_ntp.time_status))
+	if (is_error_status(timekeeper.ntp.time_status))
 		result = TIME_ERROR;
 
-	txc->freq = shift_right((tk_ntp.time_freq >> PPM_SCALE_INV_SHIFT) *
+	txc->freq = shift_right((timekeeper.ntp.time_freq >> PPM_SCALE_INV_SHIFT) *
 		PPM_SCALE_INV, NTP_SCALE_SHIFT);
-	txc->maxerror = tk_ntp.time_maxerror;
-	txc->esterror = tk_ntp.time_esterror;
-	txc->status = tk_ntp.time_status;
-	txc->constant = tk_ntp.time_constant;
+	txc->maxerror = timekeeper.ntp.time_maxerror;
+	txc->esterror = timekeeper.ntp.time_esterror;
+	txc->status = timekeeper.ntp.time_status;
+	txc->constant = timekeeper.ntp.time_constant;
 	txc->precision = 1;
 	txc->tolerance = MAXFREQ_SCALED / PPM_SCALE;
-	txc->tick = tk_ntp.tick_usec;
+	txc->tick = timekeeper.ntp.tick_usec;
 	txc->tai = *time_tai;
 
 	/* fill PPS status fields */
@@ -622,7 +613,7 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
 
 	txc->time.tv_sec = ts->tv_sec;
 	txc->time.tv_usec = ts->tv_nsec;
-	if (!(tk_ntp.time_status & STA_NANO))
+	if (!(timekeeper.ntp.time_status & STA_NANO))
 		txc->time.tv_usec /= NSEC_PER_USEC;
 
 	return result;
@@ -659,20 +650,20 @@ static inline struct pps_normtime pps_normalize_ts(struct timespec ts)
 /* get current phase correction and jitter */
 static inline long pps_phase_filter_get(long *jitter)
 {
-	*jitter = tk_ntp.pps.tf[0] - tk_ntp.pps.tf[1];
+	*jitter = timekeeper.ntp.pps.tf[0] - timekeeper.ntp.pps.tf[1];
 	if (*jitter < 0)
 		*jitter = -*jitter;
 
 	/* TODO: test various filters */
-	return tk_ntp.pps.tf[0];
+	return timekeeper.ntp.pps.tf[0];
 }
 
 /* add the sample to the phase filter */
 static inline void pps_phase_filter_add(long err)
 {
-	tk_ntp.pps.tf[2] = tk_ntp.pps.tf[1];
-	tk_ntp.pps.tf[1] = tk_ntp.pps.tf[0];
-	tk_ntp.pps.tf[0] = err;
+	timekeeper.ntp.pps.tf[2] = timekeeper.ntp.pps.tf[1];
+	timekeeper.ntp.pps.tf[1] = timekeeper.ntp.pps.tf[0];
+	timekeeper.ntp.pps.tf[0] = err;
 }
 
 /* decrease frequency calibration interval length.
@@ -680,11 +671,11 @@ static inline void pps_phase_filter_add(long err)
  */
 static inline void pps_dec_freq_interval(void)
 {
-	if (--tk_ntp.pps.intcnt <= -PPS_INTCOUNT) {
-		tk_ntp.pps.intcnt = -PPS_INTCOUNT;
-		if (tk_ntp.pps.shift > PPS_INTMIN) {
-			tk_ntp.pps.shift--;
-			tk_ntp.pps.intcnt = 0;
+	if (--timekeeper.ntp.pps.intcnt <= -PPS_INTCOUNT) {
+		timekeeper.ntp.pps.intcnt = -PPS_INTCOUNT;
+		if (timekeeper.ntp.pps.shift > PPS_INTMIN) {
+			timekeeper.ntp.pps.shift--;
+			timekeeper.ntp.pps.intcnt = 0;
 		}
 	}
 }
@@ -694,11 +685,11 @@ static inline void pps_dec_freq_interval(void)
  */
 static inline void pps_inc_freq_interval(void)
 {
-	if (++tk_ntp.pps.intcnt >= PPS_INTCOUNT) {
-		tk_ntp.pps.intcnt = PPS_INTCOUNT;
-		if (tk_ntp.pps.shift < PPS_INTMAX) {
-			tk_ntp.pps.shift++;
-			tk_ntp.pps.intcnt = 0;
+	if (++timekeeper.ntp.pps.intcnt >= PPS_INTCOUNT) {
+		timekeeper.ntp.pps.intcnt = PPS_INTCOUNT;
+		if (timekeeper.ntp.pps.shift < PPS_INTMAX) {
+			timekeeper.ntp.pps.shift++;
+			timekeeper.ntp.pps.intcnt = 0;
 		}
 	}
 }
@@ -718,9 +709,9 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	s64 ftemp;
 
 	/* check if the frequency interval was too long */
-	if (freq_norm.sec > (2 << tk_ntp.pps.shift)) {
-		tk_ntp.time_status |= STA_PPSERROR;
-		tk_ntp.pps.errcnt++;
+	if (freq_norm.sec > (2 << timekeeper.ntp.pps.shift)) {
+		timekeeper.ntp.time_status |= STA_PPSERROR;
+		timekeeper.ntp.pps.errcnt++;
 		pps_dec_freq_interval();
 		pr_err("hardpps: PPSERROR: interval too long - %ld s\n",
 				freq_norm.sec);
@@ -733,12 +724,12 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	 */
 	ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT,
 			freq_norm.sec);
-	delta = shift_right(ftemp - tk_ntp.pps.freq, NTP_SCALE_SHIFT);
-	tk_ntp.pps.freq = ftemp;
+	delta = shift_right(ftemp - timekeeper.ntp.pps.freq, NTP_SCALE_SHIFT);
+	timekeeper.ntp.pps.freq = ftemp;
 	if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
 		pr_warning("hardpps: PPSWANDER: change=%ld\n", delta);
-		tk_ntp.time_status |= STA_PPSWANDER;
-		tk_ntp.pps.stbcnt++;
+		timekeeper.ntp.time_status |= STA_PPSWANDER;
+		timekeeper.ntp.pps.stbcnt++;
 		pps_dec_freq_interval();
 	} else {	/* good sample */
 		pps_inc_freq_interval();
@@ -751,14 +742,14 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	delta_mod = delta;
 	if (delta_mod < 0)
 		delta_mod = -delta_mod;
-	tk_ntp.pps.stabil += (div_s64(((s64)delta_mod) <<
+	timekeeper.ntp.pps.stabil += (div_s64(((s64)delta_mod) <<
 		(NTP_SCALE_SHIFT - SHIFT_USEC),
-		NSEC_PER_USEC) - tk_ntp.pps.stabil) >> PPS_INTMIN;
+		NSEC_PER_USEC) - timekeeper.ntp.pps.stabil) >> PPS_INTMIN;
 
 	/* if enabled, the system clock frequency is updated */
-	if ((tk_ntp.time_status & STA_PPSFREQ) != 0 &&
-	    (tk_ntp.time_status & STA_FREQHOLD) == 0) {
-		tk_ntp.time_freq = tk_ntp.pps.freq;
+	if ((timekeeper.ntp.time_status & STA_PPSFREQ) != 0 &&
+	    (timekeeper.ntp.time_status & STA_FREQHOLD) == 0) {
+		timekeeper.ntp.time_freq = timekeeper.ntp.pps.freq;
 		ntp_update_frequency();
 	}
 
@@ -779,21 +770,21 @@ static void hardpps_update_phase(long error)
 	 * threshold, the sample is discarded; otherwise, if so enabled,
 	 * the time offset is updated.
 	 */
-	if (jitter > (tk_ntp.pps.jitter << PPS_POPCORN)) {
+	if (jitter > (timekeeper.ntp.pps.jitter << PPS_POPCORN)) {
 		pr_warning("hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
-		       jitter, (tk_ntp.pps.jitter << PPS_POPCORN));
-		tk_ntp.time_status |= STA_PPSJITTER;
-		tk_ntp.pps.jitcnt++;
-	} else if (tk_ntp.time_status & STA_PPSTIME) {
+		       jitter, (timekeeper.ntp.pps.jitter << PPS_POPCORN));
+		timekeeper.ntp.time_status |= STA_PPSJITTER;
+		timekeeper.ntp.pps.jitcnt++;
+	} else if (timekeeper.ntp.time_status & STA_PPSTIME) {
 		/* correct the time using the phase offset */
-		tk_ntp.time_offset =
+		timekeeper.ntp.time_offset =
 			div_s64(((s64)correction) << NTP_SCALE_SHIFT,
 				NTP_INTERVAL_FREQ);
 		/* cancel running adjtime() */
-		tk_ntp.time_adjust = 0;
+		timekeeper.ntp.time_adjust = 0;
 	}
 	/* update jitter */
-	tk_ntp.pps.jitter += (jitter - tk_ntp.pps.jitter) >> PPS_INTMIN;
+	timekeeper.ntp.pps.jitter += (jitter - timekeeper.ntp.pps.jitter) >> PPS_INTMIN;
 }
 
 /*
@@ -815,31 +806,31 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 	pts_norm = pps_normalize_ts(*phase_ts);
 
 	/* clear the error bits, they will be set again if needed */
-	tk_ntp.time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
+	timekeeper.ntp.time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
 
 	/* indicate signal presence */
-	tk_ntp.time_status |= STA_PPSSIGNAL;
-	tk_ntp.pps.valid = PPS_VALID;
+	timekeeper.ntp.time_status |= STA_PPSSIGNAL;
+	timekeeper.ntp.pps.valid = PPS_VALID;
 
 	/* when called for the first time,
 	 * just start the frequency interval */
-	if (unlikely(tk_ntp.pps.fbase.tv_sec == 0)) {
-		tk_ntp.pps.fbase = *raw_ts;
+	if (unlikely(timekeeper.ntp.pps.fbase.tv_sec == 0)) {
+		timekeeper.ntp.pps.fbase = *raw_ts;
 		return;
 	}
 
 	/* ok, now we have a base for frequency calculation */
 	freq_norm = pps_normalize_ts(timespec_sub(*raw_ts,
-		tk_ntp.pps.fbase));
+		timekeeper.ntp.pps.fbase));
 
 	/* check that the signal is in the range
 	 * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */
 	if ((freq_norm.sec == 0) ||
 			(freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
 			(freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
-		tk_ntp.time_status |= STA_PPSJITTER;
+		timekeeper.ntp.time_status |= STA_PPSJITTER;
 		/* restart the frequency calibration interval */
-		tk_ntp.pps.fbase = *raw_ts;
+		timekeeper.ntp.pps.fbase = *raw_ts;
 		pr_err("hardpps: PPSJITTER: bad pulse\n");
 		return;
 	}
@@ -847,10 +838,10 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 	/* signal is ok */
 
 	/* check if the current frequency interval is finished */
-	if (freq_norm.sec >= (1 << tk_ntp.pps.shift)) {
-		tk_ntp.pps.calcnt++;
+	if (freq_norm.sec >= (1 << timekeeper.ntp.pps.shift)) {
+		timekeeper.ntp.pps.calcnt++;
 		/* restart the frequency calibration interval */
-		tk_ntp.pps.fbase = *raw_ts;
+		timekeeper.ntp.pps.fbase = *raw_ts;
 		hardpps_update_freq(freq_norm);
 	}
 
@@ -861,8 +852,8 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 
 static int __init ntp_tick_adj_setup(char *str)
 {
-	tk_ntp.ntp_tick_adj = simple_strtol(str, NULL, 0);
-	tk_ntp.ntp_tick_adj <<= NTP_SCALE_SHIFT;
+	timekeeper.ntp.ntp_tick_adj = simple_strtol(str, NULL, 0);
+	timekeeper.ntp.ntp_tick_adj <<= NTP_SCALE_SHIFT;
 
 	return 1;
 }
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 947ba25..d1ecafb 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -31,7 +31,17 @@
 #define TK_MIRROR		(1 << 1)
 #define TK_CLOCK_WAS_SET	(1 << 2)
 
-static struct timekeeper timekeeper;
+struct timekeeper timekeeper = {
+	.ntp = {
+		.tick_usec = TICK_USEC,
+		.time_state = TIME_OK,
+		.time_status = STA_UNSYNC,
+		.time_constant = 2,
+		.time_maxerror = NTP_PHASE_LIMIT,
+		.time_esterror = NTP_PHASE_LIMIT,
+	},
+};
+
 static DEFINE_RAW_SPINLOCK(timekeeper_lock);
 static seqcount_t timekeeper_seq;
 static struct timekeeper shadow_timekeeper;
-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 4/7] Pass struct timekeeper_ntp as parameter from timekeeper to ntp
  2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
                   ` (2 preceding siblings ...)
  2013-09-14 19:47 ` [PATCH 3/7] Move ntp structure into struct timekeeper Mathieu Desnoyers
@ 2013-09-14 19:47 ` Mathieu Desnoyers
  2013-09-14 19:47 ` [PATCH 5/7] clocksource: add latch to clocksource Mathieu Desnoyers
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:47 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel
  Cc: Mathieu Desnoyers

This is in preparation for the latch synchronization scheme.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 kernel/time/ntp.c          |  472 ++++++++++++++++++++++----------------------
 kernel/time/ntp_internal.h |   16 +-
 kernel/time/timekeeping.c  |   17 +-
 3 files changed, 260 insertions(+), 245 deletions(-)

diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index d61e700..2a1b4ef 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -39,108 +39,108 @@
 /* PPS kernel consumer compensates the whole phase error immediately.
  * Otherwise, reduce the offset by a fixed factor times the time constant.
  */
-static inline s64 ntp_offset_chunk(s64 offset)
+static inline s64 ntp_offset_chunk(struct timekeeper_ntp *ntp, s64 offset)
 {
-	if (timekeeper.ntp.time_status & STA_PPSTIME
-			&& timekeeper.ntp.time_status & STA_PPSSIGNAL)
+	if (ntp->time_status & STA_PPSTIME
+			&& ntp->time_status & STA_PPSSIGNAL)
 		return offset;
 	else
-		return shift_right(offset, SHIFT_PLL + timekeeper.ntp.time_constant);
+		return shift_right(offset, SHIFT_PLL + ntp->time_constant);
 }
 
-static inline void pps_reset_freq_interval(void)
+static inline void pps_reset_freq_interval(struct timekeeper_ntp *ntp)
 {
 	/* the PPS calibration interval may end
 	   surprisingly early */
-	timekeeper.ntp.pps.shift = PPS_INTMIN;
-	timekeeper.ntp.pps.intcnt = 0;
+	ntp->pps.shift = PPS_INTMIN;
+	ntp->pps.intcnt = 0;
 }
 
 /**
  * pps_clear - Clears the PPS state variables
  */
-static inline void pps_clear(void)
+static inline void pps_clear(struct timekeeper_ntp *ntp)
 {
-	pps_reset_freq_interval();
-	timekeeper.ntp.pps.tf[0] = 0;
-	timekeeper.ntp.pps.tf[1] = 0;
-	timekeeper.ntp.pps.tf[2] = 0;
-	timekeeper.ntp.pps.fbase.tv_sec = timekeeper.ntp.pps.fbase.tv_nsec = 0;
-	timekeeper.ntp.pps.freq = 0;
+	pps_reset_freq_interval(ntp);
+	ntp->pps.tf[0] = 0;
+	ntp->pps.tf[1] = 0;
+	ntp->pps.tf[2] = 0;
+	ntp->pps.fbase.tv_sec = ntp->pps.fbase.tv_nsec = 0;
+	ntp->pps.freq = 0;
 }
 
 /* Decrease pps_valid to indicate that another second has passed since
  * the last PPS signal. When it reaches 0, indicate that PPS signal is
  * missing.
  */
-static inline void pps_dec_valid(void)
+static inline void pps_dec_valid(struct timekeeper_ntp *ntp)
 {
-	if (timekeeper.ntp.pps.valid > 0)
-		timekeeper.ntp.pps.valid--;
+	if (ntp->pps.valid > 0)
+		ntp->pps.valid--;
 	else {
-		timekeeper.ntp.time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
+		ntp->time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
 				 STA_PPSWANDER | STA_PPSERROR);
-		pps_clear();
+		pps_clear(ntp);
 	}
 }
 
-static inline void pps_set_freq(s64 freq)
+static inline void pps_set_freq(struct timekeeper_ntp *ntp, s64 freq)
 {
-	timekeeper.ntp.pps.freq = freq;
+	ntp->pps.freq = freq;
 }
 
-static inline int is_error_status(int status)
+static inline int is_error_status(struct timekeeper_ntp *ntp, int status)
 {
-	return (timekeeper.ntp.time_status & (STA_UNSYNC|STA_CLOCKERR))
+	return (ntp->time_status & (STA_UNSYNC|STA_CLOCKERR))
 		/* PPS signal lost when either PPS time or
 		 * PPS frequency synchronization requested
 		 */
-		|| ((timekeeper.ntp.time_status & (STA_PPSFREQ|STA_PPSTIME))
-			&& !(timekeeper.ntp.time_status & STA_PPSSIGNAL))
+		|| ((ntp->time_status & (STA_PPSFREQ|STA_PPSTIME))
+			&& !(ntp->time_status & STA_PPSSIGNAL))
 		/* PPS jitter exceeded when
 		 * PPS time synchronization requested */
-		|| ((timekeeper.ntp.time_status & (STA_PPSTIME|STA_PPSJITTER))
+		|| ((ntp->time_status & (STA_PPSTIME|STA_PPSJITTER))
 			== (STA_PPSTIME|STA_PPSJITTER))
 		/* PPS wander exceeded or calibration error when
 		 * PPS frequency synchronization requested
 		 */
-		|| ((timekeeper.ntp.time_status & STA_PPSFREQ)
-			&& (timekeeper.ntp.time_status & (STA_PPSWANDER|STA_PPSERROR)));
+		|| ((ntp->time_status & STA_PPSFREQ)
+			&& (ntp->time_status & (STA_PPSWANDER|STA_PPSERROR)));
 }
 
-static inline void pps_fill_timex(struct timex *txc)
+static inline void pps_fill_timex(struct timekeeper_ntp *ntp, struct timex *txc)
 {
-	txc->ppsfreq = shift_right((timekeeper.ntp.pps.freq >> PPM_SCALE_INV_SHIFT) *
+	txc->ppsfreq = shift_right((ntp->pps.freq >> PPM_SCALE_INV_SHIFT) *
 					 PPM_SCALE_INV, NTP_SCALE_SHIFT);
-	txc->jitter = timekeeper.ntp.pps.jitter;
-	if (!(timekeeper.ntp.time_status & STA_NANO))
+	txc->jitter = ntp->pps.jitter;
+	if (!(ntp->time_status & STA_NANO))
 		txc->jitter /= NSEC_PER_USEC;
-	txc->shift = timekeeper.ntp.pps.shift;
-	txc->stabil = timekeeper.ntp.pps.stabil;
-	txc->jitcnt = timekeeper.ntp.pps.jitcnt;
-	txc->calcnt = timekeeper.ntp.pps.calcnt;
-	txc->errcnt = timekeeper.ntp.pps.errcnt;
-	txc->stbcnt = timekeeper.ntp.pps.stbcnt;
+	txc->shift = ntp->pps.shift;
+	txc->stabil = ntp->pps.stabil;
+	txc->jitcnt = ntp->pps.jitcnt;
+	txc->calcnt = ntp->pps.calcnt;
+	txc->errcnt = ntp->pps.errcnt;
+	txc->stbcnt = ntp->pps.stbcnt;
 }
 
 #else /* !CONFIG_NTP_PPS */
 
-static inline s64 ntp_offset_chunk(s64 offset)
+static inline s64 ntp_offset_chunk(struct timekeeper_ntp *ntp, s64 offset)
 {
-	return shift_right(offset, SHIFT_PLL + timekeeper.ntp.time_constant);
+	return shift_right(offset, SHIFT_PLL + ntp->time_constant);
 }
 
-static inline void pps_reset_freq_interval(void) {}
-static inline void pps_clear(void) {}
-static inline void pps_dec_valid(void) {}
-static inline void pps_set_freq(s64 freq) {}
+static inline void pps_reset_freq_interval(struct timekeeper_ntp *ntp) {}
+static inline void pps_clear(struct timekeeper_ntp *ntp) {}
+static inline void pps_dec_valid(struct timekeeper_ntp *ntp) {}
+static inline void pps_set_freq(struct timekeeper_ntp *ntp, s64 freq) {}
 
-static inline int is_error_status(int status)
+static inline int is_error_status(struct timekeeper_ntp *ntp, int status)
 {
 	return status & (STA_UNSYNC|STA_CLOCKERR);
 }
 
-static inline void pps_fill_timex(struct timex *txc)
+static inline void pps_fill_timex(struct timekeeper_ntp *ntp, struct timex *txc)
 {
 	/* PPS is not implemented, so these are zero */
 	txc->ppsfreq	   = 0;
@@ -160,9 +160,9 @@ static inline void pps_fill_timex(struct timex *txc)
  * ntp_synced - Returns 1 if the NTP status is not UNSYNC
  *
  */
-static inline int ntp_synced(void)
+static inline int ntp_synced(struct timekeeper_ntp *ntp)
 {
-	return !(timekeeper.ntp.time_status & STA_UNSYNC);
+	return !(ntp->time_status & STA_UNSYNC);
 }
 
 
@@ -171,56 +171,57 @@ static inline int ntp_synced(void)
  */
 
 /*
- * Update (timekeeper.ntp.tick_length, timekeeper.ntp.tick_length_base, timekeeper.ntp.tick_nsec),
- * based on (timekeeper.ntp.tick_usec, timekeeper.ntp.ntp_tick_adj, timekeeper.ntp.time_freq):
+ * Update (ntp->tick_length, ntp->tick_length_base, ntp->tick_nsec),
+ * based on (ntp->tick_usec, ntp->ntp_tick_adj, ntp->time_freq):
  */
-static void ntp_update_frequency(void)
+static void ntp_update_frequency(struct timekeeper_ntp *ntp)
 {
 	u64 second_length;
 	u64 new_base;
 
-	second_length = (u64)(timekeeper.ntp.tick_usec * NSEC_PER_USEC * USER_HZ)
+	second_length = (u64)(ntp->tick_usec * NSEC_PER_USEC * USER_HZ)
 						<< NTP_SCALE_SHIFT;
 
-	second_length += timekeeper.ntp.ntp_tick_adj;
-	second_length += timekeeper.ntp.time_freq;
+	second_length += ntp->ntp_tick_adj;
+	second_length += ntp->time_freq;
 
-	timekeeper.ntp.tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
+	ntp->tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
 	new_base = div_u64(second_length, NTP_INTERVAL_FREQ);
 
 	/*
 	 * Don't wait for the next second_overflow, apply
 	 * the change to the tick length immediately:
 	 */
-	timekeeper.ntp.tick_length += new_base - timekeeper.ntp.tick_length_base;
-	timekeeper.ntp.tick_length_base = new_base;
+	ntp->tick_length += new_base - ntp->tick_length_base;
+	ntp->tick_length_base = new_base;
 }
 
-static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
+static inline s64 ntp_update_offset_fll(struct timekeeper_ntp *ntp,
+		s64 offset64, long secs)
 {
-	timekeeper.ntp.time_status &= ~STA_MODE;
+	ntp->time_status &= ~STA_MODE;
 
 	if (secs < MINSEC)
 		return 0;
 
-	if (!(timekeeper.ntp.time_status & STA_FLL) && (secs <= MAXSEC))
+	if (!(ntp->time_status & STA_FLL) && (secs <= MAXSEC))
 		return 0;
 
-	timekeeper.ntp.time_status |= STA_MODE;
+	ntp->time_status |= STA_MODE;
 
 	return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);
 }
 
-static void ntp_update_offset(long offset)
+static void ntp_update_offset(struct timekeeper_ntp *ntp, long offset)
 {
 	s64 freq_adj;
 	s64 offset64;
 	long secs;
 
-	if (!(timekeeper.ntp.time_status & STA_PLL))
+	if (!(ntp->time_status & STA_PLL))
 		return;
 
-	if (!(timekeeper.ntp.time_status & STA_NANO))
+	if (!(ntp->time_status & STA_NANO))
 		offset *= NSEC_PER_USEC;
 
 	/*
@@ -234,57 +235,57 @@ static void ntp_update_offset(long offset)
 	 * Select how the frequency is to be controlled
 	 * and in which mode (PLL or FLL).
 	 */
-	secs = get_seconds() - timekeeper.ntp.time_reftime;
-	if (unlikely(timekeeper.ntp.time_status & STA_FREQHOLD))
+	secs = get_seconds() - ntp->time_reftime;
+	if (unlikely(ntp->time_status & STA_FREQHOLD))
 		secs = 0;
 
-	timekeeper.ntp.time_reftime = get_seconds();
+	ntp->time_reftime = get_seconds();
 
 	offset64    = offset;
-	freq_adj    = ntp_update_offset_fll(offset64, secs);
+	freq_adj    = ntp_update_offset_fll(ntp, offset64, secs);
 
 	/*
 	 * Clamp update interval to reduce PLL gain with low
 	 * sampling rate (e.g. intermittent network connection)
 	 * to avoid instability.
 	 */
-	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + timekeeper.ntp.time_constant)))
-		secs = 1 << (SHIFT_PLL + 1 + timekeeper.ntp.time_constant);
+	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + ntp->time_constant)))
+		secs = 1 << (SHIFT_PLL + 1 + ntp->time_constant);
 
 	freq_adj    += (offset64 * secs) <<
-		(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + timekeeper.ntp.time_constant));
+		(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + ntp->time_constant));
 
-	freq_adj    = min(freq_adj + timekeeper.ntp.time_freq, MAXFREQ_SCALED);
+	freq_adj    = min(freq_adj + ntp->time_freq, MAXFREQ_SCALED);
 
-	timekeeper.ntp.time_freq   = max(freq_adj, -MAXFREQ_SCALED);
+	ntp->time_freq   = max(freq_adj, -MAXFREQ_SCALED);
 
-	timekeeper.ntp.time_offset = div_s64(offset64 << NTP_SCALE_SHIFT,
+	ntp->time_offset = div_s64(offset64 << NTP_SCALE_SHIFT,
 		NTP_INTERVAL_FREQ);
 }
 
 /**
  * ntp_clear - Clears the NTP state variables
  */
-void ntp_clear(void)
+void ntp_clear(struct timekeeper_ntp *ntp)
 {
-	timekeeper.ntp.time_adjust	= 0;		/* stop active adjtime() */
-	timekeeper.ntp.time_status	|= STA_UNSYNC;
-	timekeeper.ntp.time_maxerror	= NTP_PHASE_LIMIT;
-	timekeeper.ntp.time_esterror	= NTP_PHASE_LIMIT;
+	ntp->time_adjust	= 0;		/* stop active adjtime() */
+	ntp->time_status	|= STA_UNSYNC;
+	ntp->time_maxerror	= NTP_PHASE_LIMIT;
+	ntp->time_esterror	= NTP_PHASE_LIMIT;
 
-	ntp_update_frequency();
+	ntp_update_frequency(ntp);
 
-	timekeeper.ntp.tick_length	= timekeeper.ntp.tick_length_base;
-	timekeeper.ntp.time_offset	= 0;
+	ntp->tick_length	= ntp->tick_length_base;
+	ntp->time_offset	= 0;
 
 	/* Clear PPS state variables */
-	pps_clear();
+	pps_clear(ntp);
 }
 
 
-u64 ntp_tick_length(void)
+u64 ntp_tick_length(struct timekeeper_ntp *ntp)
 {
-	return timekeeper.ntp.tick_length;
+	return ntp->tick_length;
 }
 
 
@@ -298,7 +299,7 @@ u64 ntp_tick_length(void)
  *
  * Also handles leap second processing, and returns leap offset
  */
-int second_overflow(unsigned long secs)
+int second_overflow(struct timekeeper_ntp *ntp, unsigned long secs)
 {
 	s64 delta;
 	int leap = 0;
@@ -308,80 +309,80 @@ int second_overflow(unsigned long secs)
 	 * day, the system clock is set back one second; if in leap-delete
 	 * state, the system clock is set ahead one second.
 	 */
-	switch (timekeeper.ntp.time_state) {
+	switch (ntp->time_state) {
 	case TIME_OK:
-		if (timekeeper.ntp.time_status & STA_INS)
-			timekeeper.ntp.time_state = TIME_INS;
-		else if (timekeeper.ntp.time_status & STA_DEL)
-			timekeeper.ntp.time_state = TIME_DEL;
+		if (ntp->time_status & STA_INS)
+			ntp->time_state = TIME_INS;
+		else if (ntp->time_status & STA_DEL)
+			ntp->time_state = TIME_DEL;
 		break;
 	case TIME_INS:
-		if (!(timekeeper.ntp.time_status & STA_INS))
-			timekeeper.ntp.time_state = TIME_OK;
+		if (!(ntp->time_status & STA_INS))
+			ntp->time_state = TIME_OK;
 		else if (secs % 86400 == 0) {
 			leap = -1;
-			timekeeper.ntp.time_state = TIME_OOP;
+			ntp->time_state = TIME_OOP;
 			printk(KERN_NOTICE
 				"Clock: inserting leap second 23:59:60 UTC\n");
 		}
 		break;
 	case TIME_DEL:
-		if (!(timekeeper.ntp.time_status & STA_DEL))
-			timekeeper.ntp.time_state = TIME_OK;
+		if (!(ntp->time_status & STA_DEL))
+			ntp->time_state = TIME_OK;
 		else if ((secs + 1) % 86400 == 0) {
 			leap = 1;
-			timekeeper.ntp.time_state = TIME_WAIT;
+			ntp->time_state = TIME_WAIT;
 			printk(KERN_NOTICE
 				"Clock: deleting leap second 23:59:59 UTC\n");
 		}
 		break;
 	case TIME_OOP:
-		timekeeper.ntp.time_state = TIME_WAIT;
+		ntp->time_state = TIME_WAIT;
 		break;
 
 	case TIME_WAIT:
-		if (!(timekeeper.ntp.time_status & (STA_INS | STA_DEL)))
-			timekeeper.ntp.time_state = TIME_OK;
+		if (!(ntp->time_status & (STA_INS | STA_DEL)))
+			ntp->time_state = TIME_OK;
 		break;
 	}
 
 
 	/* Bump the maxerror field */
-	timekeeper.ntp.time_maxerror += MAXFREQ / NSEC_PER_USEC;
-	if (timekeeper.ntp.time_maxerror > NTP_PHASE_LIMIT) {
-		timekeeper.ntp.time_maxerror = NTP_PHASE_LIMIT;
-		timekeeper.ntp.time_status |= STA_UNSYNC;
+	ntp->time_maxerror += MAXFREQ / NSEC_PER_USEC;
+	if (ntp->time_maxerror > NTP_PHASE_LIMIT) {
+		ntp->time_maxerror = NTP_PHASE_LIMIT;
+		ntp->time_status |= STA_UNSYNC;
 	}
 
 	/* Compute the phase adjustment for the next second */
-	timekeeper.ntp.tick_length = timekeeper.ntp.tick_length_base;
+	ntp->tick_length = ntp->tick_length_base;
 
-	delta = ntp_offset_chunk(timekeeper.ntp.time_offset);
-	timekeeper.ntp.time_offset -= delta;
-	timekeeper.ntp.tick_length += delta;
+	delta = ntp_offset_chunk(ntp, ntp->time_offset);
+	ntp->time_offset -= delta;
+	ntp->tick_length += delta;
 
 	/* Check PPS signal */
-	pps_dec_valid();
+	pps_dec_valid(ntp);
 
-	if (!timekeeper.ntp.time_adjust)
+	if (!ntp->time_adjust)
 		goto out;
 
-	if (timekeeper.ntp.time_adjust > MAX_TICKADJ) {
-		timekeeper.ntp.time_adjust -= MAX_TICKADJ;
-		timekeeper.ntp.tick_length += MAX_TICKADJ_SCALED;
+	if (ntp->time_adjust > MAX_TICKADJ) {
+		ntp->time_adjust -= MAX_TICKADJ;
+		ntp->tick_length += MAX_TICKADJ_SCALED;
 		goto out;
 	}
 
-	if (timekeeper.ntp.time_adjust < -MAX_TICKADJ) {
-		timekeeper.ntp.time_adjust += MAX_TICKADJ;
-		timekeeper.ntp.tick_length -= MAX_TICKADJ_SCALED;
+	if (ntp->time_adjust < -MAX_TICKADJ) {
+		ntp->time_adjust += MAX_TICKADJ;
+		ntp->tick_length -= MAX_TICKADJ_SCALED;
 		goto out;
 	}
 
-	timekeeper.ntp.tick_length +=
-		(s64)(timekeeper.ntp.time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
+	ntp->tick_length +=
+		(s64)(ntp->time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)
 							 << NTP_SCALE_SHIFT;
-	timekeeper.ntp.time_adjust = 0;
+	ntp->time_adjust = 0;
 
 out:
 	return leap;
@@ -394,6 +395,7 @@ static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
 
 static void sync_cmos_clock(struct work_struct *work)
 {
+	struct timekeeper_ntp *ntp = &timekeeper.ntp;
 	struct timespec now, next;
 	int fail = 1;
 
@@ -404,7 +406,7 @@ static void sync_cmos_clock(struct work_struct *work)
 	 * This code is run on a timer.  If the clock is set, that timer
 	 * may not expire at the correct time.  Thus, we adjust...
 	 */
-	if (!ntp_synced()) {
+	if (!ntp_synced(ntp)) {
 		/*
 		 * Not synced, exit, do not restart a timer (if one is
 		 * running, let it run out).
@@ -413,7 +415,7 @@ static void sync_cmos_clock(struct work_struct *work)
 	}
 
 	getnstimeofday(&now);
-	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= timekeeper.ntp.tick_nsec / 2) {
+	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= ntp->tick_nsec / 2) {
 		struct timespec adjust = now;
 
 		fail = -ENODEV;
@@ -457,74 +459,76 @@ void ntp_notify_cmos_timer(void) { }
 /*
  * Propagate a new txc->status value into the NTP state:
  */
-static inline void process_adj_status(struct timex *txc, struct timespec *ts)
+static inline void process_adj_status(struct timekeeper_ntp *ntp,
+		struct timex *txc, struct timespec *ts)
 {
-	if ((timekeeper.ntp.time_status & STA_PLL) && !(txc->status & STA_PLL)) {
-		timekeeper.ntp.time_state = TIME_OK;
-		timekeeper.ntp.time_status = STA_UNSYNC;
+	if ((ntp->time_status & STA_PLL) && !(txc->status & STA_PLL)) {
+		ntp->time_state = TIME_OK;
+		ntp->time_status = STA_UNSYNC;
 		/* restart PPS frequency calibration */
-		pps_reset_freq_interval();
+		pps_reset_freq_interval(ntp);
 	}
 
 	/*
 	 * If we turn on PLL adjustments then reset the
 	 * reference time to current time.
 	 */
-	if (!(timekeeper.ntp.time_status & STA_PLL) && (txc->status & STA_PLL))
-		timekeeper.ntp.time_reftime = get_seconds();
+	if (!(ntp->time_status & STA_PLL) && (txc->status & STA_PLL))
+		ntp->time_reftime = get_seconds();
 
 	/* only set allowed bits */
-	timekeeper.ntp.time_status &= STA_RONLY;
-	timekeeper.ntp.time_status |= txc->status & ~STA_RONLY;
+	ntp->time_status &= STA_RONLY;
+	ntp->time_status |= txc->status & ~STA_RONLY;
 }
 
 
-static inline void process_adjtimex_modes(struct timex *txc,
+static inline void process_adjtimex_modes(struct timekeeper_ntp *ntp,
+						struct timex *txc,
 						struct timespec *ts,
 						s32 *time_tai)
 {
 	if (txc->modes & ADJ_STATUS)
-		process_adj_status(txc, ts);
+		process_adj_status(ntp, txc, ts);
 
 	if (txc->modes & ADJ_NANO)
-		timekeeper.ntp.time_status |= STA_NANO;
+		ntp->time_status |= STA_NANO;
 
 	if (txc->modes & ADJ_MICRO)
-		timekeeper.ntp.time_status &= ~STA_NANO;
+		ntp->time_status &= ~STA_NANO;
 
 	if (txc->modes & ADJ_FREQUENCY) {
-		timekeeper.ntp.time_freq = txc->freq * PPM_SCALE;
-		timekeeper.ntp.time_freq = min(timekeeper.ntp.time_freq, MAXFREQ_SCALED);
-		timekeeper.ntp.time_freq = max(timekeeper.ntp.time_freq, -MAXFREQ_SCALED);
-		/* update timekeeper.ntp.pps.freq */
-		pps_set_freq(timekeeper.ntp.time_freq);
+		ntp->time_freq = txc->freq * PPM_SCALE;
+		ntp->time_freq = min(ntp->time_freq, MAXFREQ_SCALED);
+		ntp->time_freq = max(ntp->time_freq, -MAXFREQ_SCALED);
+		/* update ntp->pps.freq */
+		pps_set_freq(ntp, ntp->time_freq);
 	}
 
 	if (txc->modes & ADJ_MAXERROR)
-		timekeeper.ntp.time_maxerror = txc->maxerror;
+		ntp->time_maxerror = txc->maxerror;
 
 	if (txc->modes & ADJ_ESTERROR)
-		timekeeper.ntp.time_esterror = txc->esterror;
+		ntp->time_esterror = txc->esterror;
 
 	if (txc->modes & ADJ_TIMECONST) {
-		timekeeper.ntp.time_constant = txc->constant;
-		if (!(timekeeper.ntp.time_status & STA_NANO))
-			timekeeper.ntp.time_constant += 4;
-		timekeeper.ntp.time_constant = min(timekeeper.ntp.time_constant, (long)MAXTC);
-		timekeeper.ntp.time_constant = max(timekeeper.ntp.time_constant, 0l);
+		ntp->time_constant = txc->constant;
+		if (!(ntp->time_status & STA_NANO))
+			ntp->time_constant += 4;
+		ntp->time_constant = min(ntp->time_constant, (long)MAXTC);
+		ntp->time_constant = max(ntp->time_constant, 0l);
 	}
 
 	if (txc->modes & ADJ_TAI && txc->constant > 0)
 		*time_tai = txc->constant;
 
 	if (txc->modes & ADJ_OFFSET)
-		ntp_update_offset(txc->offset);
+		ntp_update_offset(ntp, txc->offset);
 
 	if (txc->modes & ADJ_TICK)
-		timekeeper.ntp.tick_usec = txc->tick;
+		ntp->tick_usec = txc->tick;
 
 	if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
-		ntp_update_frequency();
+		ntp_update_frequency(ntp);
 }
 
 
@@ -566,54 +570,55 @@ int ntp_validate_timex(struct timex *txc)
  * adjtimex mainly allows reading (and writing, if superuser) of
  * kernel time-keeping variables. used by xntpd.
  */
-int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
+int __do_adjtimex(struct timekeeper_ntp *ntp, struct timex *txc,
+		struct timespec *ts, s32 *time_tai)
 {
 	int result;
 
 	if (txc->modes & ADJ_ADJTIME) {
-		long save_adjust = timekeeper.ntp.time_adjust;
+		long save_adjust = ntp->time_adjust;
 
 		if (!(txc->modes & ADJ_OFFSET_READONLY)) {
 			/* adjtime() is independent from ntp_adjtime() */
-			timekeeper.ntp.time_adjust = txc->offset;
-			ntp_update_frequency();
+			ntp->time_adjust = txc->offset;
+			ntp_update_frequency(ntp);
 		}
 		txc->offset = save_adjust;
 	} else {
 
 		/* If there are input parameters, then process them: */
 		if (txc->modes)
-			process_adjtimex_modes(txc, ts, time_tai);
+			process_adjtimex_modes(ntp, txc, ts, time_tai);
 
 		txc->offset =
-			shift_right(timekeeper.ntp.time_offset * NTP_INTERVAL_FREQ,
+			shift_right(ntp->time_offset * NTP_INTERVAL_FREQ,
 				  NTP_SCALE_SHIFT);
-		if (!(timekeeper.ntp.time_status & STA_NANO))
+		if (!(ntp->time_status & STA_NANO))
 			txc->offset /= NSEC_PER_USEC;
 	}
 
-	result = timekeeper.ntp.time_state;	/* mostly `TIME_OK' */
+	result = ntp->time_state;	/* mostly `TIME_OK' */
 	/* check for errors */
-	if (is_error_status(timekeeper.ntp.time_status))
+	if (is_error_status(ntp, ntp->time_status))
 		result = TIME_ERROR;
 
-	txc->freq = shift_right((timekeeper.ntp.time_freq >> PPM_SCALE_INV_SHIFT) *
+	txc->freq = shift_right((ntp->time_freq >> PPM_SCALE_INV_SHIFT) *
 		PPM_SCALE_INV, NTP_SCALE_SHIFT);
-	txc->maxerror = timekeeper.ntp.time_maxerror;
-	txc->esterror = timekeeper.ntp.time_esterror;
-	txc->status = timekeeper.ntp.time_status;
-	txc->constant = timekeeper.ntp.time_constant;
+	txc->maxerror = ntp->time_maxerror;
+	txc->esterror = ntp->time_esterror;
+	txc->status = ntp->time_status;
+	txc->constant = ntp->time_constant;
 	txc->precision = 1;
 	txc->tolerance = MAXFREQ_SCALED / PPM_SCALE;
-	txc->tick = timekeeper.ntp.tick_usec;
+	txc->tick = ntp->tick_usec;
 	txc->tai = *time_tai;
 
 	/* fill PPS status fields */
-	pps_fill_timex(txc);
+	pps_fill_timex(ntp, txc);
 
 	txc->time.tv_sec = ts->tv_sec;
 	txc->time.tv_usec = ts->tv_nsec;
-	if (!(timekeeper.ntp.time_status & STA_NANO))
+	if (!(ntp->time_status & STA_NANO))
 		txc->time.tv_usec /= NSEC_PER_USEC;
 
 	return result;
@@ -648,34 +653,35 @@ static inline struct pps_normtime pps_normalize_ts(struct timespec ts)
 }
 
 /* get current phase correction and jitter */
-static inline long pps_phase_filter_get(long *jitter)
+static inline long pps_phase_filter_get(struct timekeeper_ntp *ntp,
+		long *jitter)
 {
-	*jitter = timekeeper.ntp.pps.tf[0] - timekeeper.ntp.pps.tf[1];
+	*jitter = ntp->pps.tf[0] - ntp->pps.tf[1];
 	if (*jitter < 0)
 		*jitter = -*jitter;
 
 	/* TODO: test various filters */
-	return timekeeper.ntp.pps.tf[0];
+	return ntp->pps.tf[0];
 }
 
 /* add the sample to the phase filter */
-static inline void pps_phase_filter_add(long err)
+static inline void pps_phase_filter_add(struct timekeeper_ntp *ntp, long err)
 {
-	timekeeper.ntp.pps.tf[2] = timekeeper.ntp.pps.tf[1];
-	timekeeper.ntp.pps.tf[1] = timekeeper.ntp.pps.tf[0];
-	timekeeper.ntp.pps.tf[0] = err;
+	ntp->pps.tf[2] = ntp->pps.tf[1];
+	ntp->pps.tf[1] = ntp->pps.tf[0];
+	ntp->pps.tf[0] = err;
 }
 
 /* decrease frequency calibration interval length.
  * It is halved after four consecutive unstable intervals.
  */
-static inline void pps_dec_freq_interval(void)
+static inline void pps_dec_freq_interval(struct timekeeper_ntp *ntp)
 {
-	if (--timekeeper.ntp.pps.intcnt <= -PPS_INTCOUNT) {
-		timekeeper.ntp.pps.intcnt = -PPS_INTCOUNT;
-		if (timekeeper.ntp.pps.shift > PPS_INTMIN) {
-			timekeeper.ntp.pps.shift--;
-			timekeeper.ntp.pps.intcnt = 0;
+	if (--ntp->pps.intcnt <= -PPS_INTCOUNT) {
+		ntp->pps.intcnt = -PPS_INTCOUNT;
+		if (ntp->pps.shift > PPS_INTMIN) {
+			ntp->pps.shift--;
+			ntp->pps.intcnt = 0;
 		}
 	}
 }
@@ -683,13 +689,13 @@ static inline void pps_dec_freq_interval(void)
 /* increase frequency calibration interval length.
  * It is doubled after four consecutive stable intervals.
  */
-static inline void pps_inc_freq_interval(void)
+static inline void pps_inc_freq_interval(struct timekeeper_ntp *ntp)
 {
-	if (++timekeeper.ntp.pps.intcnt >= PPS_INTCOUNT) {
-		timekeeper.ntp.pps.intcnt = PPS_INTCOUNT;
-		if (timekeeper.ntp.pps.shift < PPS_INTMAX) {
-			timekeeper.ntp.pps.shift++;
-			timekeeper.ntp.pps.intcnt = 0;
+	if (++ntp->pps.intcnt >= PPS_INTCOUNT) {
+		ntp->pps.intcnt = PPS_INTCOUNT;
+		if (ntp->pps.shift < PPS_INTMAX) {
+			ntp->pps.shift++;
+			ntp->pps.intcnt = 0;
 		}
 	}
 }
@@ -703,16 +709,17 @@ static inline void pps_inc_freq_interval(void)
  * too long, the data are discarded.
  * Returns the difference between old and new frequency values.
  */
-static long hardpps_update_freq(struct pps_normtime freq_norm)
+static long hardpps_update_freq(struct timekeeper_ntp *ntp,
+		struct pps_normtime freq_norm)
 {
 	long delta, delta_mod;
 	s64 ftemp;
 
 	/* check if the frequency interval was too long */
-	if (freq_norm.sec > (2 << timekeeper.ntp.pps.shift)) {
-		timekeeper.ntp.time_status |= STA_PPSERROR;
-		timekeeper.ntp.pps.errcnt++;
-		pps_dec_freq_interval();
+	if (freq_norm.sec > (2 << ntp->pps.shift)) {
+		ntp->time_status |= STA_PPSERROR;
+		ntp->pps.errcnt++;
+		pps_dec_freq_interval(ntp);
 		pr_err("hardpps: PPSERROR: interval too long - %ld s\n",
 				freq_norm.sec);
 		return 0;
@@ -724,15 +731,15 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	 */
 	ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT,
 			freq_norm.sec);
-	delta = shift_right(ftemp - timekeeper.ntp.pps.freq, NTP_SCALE_SHIFT);
-	timekeeper.ntp.pps.freq = ftemp;
+	delta = shift_right(ftemp - ntp->pps.freq, NTP_SCALE_SHIFT);
+	ntp->pps.freq = ftemp;
 	if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
 		pr_warning("hardpps: PPSWANDER: change=%ld\n", delta);
-		timekeeper.ntp.time_status |= STA_PPSWANDER;
-		timekeeper.ntp.pps.stbcnt++;
-		pps_dec_freq_interval();
+		ntp->time_status |= STA_PPSWANDER;
+		ntp->pps.stbcnt++;
+		pps_dec_freq_interval(ntp);
 	} else {	/* good sample */
-		pps_inc_freq_interval();
+		pps_inc_freq_interval(ntp);
 	}
 
 	/* the stability metric is calculated as the average of recent
@@ -742,49 +749,49 @@ static long hardpps_update_freq(struct pps_normtime freq_norm)
 	delta_mod = delta;
 	if (delta_mod < 0)
 		delta_mod = -delta_mod;
-	timekeeper.ntp.pps.stabil += (div_s64(((s64)delta_mod) <<
+	ntp->pps.stabil += (div_s64(((s64)delta_mod) <<
 		(NTP_SCALE_SHIFT - SHIFT_USEC),
-		NSEC_PER_USEC) - timekeeper.ntp.pps.stabil) >> PPS_INTMIN;
+		NSEC_PER_USEC) - ntp->pps.stabil) >> PPS_INTMIN;
 
 	/* if enabled, the system clock frequency is updated */
-	if ((timekeeper.ntp.time_status & STA_PPSFREQ) != 0 &&
-	    (timekeeper.ntp.time_status & STA_FREQHOLD) == 0) {
-		timekeeper.ntp.time_freq = timekeeper.ntp.pps.freq;
-		ntp_update_frequency();
+	if ((ntp->time_status & STA_PPSFREQ) != 0 &&
+	    (ntp->time_status & STA_FREQHOLD) == 0) {
+		ntp->time_freq = ntp->pps.freq;
+		ntp_update_frequency(ntp);
 	}
 
 	return delta;
 }
 
 /* correct REALTIME clock phase error against PPS signal */
-static void hardpps_update_phase(long error)
+static void hardpps_update_phase(struct timekeeper_ntp *ntp, long error)
 {
 	long correction = -error;
 	long jitter;
 
 	/* add the sample to the median filter */
-	pps_phase_filter_add(correction);
-	correction = pps_phase_filter_get(&jitter);
+	pps_phase_filter_add(ntp, correction);
+	correction = pps_phase_filter_get(ntp, &jitter);
 
 	/* Nominal jitter is due to PPS signal noise. If it exceeds the
 	 * threshold, the sample is discarded; otherwise, if so enabled,
 	 * the time offset is updated.
 	 */
-	if (jitter > (timekeeper.ntp.pps.jitter << PPS_POPCORN)) {
+	if (jitter > (ntp->pps.jitter << PPS_POPCORN)) {
 		pr_warning("hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
-		       jitter, (timekeeper.ntp.pps.jitter << PPS_POPCORN));
-		timekeeper.ntp.time_status |= STA_PPSJITTER;
-		timekeeper.ntp.pps.jitcnt++;
-	} else if (timekeeper.ntp.time_status & STA_PPSTIME) {
+		       jitter, (ntp->pps.jitter << PPS_POPCORN));
+		ntp->time_status |= STA_PPSJITTER;
+		ntp->pps.jitcnt++;
+	} else if (ntp->time_status & STA_PPSTIME) {
 		/* correct the time using the phase offset */
-		timekeeper.ntp.time_offset =
+		ntp->time_offset =
 			div_s64(((s64)correction) << NTP_SCALE_SHIFT,
 				NTP_INTERVAL_FREQ);
 		/* cancel running adjtime() */
-		timekeeper.ntp.time_adjust = 0;
+		ntp->time_adjust = 0;
 	}
 	/* update jitter */
-	timekeeper.ntp.pps.jitter += (jitter - timekeeper.ntp.pps.jitter) >> PPS_INTMIN;
+	ntp->pps.jitter += (jitter - ntp->pps.jitter) >> PPS_INTMIN;
 }
 
 /*
@@ -799,38 +806,39 @@ static void hardpps_update_phase(long error)
  * This code is based on David Mills's reference nanokernel
  * implementation. It was mostly rewritten but keeps the same idea.
  */
-void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
+void __hardpps(struct timekeeper_ntp *ntp, const struct timespec *phase_ts,
+		const struct timespec *raw_ts)
 {
 	struct pps_normtime pts_norm, freq_norm;
 
 	pts_norm = pps_normalize_ts(*phase_ts);
 
 	/* clear the error bits, they will be set again if needed */
-	timekeeper.ntp.time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
+	ntp->time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
 
 	/* indicate signal presence */
-	timekeeper.ntp.time_status |= STA_PPSSIGNAL;
-	timekeeper.ntp.pps.valid = PPS_VALID;
+	ntp->time_status |= STA_PPSSIGNAL;
+	ntp->pps.valid = PPS_VALID;
 
 	/* when called for the first time,
 	 * just start the frequency interval */
-	if (unlikely(timekeeper.ntp.pps.fbase.tv_sec == 0)) {
-		timekeeper.ntp.pps.fbase = *raw_ts;
+	if (unlikely(ntp->pps.fbase.tv_sec == 0)) {
+		ntp->pps.fbase = *raw_ts;
 		return;
 	}
 
 	/* ok, now we have a base for frequency calculation */
 	freq_norm = pps_normalize_ts(timespec_sub(*raw_ts,
-		timekeeper.ntp.pps.fbase));
+		ntp->pps.fbase));
 
 	/* check that the signal is in the range
 	 * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */
 	if ((freq_norm.sec == 0) ||
 			(freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
 			(freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
-		timekeeper.ntp.time_status |= STA_PPSJITTER;
+		ntp->time_status |= STA_PPSJITTER;
 		/* restart the frequency calibration interval */
-		timekeeper.ntp.pps.fbase = *raw_ts;
+		ntp->pps.fbase = *raw_ts;
 		pr_err("hardpps: PPSJITTER: bad pulse\n");
 		return;
 	}
@@ -838,29 +846,31 @@ void __hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 	/* signal is ok */
 
 	/* check if the current frequency interval is finished */
-	if (freq_norm.sec >= (1 << timekeeper.ntp.pps.shift)) {
-		timekeeper.ntp.pps.calcnt++;
+	if (freq_norm.sec >= (1 << ntp->pps.shift)) {
+		ntp->pps.calcnt++;
 		/* restart the frequency calibration interval */
-		timekeeper.ntp.pps.fbase = *raw_ts;
-		hardpps_update_freq(freq_norm);
+		ntp->pps.fbase = *raw_ts;
+		hardpps_update_freq(ntp, freq_norm);
 	}
 
-	hardpps_update_phase(pts_norm.nsec);
+	hardpps_update_phase(ntp, pts_norm.nsec);
 
 }
 #endif	/* CONFIG_NTP_PPS */
 
 static int __init ntp_tick_adj_setup(char *str)
 {
-	timekeeper.ntp.ntp_tick_adj = simple_strtol(str, NULL, 0);
-	timekeeper.ntp.ntp_tick_adj <<= NTP_SCALE_SHIFT;
+	struct timekeeper_ntp *ntp = &timekeeper.ntp;
+
+	ntp->ntp_tick_adj = simple_strtol(str, NULL, 0);
+	ntp->ntp_tick_adj <<= NTP_SCALE_SHIFT;
 
 	return 1;
 }
 
 __setup("ntp_tick_adj=", ntp_tick_adj_setup);
 
-void __init ntp_init(void)
+void __init ntp_init(struct timekeeper_ntp *ntp)
 {
-	ntp_clear();
+	ntp_clear(ntp);
 }
diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h
index 1950cb4..970e260 100644
--- a/kernel/time/ntp_internal.h
+++ b/kernel/time/ntp_internal.h
@@ -1,12 +1,16 @@
 #ifndef _LINUX_NTP_INTERNAL_H
 #define _LINUX_NTP_INTERNAL_H
 
-extern void ntp_init(void);
-extern void ntp_clear(void);
+struct timekeeper_ntp;
+
+extern void ntp_init(struct timekeeper_ntp *ntp);
+extern void ntp_clear(struct timekeeper_ntp *ntp);
 /* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
-extern u64 ntp_tick_length(void);
-extern int second_overflow(unsigned long secs);
+extern u64 ntp_tick_length(struct timekeeper_ntp *ntp);
+extern int second_overflow(struct timekeeper_ntp *ntp, unsigned long secs);
 extern int ntp_validate_timex(struct timex *);
-extern int __do_adjtimex(struct timex *, struct timespec *, s32 *);
-extern void __hardpps(const struct timespec *, const struct timespec *);
+extern int __do_adjtimex(struct timekeeper_ntp *ntp, struct timex *,
+		struct timespec *, s32 *);
+extern void __hardpps(struct timekeeper_ntp *ntp, const struct timespec *,
+		const struct timespec *);
 #endif /* _LINUX_NTP_INTERNAL_H */
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index d1ecafb..2210abb 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -260,7 +260,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
 {
 	if (action & TK_CLEAR_NTP) {
 		tk->ntp_error = 0;
-		ntp_clear();
+		ntp_clear(&tk->ntp);
 	}
 	update_vsyscall(tk);
 	update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);
@@ -819,7 +819,7 @@ void __init timekeeping_init(void)
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
 	write_seqcount_begin(&timekeeper_seq);
-	ntp_init();
+	ntp_init(&tk->ntp);
 
 	clock = clocksource_default_clock();
 	if (clock->enable)
@@ -1087,7 +1087,7 @@ static __always_inline int timekeeping_bigadjust(struct timekeeper *tk,
 	 * Now calculate the error in (1 << look_ahead) ticks, but first
 	 * remove the single look ahead already included in the error.
 	 */
-	tick_error = ntp_tick_length() >> (tk->ntp_error_shift + 1);
+	tick_error = ntp_tick_length(&tk->ntp) >> (tk->ntp_error_shift + 1);
 	tick_error -= tk->xtime_interval >> 1;
 	error = ((error - tick_error) >> look_ahead) + tick_error;
 
@@ -1274,7 +1274,7 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
 		tk->xtime_sec++;
 
 		/* Figure out if its a leap sec and apply if needed */
-		leap = second_overflow(tk->xtime_sec);
+		leap = second_overflow(&tk->ntp, tk->xtime_sec);
 		if (unlikely(leap)) {
 			struct timespec ts;
 
@@ -1331,7 +1331,7 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
 	tk->raw_time.tv_nsec = raw_nsecs;
 
 	/* Accumulate error between NTP and clock interval */
-	tk->ntp_error += ntp_tick_length() << shift;
+	tk->ntp_error += ntp_tick_length(&tk->ntp) << shift;
 	tk->ntp_error -= (tk->xtime_interval + tk->xtime_remainder) <<
 						(tk->ntp_error_shift + shift);
 
@@ -1408,7 +1408,7 @@ static void update_wall_time(void)
 	shift = ilog2(offset) - ilog2(tk->cycle_interval);
 	shift = max(0, shift);
 	/* Bound shift to one less than what overflows tick_length */
-	maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
+	maxshift = (64 - (ilog2(ntp_tick_length(&tk->ntp))+1)) - 1;
 	shift = min(shift, maxshift);
 	while (offset >= tk->cycle_interval) {
 		offset = logarithmic_accumulation(tk, offset, shift);
@@ -1703,7 +1703,7 @@ int do_adjtimex(struct timex *txc)
 	write_seqcount_begin(&timekeeper_seq);
 
 	orig_tai = tai = tk->tai_offset;
-	ret = __do_adjtimex(txc, &ts, &tai);
+	ret = __do_adjtimex(&tk->ntp, txc, &ts, &tai);
 
 	if (tai != orig_tai) {
 		__timekeeping_set_tai_offset(tk, tai);
@@ -1724,12 +1724,13 @@ int do_adjtimex(struct timex *txc)
  */
 void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 {
+	struct timekeeper *tk = &timekeeper;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
 	write_seqcount_begin(&timekeeper_seq);
 
-	__hardpps(phase_ts, raw_ts);
+	__hardpps(&tk->ntp, phase_ts, raw_ts);
 
 	write_seqcount_end(&timekeeper_seq);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 5/7] clocksource: add latch to clocksource
  2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
                   ` (3 preceding siblings ...)
  2013-09-14 19:47 ` [PATCH 4/7] Pass struct timekeeper_ntp as parameter from timekeeper to ntp Mathieu Desnoyers
@ 2013-09-14 19:47 ` Mathieu Desnoyers
  2013-09-14 19:48 ` [PATCH 6/7] x86 tsc clock: implement clock latch Mathieu Desnoyers
  2013-09-14 19:48 ` [PATCH 7/7] Introduce timekeeper latch synchronization Mathieu Desnoyers
  6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:47 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel
  Cc: Mathieu Desnoyers

Add latch for data used by clock read operations. This is in preparation
for the clock latch synchronization scheme. "cycle_last" rely on
timekeeper seqlock synchronization, and will therefore need to be
latched.

Add:
- cycle_last_latch (array of 2 elements),
- read_latch(),
- update_latch().

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 include/linux/clocksource.h |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index dbbf8aa..ef9c2e5 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -180,6 +180,10 @@ struct clocksource {
 #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
 	struct arch_clocksource_data archdata;
 #endif
+	cycle_t (*read_latch)(struct clocksource *cs, int index);
+	void (*update_latch)(struct clocksource *cs, int oldindex,
+			int newindex);
+	cycle_t cycle_last_latch[2];
 
 	const char *name;
 	struct list_head list;
-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 6/7] x86 tsc clock: implement clock latch
  2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
                   ` (4 preceding siblings ...)
  2013-09-14 19:47 ` [PATCH 5/7] clocksource: add latch to clocksource Mathieu Desnoyers
@ 2013-09-14 19:48 ` Mathieu Desnoyers
  2013-09-14 19:48 ` [PATCH 7/7] Introduce timekeeper latch synchronization Mathieu Desnoyers
  6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:48 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel
  Cc: Mathieu Desnoyers

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 arch/x86/kernel/tsc.c |   22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 6ff4924..c75e9f9 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -766,10 +766,28 @@ static cycle_t read_tsc(struct clocksource *cs)
 		ret : clocksource_tsc.cycle_last;
 }
 
+static cycle_t read_tsc_latch(struct clocksource *cs, int index)
+{
+	cycle_t ret = (cycle_t)get_cycles();
+
+	return ret >= clocksource_tsc.cycle_last_latch[index] ?
+		ret : clocksource_tsc.cycle_last_latch[index];
+}
+
+static void update_tsc_latch(struct clocksource *cs, int oldindex,
+		int newindex)
+{
+	clocksource_tsc.cycle_last_latch[newindex] =
+		clocksource_tsc.cycle_last_latch[oldindex];
+}
+
 static void resume_tsc(struct clocksource *cs)
 {
-	if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3))
+	if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC_S3)) {
 		clocksource_tsc.cycle_last = 0;
+		clocksource_tsc.cycle_last_latch[0] = 0;
+		clocksource_tsc.cycle_last_latch[1] = 0;
+	}
 }
 
 static struct clocksource clocksource_tsc = {
@@ -783,6 +801,8 @@ static struct clocksource clocksource_tsc = {
 #ifdef CONFIG_X86_64
 	.archdata               = { .vclock_mode = VCLOCK_TSC },
 #endif
+	.read_latch		= read_tsc_latch,
+	.update_latch		= update_tsc_latch,
 };
 
 void mark_tsc_unstable(char *reason)
-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 7/7] Introduce timekeeper latch synchronization
  2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
                   ` (5 preceding siblings ...)
  2013-09-14 19:48 ` [PATCH 6/7] x86 tsc clock: implement clock latch Mathieu Desnoyers
@ 2013-09-14 19:48 ` Mathieu Desnoyers
  6 siblings, 0 replies; 8+ messages in thread
From: Mathieu Desnoyers @ 2013-09-14 19:48 UTC (permalink / raw)
  To: John Stultz, Thomas Gleixner, Peter Zijlstra, linux-kernel
  Cc: Mathieu Desnoyers

Unlike the sequence lock, this latch synchronization scheme, proposed by
Peter Zijlstra, always keeps a readable copy of the data. Therefore,
readers will never deadlock if they nest on the writer, whether this
happens because the read-side is explicitly called within the write-side
critical section, executed in a nested interrupt (e.g. NMI), or executed
in an execution context that has lock dependency with the write-side
critical section.

The only situations in which readers have to retry is if 2 updates or
more happen concurrently with the read. Therefore, the only situation
that can trigger a reader retry involves updater progress, therefore if
a reader interrupts an update, it would interrupt progress of every
updates, and therefore the reader never has to retry.

A nice side-effect of this scheme is that the reader latency in the
case readers execute concurrently with updaters should be diminished,
because readers don't have to busy-loop when executing concurrently with
updaters, unless 2 or more updates are performed concurrently with the
read.

The overhead of this scheme is that every update must perform a copy of
struct timekeeper and then modify this copy rather than to do the update
in-place.

There should not be any significant overhead added to the read-side,
given the number of memory barriers is unchanged.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
---
 include/linux/timekeeper_internal.h |   93 ++++++++-
 kernel/time/ntp.c                   |   20 +-
 kernel/time/timekeeping.c           |  375 ++++++++++++++++++++---------------
 3 files changed, 317 insertions(+), 171 deletions(-)

diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 6f0532d..af54571 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -151,7 +151,98 @@ struct timekeeper {
 	struct timekeeper_ntp	ntp;
 };
 
-extern struct timekeeper timekeeper;
+struct timekeeper_latch {
+	unsigned long head, tail;
+	struct timekeeper data[2];
+};
+
+static inline
+int timekeeper_index(struct timekeeper_latch *tl, const struct timekeeper *tk)
+{
+	return tk - &tl->data[0];
+}
+
+extern struct timekeeper_latch timekeeper_latch;
+extern raw_spinlock_t timekeeper_lock;
+
+/**
+ * timekeeper_write_begin - begin timekeeper update.
+ *
+ " @tl: struct timekeeper_latch to update.
+ * @next: pointer to next element (output parameter).
+ *
+ * The area pointed to by "next" should be considered uninitialized.
+ * The caller needs to have exclusive update access to struct timekeeper_latch.
+ */
+static inline
+void timekeeper_write_begin(struct timekeeper_latch *tl,
+		struct timekeeper **next)
+{
+	const struct timekeeper *_prev;
+	struct timekeeper *_next;
+
+	tl->head++;
+	smp_wmb();		/* Store head before storing into next entry */
+	_prev = &tl->data[tl->tail & 1];
+	_next = &tl->data[tl->head & 1];
+	*_next = *_prev;	/* Copy prev content into next */
+	if (_next->clock && _next->clock->update_latch)
+		_next->clock->update_latch(_next->clock,
+				timekeeper_index(tl, _prev),
+				timekeeper_index(tl, _next));
+	*next = _next;
+}
+
+/**
+ * timekeeper_write_end - end timekeeper update.
+ *
+ " @tl: struct timekeeper_latch.
+ *
+ * The caller needs to have exclusive update access to struct timekeeper_latch.
+ */
+static inline
+void timekeeper_write_end(struct timekeeper_latch *tl)
+{
+	smp_wmb();	/* Store into next entry before storing into tail */
+	tl->tail++;
+}
+
+/**
+ * timekeeper_read_begin - begin timekeeper read.
+ *
+ " @tl: struct timekeeper_latch to read.
+ * @tail: pointer to unsigned long containing tail position (output).
+ */
+static inline
+struct timekeeper *timekeeper_read_begin(struct timekeeper_latch *tl,
+		unsigned long *tail)
+{
+	unsigned long ret;
+
+	ret = ACCESS_ONCE(tl->tail);
+	smp_rmb();	/* Load tail before loading entry */
+	*tail = ret;
+	return &tl->data[ret & 1];
+}
+
+/**
+ * timekeeper_read_retry - end timekeeper read, trigger retry if needed.
+ *
+ " @tl: struct timekeeper_latch read.
+ * @tail: tail position returned as output by timekeeper_read_begin().
+ *
+ * If timekeeper_read_retry() returns nonzero, the content of the read should
+ * be considered invalid, and the read should be performed again to
+ * reattempt reading coherent data, starting with timekeeper_read_begin().
+ */
+static inline
+int timekeeper_read_retry(struct timekeeper_latch *tl, unsigned long tail)
+{
+	smp_rmb();	/* Load entry before loading head */
+	return (ACCESS_ONCE(tl->head) - tail >= 2);
+}
+
+extern struct timekeeper *timekeeper_get_init(void);
 
 static inline struct timespec tk_xtime(struct timekeeper *tk)
 {
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 2a1b4ef..71a5d2a 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -395,9 +395,10 @@ static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
 
 static void sync_cmos_clock(struct work_struct *work)
 {
-	struct timekeeper_ntp *ntp = &timekeeper.ntp;
+	struct timekeeper *tk;
+	unsigned long seq, local_tick_nsec;
 	struct timespec now, next;
-	int fail = 1;
+	int fail = 1, ret;
 
 	/*
 	 * If we have an externally synchronized Linux clock, then update
@@ -406,7 +407,11 @@ static void sync_cmos_clock(struct work_struct *work)
 	 * This code is run on a timer.  If the clock is set, that timer
 	 * may not expire at the correct time.  Thus, we adjust...
 	 */
-	if (!ntp_synced(ntp)) {
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		ret = ntp_synced(&tk->ntp);
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
+	if (!ret) {
 		/*
 		 * Not synced, exit, do not restart a timer (if one is
 		 * running, let it run out).
@@ -415,7 +420,11 @@ static void sync_cmos_clock(struct work_struct *work)
 	}
 
 	getnstimeofday(&now);
-	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= ntp->tick_nsec / 2) {
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		local_tick_nsec = tk->ntp.tick_nsec;
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
+	if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= local_tick_nsec / 2) {
 		struct timespec adjust = now;
 
 		fail = -ENODEV;
@@ -860,8 +869,9 @@ void __hardpps(struct timekeeper_ntp *ntp, const struct timespec *phase_ts,
 
 static int __init ntp_tick_adj_setup(char *str)
 {
-	struct timekeeper_ntp *ntp = &timekeeper.ntp;
+	struct timekeeper_ntp *ntp;
 
+	ntp = &timekeeper_get_init()->ntp;
 	ntp->ntp_tick_adj = simple_strtol(str, NULL, 0);
 	ntp->ntp_tick_adj <<= NTP_SCALE_SHIFT;
 
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 2210abb..4039691 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -28,23 +28,22 @@
 #include "timekeeping_internal.h"
 
 #define TK_CLEAR_NTP		(1 << 0)
-#define TK_MIRROR		(1 << 1)
-#define TK_CLOCK_WAS_SET	(1 << 2)
-
-struct timekeeper timekeeper = {
-	.ntp = {
-		.tick_usec = TICK_USEC,
-		.time_state = TIME_OK,
-		.time_status = STA_UNSYNC,
-		.time_constant = 2,
-		.time_maxerror = NTP_PHASE_LIMIT,
-		.time_esterror = NTP_PHASE_LIMIT,
+#define TK_CLOCK_WAS_SET	(1 << 1)
+
+struct timekeeper_latch timekeeper_latch = {
+	.data[0] = {
+		.ntp = {
+			.tick_usec = TICK_USEC,
+			.time_state = TIME_OK,
+			.time_status = STA_UNSYNC,
+			.time_constant = 2,
+			.time_maxerror = NTP_PHASE_LIMIT,
+			.time_esterror = NTP_PHASE_LIMIT,
+		},
 	},
 };
 
-static DEFINE_RAW_SPINLOCK(timekeeper_lock);
-static seqcount_t timekeeper_seq;
-static struct timekeeper shadow_timekeeper;
+DEFINE_RAW_SPINLOCK(timekeeper_lock);
 
 /* flag for if timekeeping is suspended */
 int __read_mostly timekeeping_suspended;
@@ -52,6 +51,16 @@ int __read_mostly timekeeping_suspended;
 /* Flag for if there is a persistent clock on this platform */
 bool __read_mostly persistent_clock_exist = false;
 
+/*
+ * timekeeper_get_init - get initial timekeeper structure (boot time init)
+ */
+struct timekeeper *timekeeper_get_init(void)
+{
+	struct timekeeper_latch *tl = &timekeeper_latch;
+
+	return &tl->data[tl->head & 1];
+}
+
 static inline void tk_normalize_xtime(struct timekeeper *tk)
 {
 	while (tk->xtime_nsec >= ((u64)NSEC_PER_SEC << tk->shift)) {
@@ -114,10 +123,13 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
 	cycle_t interval;
 	u64 tmp, ntpinterval;
 	struct clocksource *old_clock;
+	int tk_index = timekeeper_index(&timekeeper_latch, tk);
 
 	old_clock = tk->clock;
 	tk->clock = clock;
-	tk->cycle_last = clock->cycle_last = clock->read(clock);
+	tk->cycle_last =
+		clock->cycle_last_latch[tk_index] =
+		clock->cycle_last = clock->read(clock);
 
 	/* Do the ns -> cycle conversion first, using original mult */
 	tmp = NTP_INTERVAL_LENGTH;
@@ -178,13 +190,22 @@ static inline s64 timekeeping_get_ns(struct timekeeper *tk)
 	cycle_t cycle_now, cycle_delta;
 	struct clocksource *clock;
 	s64 nsec;
+	int tk_index = timekeeper_index(&timekeeper_latch, tk);
 
 	/* read clocksource: */
 	clock = tk->clock;
-	cycle_now = clock->read(clock);
+	if (clock->read_latch) {
+		cycle_now = clock->read_latch(clock, tk_index);
 
-	/* calculate the delta since the last update_wall_time: */
-	cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now -
+			clock->cycle_last_latch[tk_index]) & clock->mask;
+	} else {
+		cycle_now = clock->read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+	}
 
 	nsec = cycle_delta * tk->mult + tk->xtime_nsec;
 	nsec >>= tk->shift;
@@ -198,13 +219,22 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
 	cycle_t cycle_now, cycle_delta;
 	struct clocksource *clock;
 	s64 nsec;
+	int tk_index = timekeeper_index(&timekeeper_latch, tk);
 
 	/* read clocksource: */
 	clock = tk->clock;
-	cycle_now = clock->read(clock);
+	if (clock->read_latch) {
+		cycle_now = clock->read_latch(clock, tk_index);
 
-	/* calculate the delta since the last update_wall_time: */
-	cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now -
+			clock->cycle_last_latch[tk_index]) & clock->mask;
+	} else {
+		cycle_now = clock->read(clock);
+
+		/* calculate the delta since the last update_wall_time: */
+		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+	}
 
 	/* convert delta to nanoseconds. */
 	nsec = clocksource_cyc2ns(cycle_delta, clock->mult, clock->shift);
@@ -225,13 +255,15 @@ static void update_pvclock_gtod(struct timekeeper *tk, bool was_set)
  */
 int pvclock_gtod_register_notifier(struct notifier_block *nb)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long flags;
 	int ret;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 	ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb);
 	update_pvclock_gtod(tk, true);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	return ret;
@@ -264,9 +296,6 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
 	}
 	update_vsyscall(tk);
 	update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);
-
-	if (action & TK_MIRROR)
-		memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper));
 }
 
 /**
@@ -281,11 +310,13 @@ static void timekeeping_forward_now(struct timekeeper *tk)
 	cycle_t cycle_now, cycle_delta;
 	struct clocksource *clock;
 	s64 nsec;
+	int tk_index = timekeeper_index(&timekeeper_latch, tk);
 
 	clock = tk->clock;
 	cycle_now = clock->read(clock);
 	cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
-	tk->cycle_last = clock->cycle_last = cycle_now;
+	tk->cycle_last = clock->cycle_last =
+		clock->cycle_last_latch[tk_index] = cycle_now;
 
 	tk->xtime_nsec += cycle_delta * tk->mult;
 
@@ -307,17 +338,15 @@ static void timekeeping_forward_now(struct timekeeper *tk)
  */
 int __getnstimeofday(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 	s64 nsecs = 0;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
-
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		ts->tv_sec = tk->xtime_sec;
 		nsecs = timekeeping_get_ns(tk);
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	ts->tv_nsec = 0;
 	timespec_add_ns(ts, nsecs);
@@ -346,18 +375,17 @@ EXPORT_SYMBOL(getnstimeofday);
 
 ktime_t ktime_get(void)
 {
-	struct timekeeper *tk = &timekeeper;
-	unsigned int seq;
+	struct timekeeper *tk;
+	unsigned long seq;
 	s64 secs, nsecs;
 
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		secs = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
 		nsecs = timekeeping_get_ns(tk) + tk->wall_to_monotonic.tv_nsec;
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 	/*
 	 * Use ktime_set/ktime_add_ns to create a proper ktime on
 	 * 32-bit architectures without CONFIG_KTIME_SCALAR.
@@ -376,20 +404,19 @@ EXPORT_SYMBOL_GPL(ktime_get);
  */
 void ktime_get_ts(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	struct timespec tomono;
 	s64 nsec;
-	unsigned int seq;
+	unsigned long seq;
 
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		ts->tv_sec = tk->xtime_sec;
 		nsec = timekeeping_get_ns(tk);
 		tomono = tk->wall_to_monotonic;
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	ts->tv_sec += tomono.tv_sec;
 	ts->tv_nsec = 0;
@@ -406,19 +433,17 @@ EXPORT_SYMBOL_GPL(ktime_get_ts);
  */
 void timekeeping_clocktai(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 	u64 nsecs;
 
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
-
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		ts->tv_sec = tk->xtime_sec + tk->tai_offset;
 		nsecs = timekeeping_get_ns(tk);
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	ts->tv_nsec = 0;
 	timespec_add_ns(ts, nsecs);
@@ -454,14 +479,14 @@ EXPORT_SYMBOL(ktime_get_clocktai);
  */
 void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 	s64 nsecs_raw, nsecs_real;
 
 	WARN_ON_ONCE(timekeeping_suspended);
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 
 		*ts_raw = tk->raw_time;
 		ts_real->tv_sec = tk->xtime_sec;
@@ -470,7 +495,7 @@ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
 		nsecs_raw = timekeeping_get_ns_raw(tk);
 		nsecs_real = timekeeping_get_ns(tk);
 
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	timespec_add_ns(ts_raw, nsecs_raw);
 	timespec_add_ns(ts_real, nsecs_real);
@@ -503,7 +528,7 @@ EXPORT_SYMBOL(do_gettimeofday);
  */
 int do_settimeofday(const struct timespec *tv)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	struct timespec ts_delta, xt;
 	unsigned long flags;
 
@@ -511,7 +536,7 @@ int do_settimeofday(const struct timespec *tv)
 		return -EINVAL;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 
 	timekeeping_forward_now(tk);
 
@@ -523,9 +548,9 @@ int do_settimeofday(const struct timespec *tv)
 
 	tk_set_xtime(tk, tv);
 
-	timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
+	timekeeping_update(tk, TK_CLEAR_NTP | TK_CLOCK_WAS_SET);
 
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	/* signal hrtimers about time change */
@@ -543,7 +568,7 @@ EXPORT_SYMBOL(do_settimeofday);
  */
 int timekeeping_inject_offset(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long flags;
 	struct timespec tmp;
 	int ret = 0;
@@ -552,7 +577,7 @@ int timekeeping_inject_offset(struct timespec *ts)
 		return -EINVAL;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 
 	timekeeping_forward_now(tk);
 
@@ -567,9 +592,9 @@ int timekeeping_inject_offset(struct timespec *ts)
 	tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts));
 
 error: /* even if we error out, we forwarded the time, so call update */
-	timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
+	timekeeping_update(tk, TK_CLEAR_NTP | TK_CLOCK_WAS_SET);
 
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	/* signal hrtimers about time change */
@@ -586,14 +611,14 @@ EXPORT_SYMBOL(timekeeping_inject_offset);
  */
 s32 timekeeping_get_tai_offset(void)
 {
-	struct timekeeper *tk = &timekeeper;
-	unsigned int seq;
+	struct timekeeper *tk;
+	unsigned long seq;
 	s32 ret;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		ret = tk->tai_offset;
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	return ret;
 }
@@ -614,13 +639,13 @@ static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset)
  */
 void timekeeping_set_tai_offset(s32 tai_offset)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 	__timekeeping_set_tai_offset(tk, tai_offset);
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 	clock_was_set();
 }
@@ -632,14 +657,14 @@ void timekeeping_set_tai_offset(s32 tai_offset)
  */
 static int change_clocksource(void *data)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	struct clocksource *new, *old;
 	unsigned long flags;
 
 	new = (struct clocksource *) data;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 
 	timekeeping_forward_now(tk);
 	/*
@@ -657,9 +682,9 @@ static int change_clocksource(void *data)
 			module_put(new->owner);
 		}
 	}
-	timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
+	timekeeping_update(tk, TK_CLEAR_NTP | TK_CLOCK_WAS_SET);
 
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	return 0;
@@ -674,13 +699,25 @@ static int change_clocksource(void *data)
  */
 int timekeeping_notify(struct clocksource *clock)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
+	struct clocksource *current_clock;
+	unsigned long seq;
 
-	if (tk->clock == clock)
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		current_clock = tk->clock;
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
+	if (current_clock == clock)
 		return 0;
+
 	stop_machine(change_clocksource, clock, NULL);
 	tick_clock_notify();
-	return tk->clock == clock ? 0 : -1;
+
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		current_clock = tk->clock;
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
+	return current_clock == clock ? 0 : -1;
 }
 
 /**
@@ -706,16 +743,15 @@ EXPORT_SYMBOL_GPL(ktime_get_real);
  */
 void getrawmonotonic(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 	s64 nsecs;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		nsecs = timekeeping_get_ns_raw(tk);
 		*ts = tk->raw_time;
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	timespec_add_ns(ts, nsecs);
 }
@@ -726,16 +762,14 @@ EXPORT_SYMBOL(getrawmonotonic);
  */
 int timekeeping_valid_for_hres(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 	int ret;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
-
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		ret = tk->clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	return ret;
 }
@@ -745,16 +779,14 @@ int timekeeping_valid_for_hres(void)
  */
 u64 timekeeping_max_deferment(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 	u64 ret;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
-
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		ret = tk->clock->max_idle_ns;
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	return ret;
 }
@@ -794,7 +826,7 @@ void __attribute__((weak)) read_boot_clock(struct timespec *ts)
  */
 void __init timekeeping_init(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	struct clocksource *clock;
 	unsigned long flags;
 	struct timespec now, boot, tmp;
@@ -818,7 +850,7 @@ void __init timekeeping_init(void)
 	}
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 	ntp_init(&tk->ntp);
 
 	clock = clocksource_default_clock();
@@ -839,9 +871,7 @@ void __init timekeeping_init(void)
 	tmp.tv_nsec = 0;
 	tk_set_sleep_time(tk, tmp);
 
-	memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper));
-
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 }
 
@@ -881,7 +911,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
  */
 void timekeeping_inject_sleeptime(struct timespec *delta)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long flags;
 
 	/*
@@ -892,15 +922,15 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
 		return;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 
 	timekeeping_forward_now(tk);
 
 	__timekeeping_inject_sleeptime(tk, delta);
 
-	timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
+	timekeeping_update(tk, TK_CLEAR_NTP | TK_CLOCK_WAS_SET);
 
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	/* signal hrtimers about time change */
@@ -916,12 +946,13 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
  */
 static void timekeeping_resume(void)
 {
-	struct timekeeper *tk = &timekeeper;
-	struct clocksource *clock = tk->clock;
+	struct timekeeper *tk;
+	struct clocksource *clock;
 	unsigned long flags;
 	struct timespec ts_new, ts_delta;
 	cycle_t cycle_now, cycle_delta;
 	bool suspendtime_found = false;
+	int tk_index;
 
 	read_persistent_clock(&ts_new);
 
@@ -929,7 +960,9 @@ static void timekeeping_resume(void)
 	clocksource_resume();
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
+	clock = tk->clock;
+	tk_index = timekeeper_index(&timekeeper_latch, tk);
 
 	/*
 	 * After system resumes, we need to calculate the suspended time and
@@ -977,11 +1010,12 @@ static void timekeeping_resume(void)
 		__timekeeping_inject_sleeptime(tk, &ts_delta);
 
 	/* Re-base the last cycle value */
-	tk->cycle_last = clock->cycle_last = cycle_now;
+	tk->cycle_last = clock->cycle_last =
+		clock->cycle_last_latch[tk_index] = cycle_now;
 	tk->ntp_error = 0;
 	timekeeping_suspended = 0;
-	timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET);
-	write_seqcount_end(&timekeeper_seq);
+	timekeeping_update(tk, TK_CLOCK_WAS_SET);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	touch_softlockup_watchdog();
@@ -994,7 +1028,7 @@ static void timekeeping_resume(void)
 
 static int timekeeping_suspend(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long flags;
 	struct timespec		delta, delta_delta;
 	static struct timespec	old_delta;
@@ -1010,7 +1044,7 @@ static int timekeeping_suspend(void)
 		persistent_clock_exist = true;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 	timekeeping_forward_now(tk);
 	timekeeping_suspended = 1;
 
@@ -1033,7 +1067,7 @@ static int timekeeping_suspend(void)
 		timekeeping_suspend_time =
 			timespec_add(timekeeping_suspend_time, delta_delta);
 	}
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
@@ -1372,29 +1406,31 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk)
 static void update_wall_time(void)
 {
 	struct clocksource *clock;
-	struct timekeeper *real_tk = &timekeeper;
-	struct timekeeper *tk = &shadow_timekeeper;
+	struct timekeeper *tk;
 	cycle_t offset;
 	int shift = 0, maxshift;
 	unsigned int action;
 	unsigned long flags;
+	int tk_index;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
+	tk_index = timekeeper_index(&timekeeper_latch, tk);
 
 	/* Make sure we're fully resumed: */
 	if (unlikely(timekeeping_suspended))
 		goto out;
 
-	clock = real_tk->clock;
+	clock = tk->clock;
 
 #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
-	offset = real_tk->cycle_interval;
+	offset = tk->cycle_interval;
 #else
 	offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
 #endif
 
 	/* Check if there's really nothing to do */
-	if (offset < real_tk->cycle_interval)
+	if (offset < tk->cycle_interval)
 		goto out;
 
 	/*
@@ -1431,23 +1467,11 @@ static void update_wall_time(void)
 	 */
 	action = accumulate_nsecs_to_secs(tk);
 
-	write_seqcount_begin(&timekeeper_seq);
 	/* Update clock->cycle_last with the new value */
-	clock->cycle_last = tk->cycle_last;
-	/*
-	 * Update the real timekeeper.
-	 *
-	 * We could avoid this memcpy by switching pointers, but that
-	 * requires changes to all other timekeeper usage sites as
-	 * well, i.e. move the timekeeper pointer getter into the
-	 * spinlocked/seqcount protected sections. And we trade this
-	 * memcpy under the timekeeper_seq against one before we start
-	 * updating.
-	 */
-	memcpy(real_tk, tk, sizeof(*tk));
-	timekeeping_update(real_tk, action);
-	write_seqcount_end(&timekeeper_seq);
+	clock->cycle_last_latch[tk_index] = clock->cycle_last = tk->cycle_last;
+	timekeeping_update(tk, action);
 out:
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 }
 
@@ -1464,13 +1488,17 @@ out:
  */
 void getboottime(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
-	struct timespec boottime = {
-		.tv_sec = tk->wall_to_monotonic.tv_sec +
-				tk->total_sleep_time.tv_sec,
-		.tv_nsec = tk->wall_to_monotonic.tv_nsec +
-				tk->total_sleep_time.tv_nsec
-	};
+	struct timekeeper *tk;
+	struct timespec boottime;
+	unsigned long seq;
+
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		boottime.tv_sec = tk->wall_to_monotonic.tv_sec +
+				tk->total_sleep_time.tv_sec;
+		boottime.tv_nsec = tk->wall_to_monotonic.tv_nsec +
+				tk->total_sleep_time.tv_nsec;
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	set_normalized_timespec(ts, -boottime.tv_sec, -boottime.tv_nsec);
 }
@@ -1487,21 +1515,20 @@ EXPORT_SYMBOL_GPL(getboottime);
  */
 void get_monotonic_boottime(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	struct timespec tomono, sleep;
 	s64 nsec;
-	unsigned int seq;
+	unsigned long seq;
 
 	WARN_ON(timekeeping_suspended);
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		ts->tv_sec = tk->xtime_sec;
 		nsec = timekeeping_get_ns(tk);
 		tomono = tk->wall_to_monotonic;
 		sleep = tk->total_sleep_time;
-
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	ts->tv_sec += tomono.tv_sec + sleep.tv_sec;
 	ts->tv_nsec = 0;
@@ -1532,38 +1559,57 @@ EXPORT_SYMBOL_GPL(ktime_get_boottime);
  */
 void monotonic_to_bootbased(struct timespec *ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
+	struct timespec ret;
+	unsigned long seq;
+
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		ret = timespec_add(*ts, tk->total_sleep_time);
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
-	*ts = timespec_add(*ts, tk->total_sleep_time);
+	*ts = ret;
 }
 EXPORT_SYMBOL_GPL(monotonic_to_bootbased);
 
 unsigned long get_seconds(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
+	unsigned long seq, ret;
+
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		ret = tk->xtime_sec;
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
-	return tk->xtime_sec;
+	return ret;
 }
 EXPORT_SYMBOL(get_seconds);
 
 struct timespec __current_kernel_time(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
+	unsigned long seq;
+	struct timespec ret;
+
+	do {
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
+		ret = tk_xtime(tk);
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
-	return tk_xtime(tk);
+	return ret;
 }
 
 struct timespec current_kernel_time(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	struct timespec now;
 	unsigned long seq;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
-
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		now = tk_xtime(tk);
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	return now;
 }
@@ -1571,16 +1617,15 @@ EXPORT_SYMBOL(current_kernel_time);
 
 struct timespec get_monotonic_coarse(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	struct timespec now, mono;
 	unsigned long seq;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
-
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		now = tk_xtime(tk);
 		mono = tk->wall_to_monotonic;
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	set_normalized_timespec(&now, now.tv_sec + mono.tv_sec,
 				now.tv_nsec + mono.tv_nsec);
@@ -1607,15 +1652,15 @@ void do_timer(unsigned long ticks)
 void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
 				struct timespec *wtom, struct timespec *sleep)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		*xtim = tk_xtime(tk);
 		*wtom = tk->wall_to_monotonic;
 		*sleep = tk->total_sleep_time;
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 }
 
 #ifdef CONFIG_HIGH_RES_TIMERS
@@ -1630,13 +1675,13 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
 ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
 							ktime_t *offs_tai)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	ktime_t now;
-	unsigned int seq;
+	unsigned long seq;
 	u64 secs, nsecs;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 
 		secs = tk->xtime_sec;
 		nsecs = timekeeping_get_ns(tk);
@@ -1644,7 +1689,7 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
 		*offs_real = tk->offs_real;
 		*offs_boot = tk->offs_boot;
 		*offs_tai = tk->offs_tai;
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	now = ktime_add_ns(ktime_set(secs, 0), nsecs);
 	now = ktime_sub(now, *offs_real);
@@ -1657,14 +1702,14 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot,
  */
 ktime_t ktime_get_monotonic_offset(void)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long seq;
 	struct timespec wtom;
 
 	do {
-		seq = read_seqcount_begin(&timekeeper_seq);
+		tk = timekeeper_read_begin(&timekeeper_latch, &seq);
 		wtom = tk->wall_to_monotonic;
-	} while (read_seqcount_retry(&timekeeper_seq, seq));
+	} while (timekeeper_read_retry(&timekeeper_latch, seq));
 
 	return timespec_to_ktime(wtom);
 }
@@ -1675,7 +1720,7 @@ EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);
  */
 int do_adjtimex(struct timex *txc)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long flags;
 	struct timespec ts;
 	s32 orig_tai, tai;
@@ -1700,7 +1745,7 @@ int do_adjtimex(struct timex *txc)
 	getnstimeofday(&ts);
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 
 	orig_tai = tai = tk->tai_offset;
 	ret = __do_adjtimex(&tk->ntp, txc, &ts, &tai);
@@ -1710,7 +1755,7 @@ int do_adjtimex(struct timex *txc)
 		update_pvclock_gtod(tk, true);
 		clock_was_set_delayed();
 	}
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
 	ntp_notify_cmos_timer();
@@ -1724,15 +1769,15 @@ int do_adjtimex(struct timex *txc)
  */
 void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)
 {
-	struct timekeeper *tk = &timekeeper;
+	struct timekeeper *tk;
 	unsigned long flags;
 
 	raw_spin_lock_irqsave(&timekeeper_lock, flags);
-	write_seqcount_begin(&timekeeper_seq);
+	timekeeper_write_begin(&timekeeper_latch, &tk);
 
 	__hardpps(&tk->ntp, phase_ts, raw_ts);
 
-	write_seqcount_end(&timekeeper_seq);
+	timekeeper_write_end(&timekeeper_latch);
 	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 }
 EXPORT_SYMBOL(hardpps);
-- 
1.7.10.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-09-14 19:49 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-14 19:47 [RFC PATCH v2] timekeeper latch synchronization Mathieu Desnoyers
2013-09-14 19:47 ` [PATCH 1/7] Move ntp variables into struct timekeeper_ntp Mathieu Desnoyers
2013-09-14 19:47 ` [PATCH 2/7] Move PPS variables into struct timekeeper_pps Mathieu Desnoyers
2013-09-14 19:47 ` [PATCH 3/7] Move ntp structure into struct timekeeper Mathieu Desnoyers
2013-09-14 19:47 ` [PATCH 4/7] Pass struct timekeeper_ntp as parameter from timekeeper to ntp Mathieu Desnoyers
2013-09-14 19:47 ` [PATCH 5/7] clocksource: add latch to clocksource Mathieu Desnoyers
2013-09-14 19:48 ` [PATCH 6/7] x86 tsc clock: implement clock latch Mathieu Desnoyers
2013-09-14 19:48 ` [PATCH 7/7] Introduce timekeeper latch synchronization Mathieu Desnoyers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®