diff options
| -rw-r--r-- | include/linux/timekeeper_internal.h | 2 | ||||
| -rw-r--r-- | include/linux/timekeeping.h | 1 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 38 | 
3 files changed, 36 insertions, 5 deletions
| diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index 95640dcd1899..05af9a334893 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -42,6 +42,7 @@ struct tk_read_base {   * struct timekeeper - Structure holding internal timekeeping values.   * @tkr:		The readout base structure   * @xtime_sec:		Current CLOCK_REALTIME time in seconds + * @ktime_sec:		Current CLOCK_MONOTONIC time in seconds   * @wall_to_monotonic:	CLOCK_REALTIME to CLOCK_MONOTONIC offset   * @offs_real:		Offset clock monotonic -> clock realtime   * @offs_boot:		Offset clock monotonic -> clock boottime @@ -77,6 +78,7 @@ struct tk_read_base {  struct timekeeper {  	struct tk_read_base	tkr;  	u64			xtime_sec; +	unsigned long		ktime_sec;  	struct timespec64	wall_to_monotonic;  	ktime_t			offs_real;  	ktime_t			offs_boot; diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 1caa6b04fdc5..115d55e11bc9 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -28,6 +28,7 @@ struct timespec __current_kernel_time(void);  struct timespec get_monotonic_coarse(void);  extern void getrawmonotonic(struct timespec *ts);  extern void ktime_get_ts64(struct timespec64 *ts); +extern time64_t ktime_get_seconds(void);  extern int __getnstimeofday64(struct timespec64 *tv);  extern void getnstimeofday64(struct timespec64 *tv); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index ec1791fae965..a693270efafb 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -417,7 +417,8 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);   */  static inline void tk_update_ktime_data(struct timekeeper *tk)  { -	s64 nsec; +	u64 seconds; +	u32 nsec;  	/*  	 * The xtime based monotonic readout is: @@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)  	 *	nsec = base_mono + now();  	 * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec  	 */ -	nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); -	nsec *= NSEC_PER_SEC; -	nsec += tk->wall_to_monotonic.tv_nsec; -	tk->tkr.base_mono = ns_to_ktime(nsec); +	seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); +	nsec = (u32) tk->wall_to_monotonic.tv_nsec; +	tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);  	/* Update the monotonic raw base */  	tk->base_raw = timespec64_to_ktime(tk->raw_time); + +	/* +	 * The sum of the nanoseconds portions of xtime and +	 * wall_to_monotonic can be greater/equal one second. Take +	 * this into account before updating tk->ktime_sec. +	 */ +	nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift); +	if (nsec >= NSEC_PER_SEC) +		seconds++; +	tk->ktime_sec = seconds;  }  /* must hold timekeeper_lock */ @@ -648,6 +658,24 @@ void ktime_get_ts64(struct timespec64 *ts)  }  EXPORT_SYMBOL_GPL(ktime_get_ts64); +/** + * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC + * + * Returns the seconds portion of CLOCK_MONOTONIC with a single non + * serialized read. tk->ktime_sec is of type 'unsigned long' so this + * works on both 32 and 64 bit systems. On 32 bit systems the readout + * covers ~136 years of uptime which should be enough to prevent + * premature wrap arounds. + */ +time64_t ktime_get_seconds(void) +{ +	struct timekeeper *tk = &tk_core.timekeeper; + +	WARN_ON(timekeeping_suspended); +	return tk->ktime_sec; +} +EXPORT_SYMBOL_GPL(ktime_get_seconds); +  #ifdef CONFIG_NTP_PPS  /** | 
