diff options
Diffstat (limited to 'kernel/time/ntp.c')
| -rw-r--r-- | kernel/time/ntp.c | 42 | 
1 files changed, 35 insertions, 7 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 7aa216188450..033743e3647a 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -77,6 +77,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 TIME64_MAX if no leap */ +static time64_t			ntp_next_leap_sec = TIME64_MAX; +  #ifdef CONFIG_NTP_PPS  /* @@ -350,6 +353,7 @@ void ntp_clear(void)  	tick_length	= tick_length_base;  	time_offset	= 0; +	ntp_next_leap_sec = TIME64_MAX;  	/* Clear PPS state variables */  	pps_clear();  } @@ -360,6 +364,21 @@ u64 ntp_tick_length(void)  	return tick_length;  } +/** + * 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 @@ -383,15 +402,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 = TIME64_MAX;  			time_state = TIME_OK; -		else if (secs % SECS_PER_DAY == 0) { +		} else if (secs % SECS_PER_DAY == 0) {  			leap = -1;  			time_state = TIME_OOP;  			printk(KERN_NOTICE @@ -399,19 +424,21 @@ int second_overflow(unsigned long secs)  		}  		break;  	case TIME_DEL: -		if (!(time_status & STA_DEL)) +		if (!(time_status & STA_DEL)) { +			ntp_next_leap_sec = TIME64_MAX;  			time_state = TIME_OK; -		else if ((secs + 1) % SECS_PER_DAY == 0) { +		} else if ((secs + 1) % SECS_PER_DAY == 0) {  			leap = 1; +			ntp_next_leap_sec = TIME64_MAX;  			time_state = TIME_WAIT;  			printk(KERN_NOTICE  				"Clock: deleting leap second 23:59:59 UTC\n");  		}  		break;  	case TIME_OOP: +		ntp_next_leap_sec = TIME64_MAX;  		time_state = TIME_WAIT;  		break; -  	case TIME_WAIT:  		if (!(time_status & (STA_INS | STA_DEL)))  			time_state = TIME_OK; @@ -548,6 +575,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)  	if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {  		time_state = TIME_OK;  		time_status = STA_UNSYNC; +		ntp_next_leap_sec = TIME64_MAX;  		/* restart PPS frequency calibration */  		pps_reset_freq_interval();  	}  | 
