diff options
Diffstat (limited to 'kernel/time/timekeeping.c')
| -rw-r--r-- | kernel/time/timekeeping.c | 396 | 
1 files changed, 315 insertions, 81 deletions
| diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 9a0bc98fbe1..98cd470bbe4 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -23,8 +23,13 @@  #include <linux/stop_machine.h>  #include <linux/pvclock_gtod.h> +#include "tick-internal.h" +#include "ntp_internal.h"  static struct timekeeper timekeeper; +static DEFINE_RAW_SPINLOCK(timekeeper_lock); +static seqcount_t timekeeper_seq; +static struct timekeeper shadow_timekeeper;  /* flag for if timekeeping is suspended */  int __read_mostly timekeeping_suspended; @@ -67,6 +72,7 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm)  	tk->wall_to_monotonic = wtm;  	set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec);  	tk->offs_real = timespec_to_ktime(tmp); +	tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tk->tai_offset, 0));  }  static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t) @@ -96,7 +102,7 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)  	old_clock = tk->clock;  	tk->clock = clock; -	clock->cycle_last = clock->read(clock); +	tk->cycle_last = clock->cycle_last = clock->read(clock);  	/* Do the ns -> cycle conversion first, using original mult */  	tmp = NTP_INTERVAL_LENGTH; @@ -201,8 +207,6 @@ static void update_pvclock_gtod(struct timekeeper *tk)  /**   * pvclock_gtod_register_notifier - register a pvclock timedata update listener - * - * Must hold write on timekeeper.lock   */  int pvclock_gtod_register_notifier(struct notifier_block *nb)  { @@ -210,11 +214,10 @@ int pvclock_gtod_register_notifier(struct notifier_block *nb)  	unsigned long flags;  	int ret; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags);  	ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); -	/* update timekeeping data */  	update_pvclock_gtod(tk); -	write_sequnlock_irqrestore(&tk->lock, flags); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	return ret;  } @@ -223,25 +226,22 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_register_notifier);  /**   * pvclock_gtod_unregister_notifier - unregister a pvclock   * timedata update listener - * - * Must hold write on timekeeper.lock   */  int pvclock_gtod_unregister_notifier(struct notifier_block *nb)  { -	struct timekeeper *tk = &timekeeper;  	unsigned long flags;  	int ret; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags);  	ret = raw_notifier_chain_unregister(&pvclock_gtod_chain, nb); -	write_sequnlock_irqrestore(&tk->lock, flags); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	return ret;  }  EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); -/* must hold write on timekeeper.lock */ -static void timekeeping_update(struct timekeeper *tk, bool clearntp) +/* must hold timekeeper_lock */ +static void timekeeping_update(struct timekeeper *tk, bool clearntp, bool mirror)  {  	if (clearntp) {  		tk->ntp_error = 0; @@ -249,6 +249,9 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp)  	}  	update_vsyscall(tk);  	update_pvclock_gtod(tk); + +	if (mirror) +		memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper));  }  /** @@ -267,7 +270,7 @@ static void timekeeping_forward_now(struct timekeeper *tk)  	clock = tk->clock;  	cycle_now = clock->read(clock);  	cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; -	clock->cycle_last = cycle_now; +	tk->cycle_last = clock->cycle_last = cycle_now;  	tk->xtime_nsec += cycle_delta * tk->mult; @@ -294,12 +297,12 @@ int __getnstimeofday(struct timespec *ts)  	s64 nsecs = 0;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		ts->tv_sec = tk->xtime_sec;  		nsecs = timekeeping_get_ns(tk); -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	ts->tv_nsec = 0;  	timespec_add_ns(ts, nsecs); @@ -335,11 +338,11 @@ ktime_t ktime_get(void)  	WARN_ON(timekeeping_suspended);  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		secs = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;  		nsecs = timekeeping_get_ns(tk) + tk->wall_to_monotonic.tv_nsec; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	/*  	 * Use ktime_set/ktime_add_ns to create a proper ktime on  	 * 32-bit architectures without CONFIG_KTIME_SCALAR. @@ -366,12 +369,12 @@ void ktime_get_ts(struct timespec *ts)  	WARN_ON(timekeeping_suspended);  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		ts->tv_sec = tk->xtime_sec;  		nsec = timekeeping_get_ns(tk);  		tomono = tk->wall_to_monotonic; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	ts->tv_sec += tomono.tv_sec;  	ts->tv_nsec = 0; @@ -379,6 +382,50 @@ void ktime_get_ts(struct timespec *ts)  }  EXPORT_SYMBOL_GPL(ktime_get_ts); + +/** + * timekeeping_clocktai - Returns the TAI time of day in a timespec + * @ts:		pointer to the timespec to be set + * + * Returns the time of day in a timespec. + */ +void timekeeping_clocktai(struct timespec *ts) +{ +	struct timekeeper *tk = &timekeeper; +	unsigned long seq; +	u64 nsecs; + +	WARN_ON(timekeeping_suspended); + +	do { +		seq = read_seqcount_begin(&timekeeper_seq); + +		ts->tv_sec = tk->xtime_sec + tk->tai_offset; +		nsecs = timekeeping_get_ns(tk); + +	} while (read_seqcount_retry(&timekeeper_seq, seq)); + +	ts->tv_nsec = 0; +	timespec_add_ns(ts, nsecs); + +} +EXPORT_SYMBOL(timekeeping_clocktai); + + +/** + * ktime_get_clocktai - Returns the TAI time of day in a ktime + * + * Returns the time of day in a ktime. + */ +ktime_t ktime_get_clocktai(void) +{ +	struct timespec ts; + +	timekeeping_clocktai(&ts); +	return timespec_to_ktime(ts); +} +EXPORT_SYMBOL(ktime_get_clocktai); +  #ifdef CONFIG_NTP_PPS  /** @@ -399,7 +446,7 @@ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)  	WARN_ON_ONCE(timekeeping_suspended);  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		*ts_raw = tk->raw_time;  		ts_real->tv_sec = tk->xtime_sec; @@ -408,7 +455,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_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	timespec_add_ns(ts_raw, nsecs_raw);  	timespec_add_ns(ts_real, nsecs_real); @@ -448,7 +495,8 @@ int do_settimeofday(const struct timespec *tv)  	if (!timespec_valid_strict(tv))  		return -EINVAL; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	timekeeping_forward_now(tk); @@ -460,9 +508,10 @@ int do_settimeofday(const struct timespec *tv)  	tk_set_xtime(tk, tv); -	timekeeping_update(tk, true); +	timekeeping_update(tk, true, true); -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	/* signal hrtimers about time change */  	clock_was_set(); @@ -487,7 +536,8 @@ int timekeeping_inject_offset(struct timespec *ts)  	if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)  		return -EINVAL; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	timekeeping_forward_now(tk); @@ -502,9 +552,10 @@ 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, true); +	timekeeping_update(tk, true, true); -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	/* signal hrtimers about time change */  	clock_was_set(); @@ -513,6 +564,52 @@ error: /* even if we error out, we forwarded the time, so call update */  }  EXPORT_SYMBOL(timekeeping_inject_offset); + +/** + * timekeeping_get_tai_offset - Returns current TAI offset from UTC + * + */ +s32 timekeeping_get_tai_offset(void) +{ +	struct timekeeper *tk = &timekeeper; +	unsigned int seq; +	s32 ret; + +	do { +		seq = read_seqcount_begin(&timekeeper_seq); +		ret = tk->tai_offset; +	} while (read_seqcount_retry(&timekeeper_seq, seq)); + +	return ret; +} + +/** + * __timekeeping_set_tai_offset - Lock free worker function + * + */ +static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) +{ +	tk->tai_offset = tai_offset; +	tk->offs_tai = ktime_sub(tk->offs_real, ktime_set(tai_offset, 0)); +} + +/** + * timekeeping_set_tai_offset - Sets the current TAI offset from UTC + * + */ +void timekeeping_set_tai_offset(s32 tai_offset) +{ +	struct timekeeper *tk = &timekeeper; +	unsigned long flags; + +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq); +	__timekeeping_set_tai_offset(tk, tai_offset); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags); +	clock_was_set(); +} +  /**   * change_clocksource - Swaps clocksources if a new one is available   * @@ -526,7 +623,8 @@ static int change_clocksource(void *data)  	new = (struct clocksource *) data; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	timekeeping_forward_now(tk);  	if (!new->enable || new->enable(new) == 0) { @@ -535,9 +633,10 @@ static int change_clocksource(void *data)  		if (old->disable)  			old->disable(old);  	} -	timekeeping_update(tk, true); +	timekeeping_update(tk, true, true); -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	return 0;  } @@ -587,11 +686,11 @@ void getrawmonotonic(struct timespec *ts)  	s64 nsecs;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		nsecs = timekeeping_get_ns_raw(tk);  		*ts = tk->raw_time; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	timespec_add_ns(ts, nsecs);  } @@ -607,11 +706,11 @@ int timekeeping_valid_for_hres(void)  	int ret;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		ret = tk->clock->flags & CLOCK_SOURCE_VALID_FOR_HRES; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	return ret;  } @@ -626,11 +725,11 @@ u64 timekeeping_max_deferment(void)  	u64 ret;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		ret = tk->clock->max_idle_ns; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	return ret;  } @@ -693,11 +792,10 @@ void __init timekeeping_init(void)  		boot.tv_nsec = 0;  	} -	seqlock_init(&tk->lock); - +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	ntp_init(); -	write_seqlock_irqsave(&tk->lock, flags);  	clock = clocksource_default_clock();  	if (clock->enable)  		clock->enable(clock); @@ -716,7 +814,10 @@ void __init timekeeping_init(void)  	tmp.tv_nsec = 0;  	tk_set_sleep_time(tk, tmp); -	write_sequnlock_irqrestore(&tk->lock, flags); +	memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper)); + +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  }  /* time in seconds when suspend began */ @@ -764,15 +865,17 @@ void timekeeping_inject_sleeptime(struct timespec *delta)  	if (has_persistent_clock())  		return; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	timekeeping_forward_now(tk);  	__timekeeping_inject_sleeptime(tk, delta); -	timekeeping_update(tk, true); +	timekeeping_update(tk, true, true); -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	/* signal hrtimers about time change */  	clock_was_set(); @@ -788,26 +891,72 @@ void timekeeping_inject_sleeptime(struct timespec *delta)  static void timekeeping_resume(void)  {  	struct timekeeper *tk = &timekeeper; +	struct clocksource *clock = tk->clock;  	unsigned long flags; -	struct timespec ts; +	struct timespec ts_new, ts_delta; +	cycle_t cycle_now, cycle_delta; +	bool suspendtime_found = false; -	read_persistent_clock(&ts); +	read_persistent_clock(&ts_new);  	clockevents_resume();  	clocksource_resume(); -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq); + +	/* +	 * After system resumes, we need to calculate the suspended time and +	 * compensate it for the OS time. There are 3 sources that could be +	 * used: Nonstop clocksource during suspend, persistent clock and rtc +	 * device. +	 * +	 * One specific platform may have 1 or 2 or all of them, and the +	 * preference will be: +	 *	suspend-nonstop clocksource -> persistent clock -> rtc +	 * The less preferred source will only be tried if there is no better +	 * usable source. The rtc part is handled separately in rtc core code. +	 */ +	cycle_now = clock->read(clock); +	if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) && +		cycle_now > clock->cycle_last) { +		u64 num, max = ULLONG_MAX; +		u32 mult = clock->mult; +		u32 shift = clock->shift; +		s64 nsec = 0; + +		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; -	if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) { -		ts = timespec_sub(ts, timekeeping_suspend_time); -		__timekeeping_inject_sleeptime(tk, &ts); +		/* +		 * "cycle_delta * mutl" may cause 64 bits overflow, if the +		 * suspended time is too long. In that case we need do the +		 * 64 bits math carefully +		 */ +		do_div(max, mult); +		if (cycle_delta > max) { +			num = div64_u64(cycle_delta, max); +			nsec = (((u64) max * mult) >> shift) * num; +			cycle_delta -= num * max; +		} +		nsec += ((u64) cycle_delta * mult) >> shift; + +		ts_delta = ns_to_timespec(nsec); +		suspendtime_found = true; +	} else if (timespec_compare(&ts_new, &timekeeping_suspend_time) > 0) { +		ts_delta = timespec_sub(ts_new, timekeeping_suspend_time); +		suspendtime_found = true;  	} -	/* re-base the last cycle value */ -	tk->clock->cycle_last = tk->clock->read(tk->clock); + +	if (suspendtime_found) +		__timekeeping_inject_sleeptime(tk, &ts_delta); + +	/* Re-base the last cycle value */ +	tk->cycle_last = clock->cycle_last = cycle_now;  	tk->ntp_error = 0;  	timekeeping_suspended = 0; -	timekeeping_update(tk, false); -	write_sequnlock_irqrestore(&tk->lock, flags); +	timekeeping_update(tk, false, true); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	touch_softlockup_watchdog(); @@ -826,7 +975,8 @@ static int timekeeping_suspend(void)  	read_persistent_clock(&timekeeping_suspend_time); -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	timekeeping_forward_now(tk);  	timekeeping_suspended = 1; @@ -849,7 +999,8 @@ static int timekeeping_suspend(void)  		timekeeping_suspend_time =  			timespec_add(timekeeping_suspend_time, delta_delta);  	} -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);  	clocksource_suspend(); @@ -1099,6 +1250,8 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)  			tk_set_wall_to_mono(tk,  				timespec_sub(tk->wall_to_monotonic, ts)); +			__timekeeping_set_tai_offset(tk, tk->tai_offset - leap); +  			clock_was_set_delayed();  		}  	} @@ -1116,15 +1269,16 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)  static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,  						u32 shift)  { +	cycle_t interval = tk->cycle_interval << shift;  	u64 raw_nsecs;  	/* If the offset is smaller then a shifted interval, do nothing */ -	if (offset < tk->cycle_interval<<shift) +	if (offset < interval)  		return offset;  	/* Accumulate one shifted interval */ -	offset -= tk->cycle_interval << shift; -	tk->clock->cycle_last += tk->cycle_interval << shift; +	offset -= interval; +	tk->cycle_last += interval;  	tk->xtime_nsec += tk->xtime_interval << shift;  	accumulate_nsecs_to_secs(tk); @@ -1181,27 +1335,28 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk)  static void update_wall_time(void)  {  	struct clocksource *clock; -	struct timekeeper *tk = &timekeeper; +	struct timekeeper *real_tk = &timekeeper; +	struct timekeeper *tk = &shadow_timekeeper;  	cycle_t offset;  	int shift = 0, maxshift;  	unsigned long flags; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags);  	/* Make sure we're fully resumed: */  	if (unlikely(timekeeping_suspended))  		goto out; -	clock = tk->clock; +	clock = real_tk->clock;  #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET -	offset = tk->cycle_interval; +	offset = real_tk->cycle_interval;  #else  	offset = (clock->read(clock) - clock->cycle_last) & clock->mask;  #endif  	/* Check if there's really nothing to do */ -	if (offset < tk->cycle_interval) +	if (offset < real_tk->cycle_interval)  		goto out;  	/* @@ -1238,11 +1393,24 @@ static void update_wall_time(void)  	 */  	accumulate_nsecs_to_secs(tk); -	timekeeping_update(tk, false); - +	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, false, false); +	write_seqcount_end(&timekeeper_seq);  out: -	write_sequnlock_irqrestore(&tk->lock, flags); - +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  }  /** @@ -1289,13 +1457,13 @@ void get_monotonic_boottime(struct timespec *ts)  	WARN_ON(timekeeping_suspended);  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		ts->tv_sec = tk->xtime_sec;  		nsec = timekeeping_get_ns(tk);  		tomono = tk->wall_to_monotonic;  		sleep = tk->total_sleep_time; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	ts->tv_sec += tomono.tv_sec + sleep.tv_sec;  	ts->tv_nsec = 0; @@ -1354,10 +1522,10 @@ struct timespec current_kernel_time(void)  	unsigned long seq;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		now = tk_xtime(tk); -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	return now;  } @@ -1370,11 +1538,11 @@ struct timespec get_monotonic_coarse(void)  	unsigned long seq;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		now = tk_xtime(tk);  		mono = tk->wall_to_monotonic; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	set_normalized_timespec(&now, now.tv_sec + mono.tv_sec,  				now.tv_nsec + mono.tv_nsec); @@ -1405,11 +1573,11 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,  	unsigned long seq;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		*xtim = tk_xtime(tk);  		*wtom = tk->wall_to_monotonic;  		*sleep = tk->total_sleep_time; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  }  #ifdef CONFIG_HIGH_RES_TIMERS @@ -1421,7 +1589,8 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,   * Returns current monotonic time and updates the offsets   * Called from hrtimer_interupt() or retrigger_next_event()   */ -ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot) +ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot, +							ktime_t *offs_tai)  {  	struct timekeeper *tk = &timekeeper;  	ktime_t now; @@ -1429,14 +1598,15 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)  	u64 secs, nsecs;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		secs = tk->xtime_sec;  		nsecs = timekeeping_get_ns(tk);  		*offs_real = tk->offs_real;  		*offs_boot = tk->offs_boot; -	} while (read_seqretry(&tk->lock, seq)); +		*offs_tai = tk->offs_tai; +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	now = ktime_add_ns(ktime_set(secs, 0), nsecs);  	now = ktime_sub(now, *offs_real); @@ -1454,15 +1624,79 @@ ktime_t ktime_get_monotonic_offset(void)  	struct timespec wtom;  	do { -		seq = read_seqbegin(&tk->lock); +		seq = read_seqcount_begin(&timekeeper_seq);  		wtom = tk->wall_to_monotonic; -	} while (read_seqretry(&tk->lock, seq)); +	} while (read_seqcount_retry(&timekeeper_seq, seq));  	return timespec_to_ktime(wtom);  }  EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);  /** + * do_adjtimex() - Accessor function to NTP __do_adjtimex function + */ +int do_adjtimex(struct timex *txc) +{ +	struct timekeeper *tk = &timekeeper; +	unsigned long flags; +	struct timespec ts; +	s32 orig_tai, tai; +	int ret; + +	/* Validate the data before disabling interrupts */ +	ret = ntp_validate_timex(txc); +	if (ret) +		return ret; + +	if (txc->modes & ADJ_SETOFFSET) { +		struct timespec delta; +		delta.tv_sec  = txc->time.tv_sec; +		delta.tv_nsec = txc->time.tv_usec; +		if (!(txc->modes & ADJ_NANO)) +			delta.tv_nsec *= 1000; +		ret = timekeeping_inject_offset(&delta); +		if (ret) +			return ret; +	} + +	getnstimeofday(&ts); + +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq); + +	orig_tai = tai = tk->tai_offset; +	ret = __do_adjtimex(txc, &ts, &tai); + +	if (tai != orig_tai) { +		__timekeeping_set_tai_offset(tk, tai); +		clock_was_set_delayed(); +	} +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + +	return ret; +} + +#ifdef CONFIG_NTP_PPS +/** + * hardpps() - Accessor function to NTP __hardpps function + */ +void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts) +{ +	unsigned long flags; + +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq); + +	__hardpps(phase_ts, raw_ts); + +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags); +} +EXPORT_SYMBOL(hardpps); +#endif + +/**   * xtime_update() - advances the timekeeping infrastructure   * @ticks:	number of ticks, that have elapsed since the last call.   * | 
