diff options
Diffstat (limited to 'kernel/time/ntp.c')
-rw-r--r-- | kernel/time/ntp.c | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index e32587e7..ea8d82ee 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -34,6 +34,7 @@ unsigned long tick_nsec; static u64 tick_length; static u64 tick_length_base; +#define SECS_PER_DAY 86400 #define MAX_TICKADJ 500LL /* usecs */ #define MAX_TICKADJ_SCALED \ (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) @@ -78,6 +79,9 @@ static long time_adjust; /* constant (boot-param configurable) NTP tick adjustment (upscaled) */ static s64 ntp_tick_adj; +/* second value of the next pending leapsecond, or KTIME_MAX if no leap */ +static s64 ntp_next_leap_sec = KTIME_MAX; + #ifdef CONFIG_NTP_PPS /* @@ -354,6 +358,8 @@ void ntp_clear(void) time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; + ntp_next_leap_sec = KTIME_MAX; + ntp_update_frequency(); tick_length = tick_length_base; @@ -377,6 +383,21 @@ u64 ntp_tick_length(void) return ret; } +/** + * ntp_get_next_leap - Returns the next leapsecond in CLOCK_REALTIME ktime_t + * + * Provides the time of the next leapsecond against CLOCK_REALTIME in + * a ktime_t format. Returns KTIME_MAX if no leapsecond is pending. + */ +ktime_t ntp_get_next_leap(void) +{ + ktime_t ret; + + if ((time_state == TIME_INS) && (time_status & STA_INS)) + return ktime_set(ntp_next_leap_sec, 0); + ret.tv64 = KTIME_MAX; + return ret; +} /* * this routine handles the overflow of the microsecond field @@ -403,15 +424,21 @@ int second_overflow(unsigned long secs) */ switch (time_state) { case TIME_OK: - if (time_status & STA_INS) + if (time_status & STA_INS) { time_state = TIME_INS; - else if (time_status & STA_DEL) + ntp_next_leap_sec = secs + SECS_PER_DAY - + (secs % SECS_PER_DAY); + } else if (time_status & STA_DEL) { time_state = TIME_DEL; + ntp_next_leap_sec = secs + SECS_PER_DAY - + ((secs+1) % SECS_PER_DAY); + } break; case TIME_INS: - if (!(time_status & STA_INS)) + if (!(time_status & STA_INS)) { + ntp_next_leap_sec = KTIME_MAX; time_state = TIME_OK; - else if (secs % 86400 == 0) { + } else if (secs % SECS_PER_DAY == 0) { leap = -1; time_state = TIME_OOP; time_tai++; @@ -420,10 +447,12 @@ int second_overflow(unsigned long secs) } break; case TIME_DEL: - if (!(time_status & STA_DEL)) + if (!(time_status & STA_DEL)) { + ntp_next_leap_sec = KTIME_MAX; time_state = TIME_OK; - else if ((secs + 1) % 86400 == 0) { + } else if ((secs + 1) % SECS_PER_DAY == 0) { leap = 1; + ntp_next_leap_sec = KTIME_MAX; time_tai--; time_state = TIME_WAIT; printk(KERN_NOTICE @@ -431,6 +460,7 @@ int second_overflow(unsigned long secs) } break; case TIME_OOP: + ntp_next_leap_sec = KTIME_MAX; time_state = TIME_WAIT; break; @@ -549,6 +579,7 @@ 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; + ntp_next_leap_sec = KTIME_MAX; /* restart PPS frequency calibration */ pps_reset_freq_interval(); } @@ -619,7 +650,7 @@ static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts * adjtimex mainly allows reading (and writing, if superuser) of * kernel time-keeping variables. used by xntpd. */ -int do_adjtimex(struct timex *txc) +int __do_adjtimex(struct timex *txc) { struct timespec ts; int result; |