diff options
Diffstat (limited to 'kernel/time/ntp.c')
| -rw-r--r-- | kernel/time/ntp.c | 134 | 
1 files changed, 42 insertions, 92 deletions
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c index 6e039b144daf..f03fd83b170b 100644 --- a/kernel/time/ntp.c +++ b/kernel/time/ntp.c @@ -34,8 +34,6 @@ unsigned long			tick_nsec;  static u64			tick_length;  static u64			tick_length_base; -static struct hrtimer		leap_timer; -  #define MAX_TICKADJ		500LL		/* usecs */  #define MAX_TICKADJ_SCALED \  	(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) @@ -381,70 +379,63 @@ u64 ntp_tick_length(void)  /* - * 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 - * state, the system clock is set ahead one second. + * this routine handles the overflow of the microsecond field + * + * The tricky bits of code to handle the accurate clock support + * were provided by Dave Mills ([email protected]) of NTP fame. + * They were originally developed for SUN and DEC kernels. + * All the kudos should go to Dave for this stuff. + * + * Also handles leap second processing, and returns leap offset   */ -static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer) +int second_overflow(unsigned long secs)  { -	enum hrtimer_restart res = HRTIMER_NORESTART; -	unsigned long flags; +	s64 delta;  	int leap = 0; +	unsigned long flags;  	spin_lock_irqsave(&ntp_lock, flags); + +	/* +	 * 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 +	 * state, the system clock is set ahead one second. +	 */  	switch (time_state) {  	case TIME_OK: +		if (time_status & STA_INS) +			time_state = TIME_INS; +		else if (time_status & STA_DEL) +			time_state = TIME_DEL;  		break;  	case TIME_INS: -		leap = -1; -		time_state = TIME_OOP; -		printk(KERN_NOTICE -			"Clock: inserting leap second 23:59:60 UTC\n"); -		hrtimer_add_expires_ns(&leap_timer, NSEC_PER_SEC); -		res = HRTIMER_RESTART; +		if (secs % 86400 == 0) { +			leap = -1; +			time_state = TIME_OOP; +			printk(KERN_NOTICE +				"Clock: inserting leap second 23:59:60 UTC\n"); +		}  		break;  	case TIME_DEL: -		leap = 1; -		time_tai--; -		time_state = TIME_WAIT; -		printk(KERN_NOTICE -			"Clock: deleting leap second 23:59:59 UTC\n"); +		if ((secs + 1) % 86400 == 0) { +			leap = 1; +			time_tai--; +			time_state = TIME_WAIT; +			printk(KERN_NOTICE +				"Clock: deleting leap second 23:59:59 UTC\n"); +		}  		break;  	case TIME_OOP:  		time_tai++;  		time_state = TIME_WAIT; -		/* fall through */ +		break; +  	case TIME_WAIT:  		if (!(time_status & (STA_INS | STA_DEL)))  			time_state = TIME_OK;  		break;  	} -	spin_unlock_irqrestore(&ntp_lock, flags); -	/* -	 * We have to call this outside of the ntp_lock to keep -	 * the proper locking hierarchy -	 */ -	if (leap) -		timekeeping_leap_insert(leap); - -	return res; -} - -/* - * this routine handles the overflow of the microsecond field - * - * The tricky bits of code to handle the accurate clock support - * were provided by Dave Mills ([email protected]) of NTP fame. - * They were originally developed for SUN and DEC kernels. - * All the kudos should go to Dave for this stuff. - */ -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; @@ -481,15 +472,17 @@ void second_overflow(void)  	tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ)  							 << NTP_SCALE_SHIFT;  	time_adjust = 0; + + +  out:  	spin_unlock_irqrestore(&ntp_lock, flags); + +	return leap;  }  #ifdef CONFIG_GENERIC_CMOS_UPDATE -/* Disable the cmos update - used by virtualization and embedded */ -int no_sync_cmos_clock  __read_mostly; -  static void sync_cmos_clock(struct work_struct *work);  static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); @@ -536,35 +529,13 @@ static void sync_cmos_clock(struct work_struct *work)  static void notify_cmos_timer(void)  { -	if (!no_sync_cmos_clock) -		schedule_delayed_work(&sync_cmos_work, 0); +	schedule_delayed_work(&sync_cmos_work, 0);  }  #else  static inline void notify_cmos_timer(void) { }  #endif -/* - * Start the leap seconds timer: - */ -static inline void ntp_start_leap_timer(struct timespec *ts) -{ -	long now = ts->tv_sec; - -	if (time_status & STA_INS) { -		time_state = TIME_INS; -		now += 86400 - now % 86400; -		hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); - -		return; -	} - -	if (time_status & STA_DEL) { -		time_state = TIME_DEL; -		now += 86400 - (now + 1) % 86400; -		hrtimer_start(&leap_timer, ktime_set(now, 0), HRTIMER_MODE_ABS); -	} -}  /*   * Propagate a new txc->status value into the NTP state: @@ -589,22 +560,6 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)  	time_status &= STA_RONLY;  	time_status |= txc->status & ~STA_RONLY; -	switch (time_state) { -	case TIME_OK: -		ntp_start_leap_timer(ts); -		break; -	case TIME_INS: -	case TIME_DEL: -		time_state = TIME_OK; -		ntp_start_leap_timer(ts); -	case TIME_WAIT: -		if (!(time_status & (STA_INS | STA_DEL))) -			time_state = TIME_OK; -		break; -	case TIME_OOP: -		hrtimer_restart(&leap_timer); -		break; -	}  }  /*   * Called with the xtime lock held, so we can access and modify @@ -686,9 +641,6 @@ int do_adjtimex(struct timex *txc)  		    (txc->tick <  900000/USER_HZ ||  		     txc->tick > 1100000/USER_HZ))  			return -EINVAL; - -		if (txc->modes & ADJ_STATUS && time_state != TIME_OK) -			hrtimer_cancel(&leap_timer);  	}  	if (txc->modes & ADJ_SETOFFSET) { @@ -1010,6 +962,4 @@ __setup("ntp_tick_adj=", ntp_tick_adj_setup);  void __init ntp_init(void)  {  	ntp_clear(); -	hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); -	leap_timer.function = ntp_leap_second;  }  |