Cesar Eduardo Barrostime: remove no_sync_cmos_clock335dd8514 years agoHistory
965 lines · 23.4 KB · C
RawDownload
/* * NTP state machine interfaces and logic. * * This code was mainly moved from kernel/timer.c and kernel/time.c * Please see those files for relevant copyright info and historical * changelogs. */#include <linux/capability.h>#include <linux/clocksource.h>#include <linux/workqueue.h>#include <linux/hrtimer.h>#include <linux/jiffies.h>#include <linux/math64.h>#include <linux/timex.h>#include <linux/time.h>#include <linux/mm.h>#include <linux/module.h> #include "tick-internal.h" /* * NTP timekeeping variables: */ DEFINE_SPINLOCK(ntp_lock);  /* USER_HZ period (usecs): */unsigned long			tick_usec = TICK_USEC; /* ACTHZ period (nsecs): */unsigned long			tick_nsec; static u64			tick_length;static u64			tick_length_base; #define MAX_TICKADJ		500LL		/* usecs */#define MAX_TICKADJ_SCALED \	(((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) /* * phase-lock loop variables */ /* * clock synchronization status * * (TIME_ERROR prevents overwriting the CMOS clock) */static int			time_state = TIME_OK; /* clock status bits:							*/static int			time_status = STA_UNSYNC; /* TAI offset (secs):							*/static long			time_tai; /* time adjustment (nsecs):						*/static s64			time_offset; /* pll time constant:							*/static long			time_constant = 2; /* maximum error (usecs):						*/static long			time_maxerror = NTP_PHASE_LIMIT; /* estimated error (usecs):						*/static long			time_esterror = NTP_PHASE_LIMIT; /* frequency offset (scaled nsecs/secs):				*/static s64			time_freq; /* time at last adjustment (secs):					*/static long			time_reftime; static long			time_adjust; /* constant (boot-param configurable) NTP tick adjustment (upscaled)	*/static s64			ntp_tick_adj; #ifdef CONFIG_NTP_PPS /* * The following variables are used when a pulse-per-second (PPS) signal * is available. They establish the engineering parameters of the clock * discipline loop when controlled by the PPS signal. */#define PPS_VALID	10	/* PPS signal watchdog max (s) */#define PPS_POPCORN	4	/* popcorn spike threshold (shift) */#define PPS_INTMIN	2	/* min freq interval (s) (shift) */#define PPS_INTMAX	8	/* max freq interval (s) (shift) */#define PPS_INTCOUNT	4	/* number of consecutive good intervals to				   increase pps_shift or consecutive bad				   intervals to decrease it */#define PPS_MAXWANDER	100000	/* max PPS freq wander (ns/s) */ static int pps_valid;		/* signal watchdog counter */static long pps_tf[3];		/* phase median filter */static long pps_jitter;		/* current jitter (ns) */static struct timespec pps_fbase; /* beginning of the last freq interval */static int pps_shift;		/* current interval duration (s) (shift) */static int pps_intcnt;		/* interval counter */static s64 pps_freq;		/* frequency offset (scaled ns/s) */static long pps_stabil;		/* current stability (scaled ns/s) */ /* * PPS signal quality monitors */static long pps_calcnt;		/* calibration intervals */static long pps_jitcnt;		/* jitter limit exceeded */static long pps_stbcnt;		/* stability limit exceeded */static long pps_errcnt;		/* calibration errors */  /* PPS kernel consumer compensates the whole phase error immediately. * Otherwise, reduce the offset by a fixed factor times the time constant. */static inline s64 ntp_offset_chunk(s64 offset){	if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)		return offset;	else		return shift_right(offset, SHIFT_PLL + time_constant);} static inline void pps_reset_freq_interval(void){	/* the PPS calibration interval may end	   surprisingly early */	pps_shift = PPS_INTMIN;	pps_intcnt = 0;} /** * pps_clear - Clears the PPS state variables * * Must be called while holding a write on the ntp_lock */static inline void pps_clear(void){	pps_reset_freq_interval();	pps_tf[0] = 0;	pps_tf[1] = 0;	pps_tf[2] = 0;	pps_fbase.tv_sec = pps_fbase.tv_nsec = 0;	pps_freq = 0;} /* Decrease pps_valid to indicate that another second has passed since * the last PPS signal. When it reaches 0, indicate that PPS signal is * missing. * * Must be called while holding a write on the ntp_lock */static inline void pps_dec_valid(void){	if (pps_valid > 0)		pps_valid--;	else {		time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |				 STA_PPSWANDER | STA_PPSERROR);		pps_clear();	}} static inline void pps_set_freq(s64 freq){	pps_freq = freq;} static inline int is_error_status(int status){	return (time_status & (STA_UNSYNC|STA_CLOCKERR))		/* PPS signal lost when either PPS time or		 * PPS frequency synchronization requested		 */		|| ((time_status & (STA_PPSFREQ|STA_PPSTIME))			&& !(time_status & STA_PPSSIGNAL))		/* PPS jitter exceeded when		 * PPS time synchronization requested */		|| ((time_status & (STA_PPSTIME|STA_PPSJITTER))			== (STA_PPSTIME|STA_PPSJITTER))		/* PPS wander exceeded or calibration error when		 * PPS frequency synchronization requested		 */		|| ((time_status & STA_PPSFREQ)			&& (time_status & (STA_PPSWANDER|STA_PPSERROR)));} static inline void pps_fill_timex(struct timex *txc){	txc->ppsfreq	   = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) *					 PPM_SCALE_INV, NTP_SCALE_SHIFT);	txc->jitter	   = pps_jitter;	if (!(time_status & STA_NANO))		txc->jitter /= NSEC_PER_USEC;	txc->shift	   = pps_shift;	txc->stabil	   = pps_stabil;	txc->jitcnt	   = pps_jitcnt;	txc->calcnt	   = pps_calcnt;	txc->errcnt	   = pps_errcnt;	txc->stbcnt	   = pps_stbcnt;} #else /* !CONFIG_NTP_PPS */ static inline s64 ntp_offset_chunk(s64 offset){	return shift_right(offset, SHIFT_PLL + time_constant);} static inline void pps_reset_freq_interval(void) {}static inline void pps_clear(void) {}static inline void pps_dec_valid(void) {}static inline void pps_set_freq(s64 freq) {} static inline int is_error_status(int status){	return status & (STA_UNSYNC|STA_CLOCKERR);} static inline void pps_fill_timex(struct timex *txc){	/* PPS is not implemented, so these are zero */	txc->ppsfreq	   = 0;	txc->jitter	   = 0;	txc->shift	   = 0;	txc->stabil	   = 0;	txc->jitcnt	   = 0;	txc->calcnt	   = 0;	txc->errcnt	   = 0;	txc->stbcnt	   = 0;} #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: */ /* * Update (tick_length, tick_length_base, tick_nsec), based * on (tick_usec, ntp_tick_adj, time_freq): */static void ntp_update_frequency(void){	u64 second_length;	u64 new_base; 	second_length		 = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)						<< NTP_SCALE_SHIFT; 	second_length		+= ntp_tick_adj;	second_length		+= time_freq; 	tick_nsec		 = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;	new_base		 = div_u64(second_length, NTP_INTERVAL_FREQ); 	/*	 * Don't wait for the next second_overflow, apply	 * the change to the tick length immediately:	 */	tick_length		+= new_base - tick_length_base;	tick_length_base	 = new_base;} static inline s64 ntp_update_offset_fll(s64 offset64, long secs){	time_status &= ~STA_MODE; 	if (secs < MINSEC)		return 0; 	if (!(time_status & STA_FLL) && (secs <= MAXSEC))		return 0; 	time_status |= STA_MODE; 	return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs);} static void ntp_update_offset(long offset){	s64 freq_adj;	s64 offset64;	long secs; 	if (!(time_status & STA_PLL))		return; 	if (!(time_status & STA_NANO))		offset *= NSEC_PER_USEC; 	/*	 * Scale the phase adjustment and	 * clamp to the operating range.	 */	offset = min(offset, MAXPHASE);	offset = max(offset, -MAXPHASE); 	/*	 * Select how the frequency is to be controlled	 * and in which mode (PLL or FLL).	 */	secs = get_seconds() - time_reftime;	if (unlikely(time_status & STA_FREQHOLD))		secs = 0; 	time_reftime = get_seconds(); 	offset64    = offset;	freq_adj    = ntp_update_offset_fll(offset64, secs); 	/*	 * Clamp update interval to reduce PLL gain with low	 * sampling rate (e.g. intermittent network connection)	 * to avoid instability.	 */	if (unlikely(secs > 1 << (SHIFT_PLL + 1 + time_constant)))		secs = 1 << (SHIFT_PLL + 1 + time_constant); 	freq_adj    += (offset64 * secs) <<			(NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant)); 	freq_adj    = min(freq_adj + time_freq, MAXFREQ_SCALED); 	time_freq   = max(freq_adj, -MAXFREQ_SCALED); 	time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);} /** * ntp_clear - Clears the NTP state variables */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;	time_esterror	= NTP_PHASE_LIMIT; 	ntp_update_frequency(); 	tick_length	= tick_length_base;	time_offset	= 0; 	/* 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;}  /* * 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 (Mills@UDEL.EDU) 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 */int second_overflow(unsigned long secs){	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:		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:		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;		break; 	case TIME_WAIT:		if (!(time_status & (STA_INS | STA_DEL)))			time_state = TIME_OK;		break;	}  	/* Bump the maxerror field */	time_maxerror += MAXFREQ / NSEC_PER_USEC;	if (time_maxerror > NTP_PHASE_LIMIT) {		time_maxerror = NTP_PHASE_LIMIT;		time_status |= STA_UNSYNC;	} 	/* Compute the phase adjustment for the next second */	tick_length	 = tick_length_base; 	delta		 = ntp_offset_chunk(time_offset);	time_offset	-= delta;	tick_length	+= delta; 	/* Check PPS signal */	pps_dec_valid(); 	if (!time_adjust)		goto out; 	if (time_adjust > MAX_TICKADJ) {		time_adjust -= MAX_TICKADJ;		tick_length += MAX_TICKADJ_SCALED;		goto out;	} 	if (time_adjust < -MAX_TICKADJ) {		time_adjust += MAX_TICKADJ;		tick_length -= MAX_TICKADJ_SCALED;		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); 	return leap;} #ifdef CONFIG_GENERIC_CMOS_UPDATE static void sync_cmos_clock(struct work_struct *work); static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); static void sync_cmos_clock(struct work_struct *work){	struct timespec now, next;	int fail = 1; 	/*	 * If we have an externally synchronized Linux clock, then update	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be	 * called as close as possible to 500 ms before the new second starts.	 * This code is run on a timer.  If the clock is set, that timer	 * may not expire at the correct time.  Thus, we adjust...

Lines 1–500 of 965.