aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/timekeeper_internal.h2
-rw-r--r--include/linux/timekeeping.h1
-rw-r--r--kernel/time/timekeeping.c38
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 {
42 * struct timekeeper - Structure holding internal timekeeping values. 42 * struct timekeeper - Structure holding internal timekeeping values.
43 * @tkr: The readout base structure 43 * @tkr: The readout base structure
44 * @xtime_sec: Current CLOCK_REALTIME time in seconds 44 * @xtime_sec: Current CLOCK_REALTIME time in seconds
45 * @ktime_sec: Current CLOCK_MONOTONIC time in seconds
45 * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset 46 * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset
46 * @offs_real: Offset clock monotonic -> clock realtime 47 * @offs_real: Offset clock monotonic -> clock realtime
47 * @offs_boot: Offset clock monotonic -> clock boottime 48 * @offs_boot: Offset clock monotonic -> clock boottime
@@ -77,6 +78,7 @@ struct tk_read_base {
77struct timekeeper { 78struct timekeeper {
78 struct tk_read_base tkr; 79 struct tk_read_base tkr;
79 u64 xtime_sec; 80 u64 xtime_sec;
81 unsigned long ktime_sec;
80 struct timespec64 wall_to_monotonic; 82 struct timespec64 wall_to_monotonic;
81 ktime_t offs_real; 83 ktime_t offs_real;
82 ktime_t offs_boot; 84 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);
28struct timespec get_monotonic_coarse(void); 28struct timespec get_monotonic_coarse(void);
29extern void getrawmonotonic(struct timespec *ts); 29extern void getrawmonotonic(struct timespec *ts);
30extern void ktime_get_ts64(struct timespec64 *ts); 30extern void ktime_get_ts64(struct timespec64 *ts);
31extern time64_t ktime_get_seconds(void);
31 32
32extern int __getnstimeofday64(struct timespec64 *tv); 33extern int __getnstimeofday64(struct timespec64 *tv);
33extern void getnstimeofday64(struct timespec64 *tv); 34extern 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);
417 */ 417 */
418static inline void tk_update_ktime_data(struct timekeeper *tk) 418static inline void tk_update_ktime_data(struct timekeeper *tk)
419{ 419{
420 s64 nsec; 420 u64 seconds;
421 u32 nsec;
421 422
422 /* 423 /*
423 * The xtime based monotonic readout is: 424 * The xtime based monotonic readout is:
@@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
426 * nsec = base_mono + now(); 427 * nsec = base_mono + now();
427 * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec 428 * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec
428 */ 429 */
429 nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); 430 seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
430 nsec *= NSEC_PER_SEC; 431 nsec = (u32) tk->wall_to_monotonic.tv_nsec;
431 nsec += tk->wall_to_monotonic.tv_nsec; 432 tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
432 tk->tkr.base_mono = ns_to_ktime(nsec);
433 433
434 /* Update the monotonic raw base */ 434 /* Update the monotonic raw base */
435 tk->base_raw = timespec64_to_ktime(tk->raw_time); 435 tk->base_raw = timespec64_to_ktime(tk->raw_time);
436
437 /*
438 * The sum of the nanoseconds portions of xtime and
439 * wall_to_monotonic can be greater/equal one second. Take
440 * this into account before updating tk->ktime_sec.
441 */
442 nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift);
443 if (nsec >= NSEC_PER_SEC)
444 seconds++;
445 tk->ktime_sec = seconds;
436} 446}
437 447
438/* must hold timekeeper_lock */ 448/* must hold timekeeper_lock */
@@ -648,6 +658,24 @@ void ktime_get_ts64(struct timespec64 *ts)
648} 658}
649EXPORT_SYMBOL_GPL(ktime_get_ts64); 659EXPORT_SYMBOL_GPL(ktime_get_ts64);
650 660
661/**
662 * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
663 *
664 * Returns the seconds portion of CLOCK_MONOTONIC with a single non
665 * serialized read. tk->ktime_sec is of type 'unsigned long' so this
666 * works on both 32 and 64 bit systems. On 32 bit systems the readout
667 * covers ~136 years of uptime which should be enough to prevent
668 * premature wrap arounds.
669 */
670time64_t ktime_get_seconds(void)
671{
672 struct timekeeper *tk = &tk_core.timekeeper;
673
674 WARN_ON(timekeeping_suspended);
675 return tk->ktime_sec;
676}
677EXPORT_SYMBOL_GPL(ktime_get_seconds);
678
651#ifdef CONFIG_NTP_PPS 679#ifdef CONFIG_NTP_PPS
652 680
653/** 681/**