diff options
Diffstat (limited to 'kernel/time/ntp.c')
| -rw-r--r-- | kernel/time/ntp.c | 85 | 
1 files changed, 64 insertions, 21 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index f6117a4c7cb..6e039b144da 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -22,13 +22,16 @@   * NTP timekeeping variables:   */ +DEFINE_SPINLOCK(ntp_lock); + +  /* USER_HZ period (usecs): */  unsigned long			tick_usec = TICK_USEC;  /* ACTHZ period (nsecs): */  unsigned long			tick_nsec; -u64				tick_length; +static u64			tick_length;  static u64			tick_length_base;  static struct hrtimer		leap_timer; @@ -49,7 +52,7 @@ static struct hrtimer		leap_timer;  static int			time_state = TIME_OK;  /* clock status bits:							*/ -int				time_status = STA_UNSYNC; +static int			time_status = STA_UNSYNC;  /* TAI offset (secs):							*/  static long			time_tai; @@ -133,7 +136,7 @@ static inline void pps_reset_freq_interval(void)  /**   * pps_clear - Clears the PPS state variables   * - * Must be called while holding a write on the xtime_lock + * Must be called while holding a write on the ntp_lock   */  static inline void pps_clear(void)  { @@ -149,7 +152,7 @@ static inline void pps_clear(void)   * the last PPS signal. When it reaches 0, indicate that PPS signal is   * missing.   * - * Must be called while holding a write on the xtime_lock + * Must be called while holding a write on the ntp_lock   */  static inline void pps_dec_valid(void)  { @@ -233,6 +236,17 @@ static inline void pps_fill_timex(struct timex *txc)  #endif /* CONFIG_NTP_PPS */ + +/** + * ntp_synced - Returns 1 if the NTP status is not UNSYNC + * + */ +static inline int ntp_synced(void) +{ +	return !(time_status & STA_UNSYNC); +} + +  /*   * NTP methods:   */ @@ -275,7 +289,7 @@ static inline s64 ntp_update_offset_fll(s64 offset64, long secs)  	time_status |= STA_MODE; -	return div_s64(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs); +	return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);  }  static void ntp_update_offset(long offset) @@ -330,11 +344,13 @@ static void ntp_update_offset(long offset)  /**   * ntp_clear - Clears the NTP state variables - * - * Must be called while holding a write on the xtime_lock   */  void ntp_clear(void)  { +	unsigned long flags; + +	spin_lock_irqsave(&ntp_lock, flags); +  	time_adjust	= 0;		/* stop active adjtime() */  	time_status	|= STA_UNSYNC;  	time_maxerror	= NTP_PHASE_LIMIT; @@ -347,8 +363,23 @@ void ntp_clear(void)  	/* Clear PPS state variables */  	pps_clear(); +	spin_unlock_irqrestore(&ntp_lock, flags); +  } + +u64 ntp_tick_length(void) +{ +	unsigned long flags; +	s64 ret; + +	spin_lock_irqsave(&ntp_lock, flags); +	ret = tick_length; +	spin_unlock_irqrestore(&ntp_lock, flags); +	return ret; +} + +  /*   * Leap second processing. If in leap-insert state at the end of the   * day, the system clock is set back one second; if in leap-delete @@ -357,14 +388,15 @@ void ntp_clear(void)  static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)  {  	enum hrtimer_restart res = HRTIMER_NORESTART; +	unsigned long flags; +	int leap = 0; -	write_seqlock(&xtime_lock); - +	spin_lock_irqsave(&ntp_lock, flags);  	switch (time_state) {  	case TIME_OK:  		break;  	case TIME_INS: -		timekeeping_leap_insert(-1); +		leap = -1;  		time_state = TIME_OOP;  		printk(KERN_NOTICE  			"Clock: inserting leap second 23:59:60 UTC\n"); @@ -372,7 +404,7 @@ static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)  		res = HRTIMER_RESTART;  		break;  	case TIME_DEL: -		timekeeping_leap_insert(1); +		leap = 1;  		time_tai--;  		time_state = TIME_WAIT;  		printk(KERN_NOTICE @@ -387,8 +419,14 @@ static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)  			time_state = TIME_OK;  		break;  	} +	spin_unlock_irqrestore(&ntp_lock, flags); -	write_sequnlock(&xtime_lock); +	/* +	 * We have to call this outside of the ntp_lock to keep +	 * the proper locking hierarchy +	 */ +	if (leap) +		timekeeping_leap_insert(leap);  	return res;  } @@ -404,6 +442,9 @@ static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)  void second_overflow(void)  {  	s64 delta; +	unsigned long flags; + +	spin_lock_irqsave(&ntp_lock, flags);  	/* Bump the maxerror field */  	time_maxerror += MAXFREQ / NSEC_PER_USEC; @@ -423,23 +464,25 @@ void second_overflow(void)  	pps_dec_valid();  	if (!time_adjust) -		return; +		goto out;  	if (time_adjust > MAX_TICKADJ) {  		time_adjust -= MAX_TICKADJ;  		tick_length += MAX_TICKADJ_SCALED; -		return; +		goto out;  	}  	if (time_adjust < -MAX_TICKADJ) {  		time_adjust += MAX_TICKADJ;  		tick_length -= MAX_TICKADJ_SCALED; -		return; +		goto out;  	}  	tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)  							 << NTP_SCALE_SHIFT;  	time_adjust = 0; +out: +	spin_unlock_irqrestore(&ntp_lock, flags);  }  #ifdef CONFIG_GENERIC_CMOS_UPDATE @@ -663,7 +706,7 @@ int do_adjtimex(struct timex *txc)  	getnstimeofday(&ts); -	write_seqlock_irq(&xtime_lock); +	spin_lock_irq(&ntp_lock);  	if (txc->modes & ADJ_ADJTIME) {  		long save_adjust = time_adjust; @@ -705,7 +748,7 @@ int do_adjtimex(struct timex *txc)  	/* fill PPS status fields */  	pps_fill_timex(txc); -	write_sequnlock_irq(&xtime_lock); +	spin_unlock_irq(&ntp_lock);  	txc->time.tv_sec = ts.tv_sec;  	txc->time.tv_usec = ts.tv_nsec; @@ -903,7 +946,7 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)  	pts_norm = pps_normalize_ts(*phase_ts); -	write_seqlock_irqsave(&xtime_lock, flags); +	spin_lock_irqsave(&ntp_lock, flags);  	/* clear the error bits, they will be set again if needed */  	time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); @@ -916,7 +959,7 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)  	 * just start the frequency interval */  	if (unlikely(pps_fbase.tv_sec == 0)) {  		pps_fbase = *raw_ts; -		write_sequnlock_irqrestore(&xtime_lock, flags); +		spin_unlock_irqrestore(&ntp_lock, flags);  		return;  	} @@ -931,7 +974,7 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)  		time_status |= STA_PPSJITTER;  		/* restart the frequency calibration interval */  		pps_fbase = *raw_ts; -		write_sequnlock_irqrestore(&xtime_lock, flags); +		spin_unlock_irqrestore(&ntp_lock, flags);  		pr_err("hardpps: PPSJITTER: bad pulse\n");  		return;  	} @@ -948,7 +991,7 @@ void hardpps(const struct timespec *phase_ts, const struct timespec *raw_ts)  	hardpps_update_phase(pts_norm.nsec); -	write_sequnlock_irqrestore(&xtime_lock, flags); +	spin_unlock_irqrestore(&ntp_lock, flags);  }  EXPORT_SYMBOL(hardpps);  |