diff options
Diffstat (limited to 'kernel/time')
| -rw-r--r-- | kernel/time/ntp.c | 18 | ||||
| -rw-r--r-- | kernel/time/tick-internal.h | 2 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 282 | 
3 files changed, 228 insertions, 74 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 072bb066bb7..59e2749be0f 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -53,9 +53,6 @@ static int			time_state = TIME_OK;  /* clock status bits:							*/  static int			time_status = STA_UNSYNC; -/* TAI offset (secs):							*/ -static long			time_tai; -  /* time adjustment (nsecs):						*/  static s64			time_offset; @@ -415,7 +412,6 @@ int second_overflow(unsigned long secs)  		else if (secs % 86400 == 0) {  			leap = -1;  			time_state = TIME_OOP; -			time_tai++;  			printk(KERN_NOTICE  				"Clock: inserting leap second 23:59:60 UTC\n");  		} @@ -425,7 +421,6 @@ int second_overflow(unsigned long secs)  			time_state = TIME_OK;  		else if ((secs + 1) % 86400 == 0) {  			leap = 1; -			time_tai--;  			time_state = TIME_WAIT;  			printk(KERN_NOTICE  				"Clock: deleting leap second 23:59:59 UTC\n"); @@ -579,7 +574,9 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)   * Called with ntp_lock held, so we can access and modify   * all the global NTP state:   */ -static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts) +static inline void process_adjtimex_modes(struct timex *txc, +						struct timespec *ts, +						s32 *time_tai)  {  	if (txc->modes & ADJ_STATUS)  		process_adj_status(txc, ts); @@ -613,7 +610,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts  	}  	if (txc->modes & ADJ_TAI && txc->constant > 0) -		time_tai = txc->constant; +		*time_tai = txc->constant;  	if (txc->modes & ADJ_OFFSET)  		ntp_update_offset(txc->offset); @@ -632,6 +629,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts  int do_adjtimex(struct timex *txc)  {  	struct timespec ts; +	u32 time_tai, orig_tai;  	int result;  	/* Validate the data before disabling interrupts */ @@ -671,6 +669,7 @@ int do_adjtimex(struct timex *txc)  	}  	getnstimeofday(&ts); +	orig_tai = time_tai = timekeeping_get_tai_offset();  	raw_spin_lock_irq(&ntp_lock); @@ -687,7 +686,7 @@ int do_adjtimex(struct timex *txc)  		/* If there are input parameters, then process them: */  		if (txc->modes) -			process_adjtimex_modes(txc, &ts); +			process_adjtimex_modes(txc, &ts, &time_tai);  		txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,  				  NTP_SCALE_SHIFT); @@ -716,6 +715,9 @@ int do_adjtimex(struct timex *txc)  	raw_spin_unlock_irq(&ntp_lock); +	if (time_tai != orig_tai) +		timekeeping_set_tai_offset(time_tai); +  	txc->time.tv_sec = ts.tv_sec;  	txc->time.tv_usec = ts.tv_nsec;  	if (!(time_status & STA_NANO)) diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 46d9bd02844..f0299eae460 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h @@ -4,6 +4,8 @@  #include <linux/hrtimer.h>  #include <linux/tick.h> +extern seqlock_t jiffies_lock; +  #ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD  #define TICK_DO_TIMER_NONE	-1 diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 9a0bc98fbe1..c5feb7aa3ac 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -23,8 +23,11 @@  #include <linux/stop_machine.h>  #include <linux/pvclock_gtod.h> +#include "tick-internal.h"  static struct timekeeper timekeeper; +static DEFINE_RAW_SPINLOCK(timekeeper_lock); +static seqcount_t timekeeper_seq;  /* flag for if timekeeping is suspended */  int __read_mostly timekeeping_suspended; @@ -67,6 +70,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) @@ -201,8 +205,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 +212,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,24 +224,21 @@ 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 */ +/* must hold timekeeper_lock */  static void timekeeping_update(struct timekeeper *tk, bool clearntp)  {  	if (clearntp) { @@ -294,12 +292,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 +333,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 +364,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 +377,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 +441,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 +450,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 +490,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); @@ -462,7 +505,8 @@ int do_settimeofday(const struct timespec *tv)  	timekeeping_update(tk, 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 +531,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); @@ -504,7 +549,8 @@ int timekeeping_inject_offset(struct timespec *ts)  error: /* even if we error out, we forwarded the time, so call update */  	timekeeping_update(tk, 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 +559,51 @@ 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); +} +  /**   * change_clocksource - Swaps clocksources if a new one is available   * @@ -526,7 +617,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) { @@ -537,7 +629,8 @@ static int change_clocksource(void *data)  	}  	timekeeping_update(tk, true); -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	return 0;  } @@ -587,11 +680,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 +700,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 +719,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 +786,10 @@ void __init timekeeping_init(void)  		boot.tv_nsec = 0;  	} -	seqlock_init(&tk->lock); -  	ntp_init(); -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	clock = clocksource_default_clock();  	if (clock->enable)  		clock->enable(clock); @@ -716,7 +808,8 @@ void __init timekeeping_init(void)  	tmp.tv_nsec = 0;  	tk_set_sleep_time(tk, tmp); -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  }  /* time in seconds when suspend began */ @@ -764,7 +857,8 @@ 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); @@ -772,7 +866,8 @@ void timekeeping_inject_sleeptime(struct timespec *delta)  	timekeeping_update(tk, 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 +883,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; -	if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) { -		ts = timespec_sub(ts, timekeeping_suspend_time); -		__timekeeping_inject_sleeptime(tk, &ts); +		cycle_delta = (cycle_now - clock->cycle_last) & clock->mask; + +		/* +		 * "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 */ +	clock->cycle_last = cycle_now;  	tk->ntp_error = 0;  	timekeeping_suspended = 0;  	timekeeping_update(tk, false); -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  	touch_softlockup_watchdog(); @@ -826,7 +967,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 +991,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 +1242,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 +1261,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->clock->cycle_last += interval;  	tk->xtime_nsec += tk->xtime_interval << shift;  	accumulate_nsecs_to_secs(tk); @@ -1186,7 +1332,8 @@ static void update_wall_time(void)  	int shift = 0, maxshift;  	unsigned long flags; -	write_seqlock_irqsave(&tk->lock, flags); +	raw_spin_lock_irqsave(&timekeeper_lock, flags); +	write_seqcount_begin(&timekeeper_seq);  	/* Make sure we're fully resumed: */  	if (unlikely(timekeeping_suspended)) @@ -1241,7 +1388,8 @@ static void update_wall_time(void)  	timekeeping_update(tk, false);  out: -	write_sequnlock_irqrestore(&tk->lock, flags); +	write_seqcount_end(&timekeeper_seq); +	raw_spin_unlock_irqrestore(&timekeeper_lock, flags);  } @@ -1289,13 +1437,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 +1502,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 +1518,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 +1553,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 +1569,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 +1578,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,9 +1604,9 @@ 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);  }  |