diff options
-rw-r--r-- | sys/kern/kern_clock.c | 7 | ||||
-rw-r--r-- | sys/kern/kern_ntptime.c | 1282 | ||||
-rw-r--r-- | sys/kern/kern_tc.c | 7 | ||||
-rw-r--r-- | sys/sys/time.h | 4 | ||||
-rw-r--r-- | sys/sys/timetc.h | 4 | ||||
-rw-r--r-- | sys/sys/timex.h | 297 |
6 files changed, 753 insertions, 848 deletions
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index 0b35622..1c536ee 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 - * $Id: kern_clock.c,v 1.87 1999/02/19 14:25:34 luoqi Exp $ + * $Id: kern_clock.c,v 1.88 1999/02/19 19:34:49 luoqi Exp $ */ #include <sys/param.h> @@ -675,10 +675,7 @@ tco_setscales(struct timecounter *tc) u_int64_t scale; scale = 1000000000LL << 32; - if (tc->tc_adjustment > 0) - scale += (tc->tc_adjustment * 1000LL) << 10; - else - scale -= (-tc->tc_adjustment * 1000LL) << 10; + scale += tc->tc_adjustment; scale /= tc->tc_frequency; tc->tc_scale_micro = scale / 1000; tc->tc_scale_nano_f = scale & 0xffffffff; diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c index 2f4114d..ec98387 100644 --- a/sys/kern/kern_ntptime.c +++ b/sys/kern/kern_ntptime.c @@ -1,507 +1,276 @@ -/****************************************************************************** - * * - * Copyright (c) David L. Mills 1993, 1994 * - * * - * Permission to use, copy, modify, and distribute this software and its * - * documentation for any purpose and without fee is hereby granted, provided * - * that the above copyright notice appears in all copies and that both the * - * copyright notice and this permission notice appear in supporting * - * documentation, and that the name University of Delaware not be used in * - * advertising or publicity pertaining to distribution of the software * - * without specific, written prior permission. The University of Delaware * - * makes no representations about the suitability this software for any * - * purpose. It is provided "as is" without express or implied warranty. * - * * - ******************************************************************************/ +/*********************************************************************** + * * + * Copyright (c) David L. Mills 1993-1998 * + * * + * Permission to use, copy, modify, and distribute this software and * + * its documentation for any purpose and without fee is hereby * + * granted, provided that the above copyright notice appears in all * + * copies and that both the copyright notice and this permission * + * notice appear in supporting documentation, and that the name * + * University of Delaware not be used in advertising or publicity * + * pertaining to distribution of the software without specific, * + * written prior permission. The University of Delaware makes no * + * representations about the suitability this software for any * + * purpose. It is provided "as is" without express or implied * + * warranty. * + * * + **********************************************************************/ /* - * Modification history kern_ntptime.c + * Adapted from the original sources for FreeBSD and timecounters by: + * Poul-Henning Kamp <phk@FreeBSD.org> * - * 24 Sep 94 David L. Mills - * Tightened code at exits. + * The 32bit version of the "LP" macros seems a bit past its "sell by" + * date so I have retained only the 64bit version and included it directly + * in this file. * - * 24 Mar 94 David L. Mills - * Revised syscall interface to include new variables for PPS - * time discipline. + * Only minor changes done to interface with the timecounters over in + * sys/kern/kern_clock.c. Some of the comments below may be (even more) + * confusing and/or plain wrong in that context. * - * 14 Feb 94 David L. Mills - * Added code for external clock + * The PPS_SYNC/hardpps() is currently not supported. * - * 28 Nov 93 David L. Mills - * Revised frequency scaling to conform with adjusted parameters - * - * 17 Sep 93 David L. Mills - * Created file - */ -/* - * ntp_gettime(), ntp_adjtime() - precision time interface for SunOS - * V4.1.1 and V4.1.3 - * - * These routines consitute the Network Time Protocol (NTP) interfaces - * for user and daemon application programs. The ntp_gettime() routine - * provides the time, maximum error (synch distance) and estimated error - * (dispersion) to client user application programs. The ntp_adjtime() - * routine is used by the NTP daemon to adjust the system clock to an - * externally derived time. The time offset and related variables set by - * this routine are used by hardclock() to adjust the phase and - * frequency of the phase-lock loop which controls the system clock. */ -#include "opt_ntp.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/kernel.h> #include <sys/proc.h> +#include <sys/time.h> #include <sys/timex.h> #include <sys/timepps.h> #include <sys/sysctl.h> /* - * Phase/frequency-lock loop (PLL/FLL) definitions - * - * The following variables are read and set by the ntp_adjtime() system - * call. - * - * time_state shows the state of the system clock, with values defined - * in the timex.h header file. - * - * time_status shows the status of the system clock, with bits defined - * in the timex.h header file. - * - * time_offset is used by the PLL/FLL to adjust the system time in small - * increments. - * - * time_constant determines the bandwidth or "stiffness" of the PLL. - * - * time_tolerance determines maximum frequency error or tolerance of the - * CPU clock oscillator and is a property of the architecture; however, - * in principle it could change as result of the presence of external - * discipline signals, for instance. - * - * time_precision is usually equal to the kernel tick variable; however, - * in cases where a precision clock counter or external clock is - * available, the resolution can be much less than this and depend on - * whether the external clock is working or not. - * - * time_maxerror is initialized by a ntp_adjtime() call and increased by - * the kernel once each second to reflect the maximum error - * bound growth. - * - * time_esterror is set and read by the ntp_adjtime() call, but - * otherwise not used by the kernel. + * Single-precision macros for 64-bit machines */ -static int time_status = STA_UNSYNC; /* clock status bits */ -static int time_state = TIME_OK; /* clock state */ -static long time_offset = 0; /* time offset (us) */ -static long time_constant = 0; /* pll time constant */ -static long time_tolerance = MAXFREQ; /* frequency tolerance (scaled ppm) */ -static long time_precision = 1; /* clock precision (us) */ -static long time_maxerror = MAXPHASE; /* maximum error (us) */ -static long time_esterror = MAXPHASE; /* estimated error (us) */ -static int time_daemon = 0; /* No timedaemon active */ +typedef long long l_fp; +#define L_ADD(v, u) ((v) += (u)) +#define L_SUB(v, u) ((v) -= (u)) +#define L_ADDHI(v, a) ((v) += (long long)(a) << 32) +#define L_NEG(v) ((v) = -(v)) +#define L_RSHIFT(v, n) \ + do { \ + if ((v) < 0) \ + (v) = -(-(v) >> (n)); \ + else \ + (v) = (v) >> (n); \ + } while (0) +#define L_MPY(v, a) ((v) *= (a)) +#define L_CLR(v) ((v) = 0) +#define L_ISNEG(v) ((v) < 0) +#define L_LINT(v, a) ((v) = (long long)(a) << 32) +#define L_GINT(v) ((v) < 0 ? -(-(v) >> 32) : (v) >> 32) /* - * The following variables establish the state of the PLL/FLL and the - * residual time and frequency offset of the local clock. The scale - * factors are defined in the timex.h header file. + * Generic NTP kernel interface * - * time_phase and time_freq are the phase increment and the frequency - * increment, respectively, of the kernel time variable at each tick of - * the clock. - * - * time_freq is set via ntp_adjtime() from a value stored in a file when - * the synchronization daemon is first started. Its value is retrieved - * via ntp_adjtime() and written to the file about once per hour by the - * daemon. - * - * time_adj is the adjustment added to the value of tick at each timer - * interrupt and is recomputed from time_phase and time_freq at each - * seconds rollover. - * - * time_reftime is the second's portion of the system time on the last - * call to ntp_adjtime(). It is used to adjust the time_freq variable - * and to increase the time_maxerror as the time since last update - * increases. + * These routines constitute the Network Time Protocol (NTP) interfaces + * for user and daemon application programs. The ntp_gettime() routine + * provides the time, maximum error (synch distance) and estimated error + * (dispersion) to client user application programs. The ntp_adjtime() + * routine is used by the NTP daemon to adjust the system clock to an + * externally derived time. The time offset and related variables set by + * this routine are used by other routines in this module to adjust the + * phase and frequency of the clock discipline loop which controls the + * system clock. + * + * When the kernel time is reckoned directly in nanoseconds (NANO + * defined), the time at each tick interrupt is derived directly from + * the kernel time variable. When the kernel time is reckoned in + * microseconds, (NANO undefined), the time is derived from the kernel + * time variable together with a variable representing the leftover + * nanoseconds at the last tick interrupt. In either case, the current + * nanosecond time is reckoned from these values plus an interpolated + * value derived by the clock routines in another architecture-specific + * module. The interpolation can use either a dedicated counter or a + * processor cycle counter (PCC) implemented in some architectures. + * + * Note that all routines must run at priority splclock or higher. */ -long time_phase = 0; /* phase offset (scaled us) */ -static long time_freq = 0; /* frequency offset (scaled ppm) */ -long time_adj = 0; /* tick adjust (scaled 1 / hz) */ -static long time_reftime = 0; /* time at last adjustment (s) */ -#ifdef PPS_SYNC /* - * The following variables are used only if the kernel PPS discipline - * code is configured (PPS_SYNC). The scale factors are defined in the - * timex.h header file. - * - * pps_time contains the time at each calibration interval, as read by - * microtime(). pps_count counts the seconds of the calibration - * interval, the duration of which is nominally pps_shift in powers of - * two. - * - * pps_offset is the time offset produced by the time median filter - * pps_tf[], while pps_jitter is the dispersion (jitter) measured by - * this filter. - * - * pps_freq is the frequency offset produced by the frequency median - * filter pps_ff[], while pps_stabil is the dispersion (wander) measured - * by this filter. - * - * pps_usec is latched from a high resolution counter or external clock - * at pps_time. Here we want the hardware counter contents only, not the - * contents plus the time_tv.usec as usual. - * - * pps_valid counts the number of seconds since the last PPS update. It - * is used as a watchdog timer to disable the PPS discipline should the - * PPS signal be lost. - * - * pps_glitch counts the number of seconds since the beginning of an - * offset burst more than tick/2 from current nominal offset. It is used - * mainly to suppress error bursts due to priority conflicts between the - * PPS interrupt and timer interrupt. + * Phase/frequency-lock loop (PLL/FLL) definitions * - * pps_intcnt counts the calibration intervals for use in the interval- - * adaptation algorithm. It's just too complicated for words. + * The nanosecond clock discipline uses two variable types, time + * variables and frequency variables. Both types are represented as 64- + * bit fixed-point quantities with the decimal point between two 32-bit + * halves. On a 32-bit machine, each half is represented as a single + * word and mathematical operations are done using multiple-precision + * arithmetic. On a 64-bit machine, ordinary computer arithmetic is + * used. + * + * A time variable is a signed 64-bit fixed-point number in ns and + * fraction. It represents the remaining time offset to be amortized + * over succeeding tick interrupts. The maximum time offset is about + * 0.512 s and the resolution is about 2.3e-10 ns. + * + * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |s s s| ns | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | fraction | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * A frequency variable is a signed 64-bit fixed-point number in ns/s + * and fraction. It represents the ns and fraction to be added to the + * kernel time variable at each second. The maximum frequency offset is + * about +-512000 ns/s and the resolution is about 2.3e-10 ns/s. + * + * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |s s s s s s s s s s s s s| ns/s | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | fraction | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -static struct timeval pps_time; /* kernel time at last interval */ -static long pps_offset = 0; /* pps time offset (us) */ -static long pps_jitter = MAXTIME; /* pps time dispersion (jitter) (us) */ -static long pps_tf[] = {0, 0, 0}; /* pps time offset median filter (us) */ -static long pps_freq = 0; /* frequency offset (scaled ppm) */ -static long pps_stabil = MAXFREQ; /* frequency dispersion (scaled ppm) */ -static long pps_ff[] = {0, 0, 0}; /* frequency offset median filter */ -static long pps_usec = 0; /* microsec counter at last interval */ -static long pps_valid = PPS_VALID; /* pps signal watchdog counter */ -static int pps_glitch = 0; /* pps signal glitch counter */ -static int pps_count = 0; /* calibration interval counter (s) */ -static int pps_shift = PPS_SHIFT; /* interval duration (s) (shift) */ -static int pps_intcnt = 0; /* intervals at current duration */ - /* - * PPS signal quality monitors - * - * pps_jitcnt counts the seconds that have been discarded because the - * jitter measured by the time median filter exceeds the limit MAXTIME - * (100 us). - * - * pps_calcnt counts the frequency calibration intervals, which are - * variable from 4 s to 256 s. - * - * pps_errcnt counts the calibration intervals which have been discarded - * because the wander exceeds the limit MAXFREQ (100 ppm) or where the - * calibration interval jitter exceeds two ticks. - * - * pps_stbcnt counts the calibration intervals that have been discarded - * because the frequency wander exceeds the limit MAXFREQ / 4 (25 us). + * The following variables establish the state of the PLL/FLL and the + * residual time and frequency offset of the local clock. */ -static long pps_jitcnt = 0; /* jitter limit exceeded */ -static long pps_calcnt = 0; /* calibration intervals */ -static long pps_errcnt = 0; /* calibration errors */ -static long pps_stbcnt = 0; /* stability limit exceeded */ -#endif /* PPS_SYNC */ +#define SHIFT_PLL 4 /* PLL loop gain (shift) */ +#define SHIFT_FLL 2 /* FLL loop gain (shift) */ -static void hardupdate __P((int64_t offset, int prescaled)); +static int time_state = TIME_OK; /* clock state */ +static int time_status = STA_UNSYNC; /* clock status bits */ +static long time_constant; /* poll interval (shift) (s) */ +static long time_precision = 1; /* clock precision (ns) */ +static long time_maxerror = MAXPHASE / 1000; /* maximum error (us) */ +static long time_esterror = MAXPHASE / 1000; /* estimated error (us) */ +static long time_reftime; /* time at last adjustment (s) */ +static long time_tick; /* nanoseconds per tick (ns) */ +static l_fp time_offset; /* time offset (ns) */ +static l_fp time_freq; /* frequency offset (ns/s) */ +#ifdef PPS_SYNC /* - * hardupdate() - local clock update - * - * This routine is called by ntp_adjtime() to update the local clock - * phase and frequency. The implementation is of an adaptive-parameter, - * hybrid phase/frequency-lock loop (PLL/FLL). The routine computes new - * time and frequency offset estimates for each call. If the kernel PPS - * discipline code is configured (PPS_SYNC), the PPS signal itself - * determines the new time offset, instead of the calling argument. - * Presumably, calls to ntp_adjtime() occur only when the caller - * believes the local clock is valid within some bound (+-128 ms with - * NTP). If the caller's time is far different than the PPS time, an - * argument will ensue, and it's not clear who will lose. - * - * For uncompensated quartz crystal oscillatores and nominal update - * intervals less than 1024 s, operation should be in phase-lock mode - * (STA_FLL = 0), where the loop is disciplined to phase. For update - * intervals greater than thiss, operation should be in frequency-lock - * mode (STA_FLL = 1), where the loop is disciplined to frequency. - * - * Note: splclock() is in effect. + * The following variables are used when a pulse-per-second (PPS) signal + * is available and connected via a modem control lead. They establish + * the engineering parameters of the clock discipline loop when + * controlled by the PPS signal. */ -static void -hardupdate(offset, prescaled) - int64_t offset; - int prescaled; -{ - long mtemp; - int64_t ltemp; +#define PPS_FAVG 2 /* min freq avg interval (s) (shift) */ +#define PPS_FAVGMAX 8 /* max freq avg interval (s) (shift) */ +#define PPS_PAVG 4 /* phase avg interval (s) (shift) */ +#define PPS_VALID 120 /* PPS signal watchdog max (s) */ +#define MAXTIME 500000 /* max PPS error (jitter) (ns) */ +#define MAXWANDER 500000 /* max PPS wander (ns/s/s) */ + +struct ppstime { + long sec; /* PPS seconds */ + long nsec; /* PPS nanoseconds */ + long count; /* PPS nanosecond counter */ +}; +static struct ppstime pps_tf[3]; /* phase median filter */ +static struct ppstime pps_filt; /* phase offset */ +static l_fp pps_freq; /* scaled frequency offset (ns/s) */ +static long pps_lastfreq; /* last scaled freq offset (ns/s) */ +static long pps_offacc; /* offset accumulator */ +static long pps_jitter; /* scaled time dispersion (ns) */ +static long pps_stabil; /* scaled frequency dispersion (ns/s) */ +static long pps_lastcount; /* last counter offset */ +static long pps_lastsec; /* time at last calibration (s) */ +static int pps_valid; /* signal watchdog counter */ +static int pps_shift = PPS_FAVG; /* interval duration (s) (shift) */ +static int pps_intcnt; /* wander counter */ +static int pps_offcnt; /* offset accumulator counter */ - if (!(time_status & STA_PLL) && !(time_status & STA_PPSTIME)) - return; - if (prescaled) - ltemp = offset; - else - ltemp = offset << SHIFT_UPDATE; -#ifdef PPS_SYNC - if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL) - ltemp = pps_offset << SHIFT_UPDATE; +/* + * 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 */ #endif /* PPS_SYNC */ +/* + * End of phase/frequency-lock loop (PLL/FLL) definitions + */ - /* - * Scale the phase adjustment and clamp to the operating range. - */ - if (ltemp > (MAXPHASE << SHIFT_UPDATE)) - time_offset = MAXPHASE << SHIFT_UPDATE; - else if (ltemp < -(MAXPHASE << SHIFT_UPDATE)) - time_offset = -(MAXPHASE << SHIFT_UPDATE); - else - time_offset = ltemp; - - /* - * Select whether the frequency is to be controlled and in which - * mode (PLL or FLL). Clamp to the operating range. Ugly - * multiply/divide should be replaced someday. - */ - if (time_status & STA_FREQHOLD || time_reftime == 0) - time_reftime = time_second; - mtemp = time_second - time_reftime; - time_reftime = time_second; - if (time_status & STA_FLL) { - if (mtemp >= MINSEC) { - ltemp = ((time_offset / mtemp) << (SHIFT_USEC - - SHIFT_UPDATE)); - if (ltemp < 0) - time_freq -= -ltemp >> SHIFT_KH; - else - time_freq += ltemp >> SHIFT_KH; - } - } else { - if (mtemp < MAXSEC) { - ltemp = time_offset * mtemp; - if (ltemp < 0) - time_freq -= -ltemp >> ((int64_t)time_constant + - time_constant + SHIFT_KF - - SHIFT_USEC + SHIFT_UPDATE); - else - time_freq += ltemp >> ((int64_t)time_constant + - time_constant + SHIFT_KF - - SHIFT_USEC + SHIFT_UPDATE); - } - } - if (time_freq > time_tolerance) - time_freq = time_tolerance; - else if (time_freq < -time_tolerance) - time_freq = -time_tolerance; -} +static void ntp_init(void); +static void hardupdate(long offset); /* - * On rollover of the second the phase adjustment to be used for - * the next second is calculated. Also, the maximum error is - * increased by the tolerance. If the PPS frequency discipline - * code is present, the phase is increased to compensate for the - * CPU clock oscillator frequency error. + * ntp_gettime() - NTP user application interface * - * On a 32-bit machine and given parameters in the timex.h - * header file, the maximum phase adjustment is +-512 ms and - * maximum frequency offset is a tad less than) +-512 ppm. On a - * 64-bit machine, you shouldn't need to ask. + * See the timex.h header file for synopsis and API description. */ -void -ntp_update_second(struct timecounter *tc) -{ - u_int32_t *newsec; - long ltemp; - - if (!time_daemon) - return; - - newsec = &tc->tc_offset_sec; - time_maxerror += time_tolerance >> SHIFT_USEC; - - /* - * Compute the phase adjustment for the next second. In - * PLL mode, the offset is reduced by a fixed factor - * times the time constant. In FLL mode the offset is - * used directly. In either mode, the maximum phase - * adjustment for each second is clamped so as to spread - * the adjustment over not more than the number of - * seconds between updates. - */ - if (time_offset < 0) { - ltemp = -time_offset; - if (!(time_status & STA_FLL)) - ltemp >>= SHIFT_KG + time_constant; - if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE) - ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE; - time_offset += ltemp; - time_adj = -ltemp << (SHIFT_SCALE - SHIFT_UPDATE); - } else { - ltemp = time_offset; - if (!(time_status & STA_FLL)) - ltemp >>= SHIFT_KG + time_constant; - if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE) - ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE; - time_offset -= ltemp; - time_adj = ltemp << (SHIFT_SCALE - SHIFT_UPDATE); - } - - /* - * Compute the frequency estimate and additional phase - * adjustment due to frequency error for the next - * second. When the PPS signal is engaged, gnaw on the - * watchdog counter and update the frequency computed by - * the pll and the PPS signal. - */ -#ifdef PPS_SYNC - pps_valid++; - if (pps_valid == PPS_VALID) { - pps_jitter = MAXTIME; - pps_stabil = MAXFREQ; - time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | - STA_PPSWANDER | STA_PPSERROR); - } - ltemp = time_freq + pps_freq; -#else - ltemp = time_freq; -#endif /* PPS_SYNC */ - if (ltemp < 0) - time_adj -= -ltemp << (SHIFT_SCALE - SHIFT_USEC); - else - time_adj += ltemp << (SHIFT_SCALE - SHIFT_USEC); - - tc->tc_adjustment = time_adj; - - /* XXX - this is really bogus, but can't be fixed until - xntpd's idea of the system clock is fixed to know how - the user wants leap seconds handled; in the mean time, - we assume that users of NTP are running without proper - leap second support (this is now the default anyway) */ - /* - * 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. The microtime() routine or - * external clock driver will insure that reported time - * is always monotonic. The ugly divides should be - * replaced. - */ - 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 ((*newsec) % 86400 == 0) { - (*newsec)--; - time_state = TIME_OOP; - } - break; - - case TIME_DEL: - if (((*newsec) + 1) % 86400 == 0) { - (*newsec)++; - time_state = TIME_WAIT; - } - break; - - case TIME_OOP: - time_state = TIME_WAIT; - break; - - case TIME_WAIT: - if (!(time_status & (STA_INS | STA_DEL))) - time_state = TIME_OK; - break; - } -} - static int ntp_sysctl SYSCTL_HANDLER_ARGS { - struct timeval atv; - struct ntptimeval ntv; - int s; + struct ntptimeval ntv; /* temporary structure */ + struct timespec atv; /* nanosecond time */ - s = splclock(); - microtime(&atv); - ntv.time = atv; + nanotime(&atv); + ntv.time.tv_sec = atv.tv_sec; + ntv.time.tv_nsec = atv.tv_nsec; ntv.maxerror = time_maxerror; ntv.esterror = time_esterror; - splx(s); - ntv.time_state = time_state; /* - * Status word error decode. If any of these conditions - * occur, an error is returned, instead of the status - * word. Most applications will care only about the fact - * the system clock may not be trusted, not about the - * details. + * Status word error decode. If any of these conditions occur, + * an error is returned, instead of the status word. Most + * applications will care only about the fact the system clock + * may not be trusted, not about the details. * * Hardware or software error */ - if (time_status & (STA_UNSYNC | STA_CLOCKERR)) { - ntv.time_state = TIME_ERROR; - } + if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || /* - * PPS signal lost when either time or frequency - * synchronization requested + * PPS signal lost when either time or frequency synchronization + * requested */ - if (time_status & (STA_PPSFREQ | STA_PPSTIME) && - !(time_status & STA_PPSSIGNAL)) { - ntv.time_state = TIME_ERROR; - } + (time_status & (STA_PPSFREQ | STA_PPSTIME) && + !(time_status & STA_PPSSIGNAL)) || /* - * PPS jitter exceeded when time synchronization - * requested + * PPS jitter exceeded when time synchronization requested */ - if (time_status & STA_PPSTIME && - time_status & STA_PPSJITTER) { - ntv.time_state = TIME_ERROR; - } + (time_status & STA_PPSTIME && + time_status & STA_PPSJITTER) || /* - * PPS wander exceeded or calibration error when - * frequency synchronization requested + * PPS wander exceeded or calibration error when frequency + * synchronization requested */ - if (time_status & STA_PPSFREQ && - time_status & (STA_PPSWANDER | STA_PPSERROR)) { + (time_status & STA_PPSFREQ && + time_status & (STA_PPSWANDER | STA_PPSERROR))) ntv.time_state = TIME_ERROR; - } return (sysctl_handle_opaque(oidp, &ntv, sizeof ntv, req)); } -SYSCTL_NODE(_kern, KERN_NTP_PLL, ntp_pll, CTLFLAG_RW, 0, - "NTP kernel PLL related stuff"); -SYSCTL_PROC(_kern_ntp_pll, NTP_PLL_GETTIME, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD, +SYSCTL_NODE(_kern, OID_AUTO, ntp_pll, CTLFLAG_RW, 0, ""); +SYSCTL_PROC(_kern_ntp_pll, OID_AUTO, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD, 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", ""); + /* * ntp_adjtime() - NTP daemon application interface + * + * See the timex.h header file for synopsis and API description. */ #ifndef _SYS_SYSPROTO_H_ struct ntp_adjtime_args { - struct timex *tp; + struct timex *tp; }; #endif int ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap) { - struct timex ntv; - int modes; - int s; + struct timex ntv; /* temporary structure */ + int modes; /* mode bits from structure */ + int s; /* caller priority */ int error; - time_daemon = 1; - error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv)); if (error) - return error; + return(error); /* * Update selected clock variables - only the superuser can @@ -509,17 +278,16 @@ ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap) * the assumption the superuser should know what it is doing. */ modes = ntv.modes; - if ((modes != 0) - && (error = suser(p->p_cred->pc_ucred, &p->p_acflag))) - return error; - + error = suser(p->p_cred->pc_ucred, &p->p_acflag); + if (error) + return (error); s = splclock(); - if (modes & MOD_FREQUENCY) + if (modes & MOD_FREQUENCY) { + L_LINT(time_freq, ntv.freq / SCALE_PPM); #ifdef PPS_SYNC - time_freq = ntv.freq - pps_freq; -#else /* PPS_SYNC */ - time_freq = ntv.freq; + pps_freq = time_freq; #endif /* PPS_SYNC */ + } if (modes & MOD_MAXERROR) time_maxerror = ntv.maxerror; if (modes & MOD_ESTERROR) @@ -530,93 +298,301 @@ ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap) } if (modes & MOD_TIMECONST) time_constant = ntv.constant; - if (modes & MOD_OFFSET) - hardupdate(ntv.offset, modes & MOD_DOSCALE); + if (modes & MOD_NANO) + time_status |= STA_NANO; + if (modes & MOD_MICRO) + time_status &= ~STA_NANO; + if (modes & MOD_CLKB) + time_status |= STA_CLK; + if (modes & MOD_CLKA) + time_status &= ~STA_CLK; + if (modes & MOD_OFFSET) { + if (time_status & STA_NANO) + hardupdate(ntv.offset); + else + hardupdate(ntv.offset * 1000); + } - ntv.modes |= MOD_CANSCALE; /* * Retrieve all clock variables */ - if (modes & MOD_DOSCALE) - ntv.offset = time_offset; - else if (time_offset < 0) - ntv.offset = -(-time_offset >> SHIFT_UPDATE); + if (time_status & STA_NANO) + ntv.offset = L_GINT(time_offset); else - ntv.offset = time_offset >> SHIFT_UPDATE; -#ifdef PPS_SYNC - ntv.freq = time_freq + pps_freq; -#else /* PPS_SYNC */ - ntv.freq = time_freq; -#endif /* PPS_SYNC */ + ntv.offset = L_GINT(time_offset) / 1000; + ntv.freq = L_GINT(time_freq) * SCALE_PPM; ntv.maxerror = time_maxerror; ntv.esterror = time_esterror; ntv.status = time_status; - ntv.constant = time_constant; - ntv.precision = time_precision; - ntv.tolerance = time_tolerance; + if (ntv.constant < 0) + time_constant = 0; + else if (ntv.constant > MAXTC) + time_constant = MAXTC; + else + time_constant = ntv.constant; + if (time_status & STA_NANO) + ntv.precision = time_precision; + else + ntv.precision = time_precision / 1000; + ntv.tolerance = MAXFREQ * SCALE_PPM; #ifdef PPS_SYNC ntv.shift = pps_shift; - ntv.ppsfreq = pps_freq; - ntv.jitter = pps_jitter >> PPS_AVG; + ntv.ppsfreq = L_GINT(pps_freq) * SCALE_PPM; + ntv.jitter = pps_jitter; + if (time_status & STA_NANO) + ntv.jitter = pps_jitter; + else + ntv.jitter = pps_jitter / 1000; ntv.stabil = pps_stabil; ntv.calcnt = pps_calcnt; ntv.errcnt = pps_errcnt; ntv.jitcnt = pps_jitcnt; ntv.stbcnt = pps_stbcnt; #endif /* PPS_SYNC */ - (void)splx(s); + splx(s); error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv)); - if (!error) { + if (error) + return (error); + + /* + * Status word error decode. See comments in + * ntp_gettime() routine. + */ + if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || + (time_status & (STA_PPSFREQ | STA_PPSTIME) && + !(time_status & STA_PPSSIGNAL)) || + (time_status & STA_PPSTIME && + time_status & STA_PPSJITTER) || + (time_status & STA_PPSFREQ && + time_status & (STA_PPSWANDER | STA_PPSERROR))) + return (TIME_ERROR); + return (time_state); +} + +/* + * second_overflow() - called after ntp_tick_adjust() + * + * This routine is ordinarily called immediately following the above + * routine ntp_tick_adjust(). While these two routines are normally + * combined, they are separated here only for the purposes of + * simulation. + */ +void +ntp_update_second(struct timecounter *tcp) +{ + u_int32_t *newsec; + l_fp ftemp, time_adj; /* 32/64-bit temporary */ + + newsec = &tcp->tc_offset_sec; + time_maxerror += MAXFREQ / 1000; + + /* + * 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. The nano_time() routine or + * external clock driver will insure that reported time + * is always monotonic. + */ + switch (time_state) { + + /* + * No warning. + */ + case TIME_OK: + if (time_status & STA_INS) + time_state = TIME_INS; + else if (time_status & STA_DEL) + time_state = TIME_DEL; + break; + + /* + * Insert second 23:59:60 following second + * 23:59:59. + */ + case TIME_INS: + if (!(time_status & STA_INS)) + time_state = TIME_OK; + else if ((*newsec) % 86400 == 0) { + (*newsec)--; + time_state = TIME_OOP; + } + break; + + /* + * Delete second 23:59:59. + */ + case TIME_DEL: + if (!(time_status & STA_DEL)) + time_state = TIME_OK; + else if (((*newsec) + 1) % 86400 == 0) { + (*newsec)++; + time_state = TIME_WAIT; + } + break; + + /* + * Insert second in progress. + */ + case TIME_OOP: + time_state = TIME_WAIT; + break; + /* - * Status word error decode. See comments in - * ntp_gettime() routine. + * Wait for status bits to clear. */ - p->p_retval[0] = time_state; - if (time_status & (STA_UNSYNC | STA_CLOCKERR)) - p->p_retval[0] = TIME_ERROR; - if (time_status & (STA_PPSFREQ | STA_PPSTIME) && - !(time_status & STA_PPSSIGNAL)) - p->p_retval[0] = TIME_ERROR; - if (time_status & STA_PPSTIME && - time_status & STA_PPSJITTER) - p->p_retval[0] = TIME_ERROR; - if (time_status & STA_PPSFREQ && - time_status & (STA_PPSWANDER | STA_PPSERROR)) - p->p_retval[0] = TIME_ERROR; + case TIME_WAIT: + if (!(time_status & (STA_INS | STA_DEL))) + time_state = TIME_OK; } - return error; + + /* + * Compute the total time adjustment for the next + * second in ns. The offset is reduced by a factor + * depending on FLL or PLL mode and whether the PPS + * signal is operating. Note that the value is in effect + * scaled by the clock frequency, since the adjustment + * is added at each tick interrupt. + */ + ftemp = time_offset; +#ifdef PPS_SYNC + if (time_status & STA_PPSTIME && time_status & + STA_PPSSIGNAL) + L_RSHIFT(ftemp, PPS_FAVG); + else if (time_status & STA_MODE) +#else + if (time_status & STA_MODE) +#endif /* PPS_SYNC */ + L_RSHIFT(ftemp, SHIFT_FLL); + else + L_RSHIFT(ftemp, SHIFT_PLL + time_constant); + time_adj = ftemp; + L_SUB(time_offset, ftemp); + L_ADD(time_adj, time_freq); + tcp->tc_adjustment = time_adj; +#ifdef PPS_SYNC + if (pps_valid > 0) + pps_valid--; + else + time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | + STA_PPSWANDER | STA_PPSERROR); +#endif /* PPS_SYNC */ } +/* + * ntp_init() - initialize variables and structures + * + * This routine must be called after the kernel variables hz and tick + * are set or changed and before the next tick interrupt. In this + * particular implementation, these values are assumed set elsewhere in + * the kernel. The design allows the clock frequency and tick interval + * to be changed while the system is running. So, this routine should + * probably be integrated with the code that does that. + */ +static void +ntp_init() +{ + + /* + * The following variable must be initialized any time the + * kernel variable hz is changed. + */ + time_tick = NANOSECOND / hz; + + /* + * The following variables are initialized only at startup. Only + * those structures not cleared by the compiler need to be + * initialized, and these only in the simulator. In the actual + * kernel, any nonzero values here will quickly evaporate. + */ + L_CLR(time_offset); + L_CLR(time_freq); #ifdef PPS_SYNC + pps_filt.sec = pps_filt.nsec = pps_filt.count = 0; + pps_tf[0] = pps_tf[1] = pps_tf[2] = pps_filt; + L_CLR(pps_freq); +#endif /* PPS_SYNC */ +} -/* We need this ugly monster twice, so let's macroize it. */ +SYSINIT(ntpclocks, SI_SUB_CLOCKS, SI_ORDER_FIRST, ntp_init, NULL) -#define MEDIAN3X(a, m, s, i1, i2, i3) \ - do { \ - m = a[i2]; \ - s = a[i1] - a[i3]; \ - } while (0) +/* + * hardupdate() - local clock update + * + * This routine is called by ntp_adjtime() to update the local clock + * phase and frequency. The implementation is of an adaptive-parameter, + * hybrid phase/frequency-lock loop (PLL/FLL). The routine computes new + * time and frequency offset estimates for each call. If the kernel PPS + * discipline code is configured (PPS_SYNC), the PPS signal itself + * determines the new time offset, instead of the calling argument. + * Presumably, calls to ntp_adjtime() occur only when the caller + * believes the local clock is valid within some bound (+-128 ms with + * NTP). If the caller's time is far different than the PPS time, an + * argument will ensue, and it's not clear who will lose. + * + * For uncompensated quartz crystal oscillators and nominal update + * intervals less than 256 s, operation should be in phase-lock mode, + * where the loop is disciplined to phase. For update intervals greater + * than 1024 s, operation should be in frequency-lock mode, where the + * loop is disciplined to frequency. Between 256 s and 1024 s, the mode + * is selected by the STA_MODE status bit. + */ +static void +hardupdate(offset) + long offset; /* clock offset (ns) */ +{ + long ltemp, mtemp; + l_fp ftemp; -#define MEDIAN3(a, m, s) \ - do { \ - if (a[0] > a[1]) { \ - if (a[1] > a[2]) \ - MEDIAN3X(a, m, s, 0, 1, 2); \ - else if (a[2] > a[0]) \ - MEDIAN3X(a, m, s, 2, 0, 1); \ - else \ - MEDIAN3X(a, m, s, 0, 2, 1); \ - } else { \ - if (a[2] > a[1]) \ - MEDIAN3X(a, m, s, 2, 1, 0); \ - else if (a[0] > a[2]) \ - MEDIAN3X(a, m, s, 1, 0, 2); \ - else \ - MEDIAN3X(a, m, s, 1, 2, 0); \ - } \ - } while (0) + /* + * Select how the phase is to be controlled and from which + * source. If the PPS signal is present and enabled to + * discipline the time, the PPS offset is used; otherwise, the + * argument offset is used. + */ + ltemp = offset; + if (ltemp > MAXPHASE) + ltemp = MAXPHASE; + else if (ltemp < -MAXPHASE) + ltemp = -MAXPHASE; + if (!(time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)) + L_LINT(time_offset, ltemp); + + /* + * Select how the frequency is to be controlled and in which + * mode (PLL or FLL). If the PPS signal is present and enabled + * to discipline the frequency, the PPS frequency is used; + * otherwise, the argument offset is used to compute it. + */ + if (time_status & STA_PPSFREQ && time_status & STA_PPSSIGNAL) { + time_reftime = time_second; + return; + } + if (time_status & STA_FREQHOLD || time_reftime == 0) + time_reftime = time_second; + mtemp = time_second - time_reftime; + if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC) + ) { + L_LINT(ftemp, (ltemp << 4) / mtemp); + L_RSHIFT(ftemp, SHIFT_FLL + 4); + L_ADD(time_freq, ftemp); + time_status |= STA_MODE; + } else { + L_LINT(ftemp, ltemp); + L_RSHIFT(ftemp, (SHIFT_PLL + 2 + time_constant) << 1); + L_MPY(ftemp, mtemp); + L_ADD(time_freq, ftemp); + time_status &= ~STA_MODE; + } + time_reftime = time_second; + if (L_GINT(time_freq) > MAXFREQ) + L_LINT(time_freq, MAXFREQ); + else if (L_GINT(time_freq) < -MAXFREQ) + L_LINT(time_freq, -MAXFREQ); +} +#ifdef PPS_SYNC /* * hardpps() - discipline CPU clock oscillator to external PPS signal * @@ -625,198 +601,216 @@ ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap) * and leaves it in a handy spot for the hardclock() routine. It * integrates successive PPS phase differences and calculates the * frequency offset. This is used in hardclock() to discipline the CPU - * clock oscillator so that intrinsic frequency error is cancelled out. - * The code requires the caller to capture the time and hardware counter - * value at the on-time PPS signal transition. + * clock oscillator so that the intrinsic frequency error is cancelled + * out. The code requires the caller to capture the time and + * architecture-dependent hardware counter values in nanoseconds at the + * on-time PPS signal transition. * - * Note that, on some Unix systems, this routine runs at an interrupt + * Note that, on some Unix systems this routine runs at an interrupt * priority level higher than the timer interrupt routine hardclock(). * Therefore, the variables used are distinct from the hardclock() - * variables, except for certain exceptions: The PPS frequency pps_freq - * and phase pps_offset variables are determined by this routine and - * updated atomically. The time_tolerance variable can be considered a - * constant, since it is infrequently changed, and then only when the - * PPS signal is disabled. The watchdog counter pps_valid is updated - * once per second by hardclock() and is atomically cleared in this - * routine. + * variables, except for the actual time and frequency variables, which + * are determined by this routine and updated atomically. */ void -hardpps(tvp, p_usec) - struct timeval *tvp; /* time at PPS */ - long p_usec; /* hardware counter at PPS */ +hardpps(tsp, nsec) + struct timespec *tsp; /* time at PPS */ + long nsec; /* hardware counter at PPS */ { - long u_usec, v_usec, bigtick; - long cal_sec, cal_usec; + long u_sec, u_nsec, v_nsec; /* temps */ + l_fp ftemp; /* - * An occasional glitch can be produced when the PPS interrupt - * occurs in the hardclock() routine before the time variable is - * updated. Here the offset is discarded when the difference - * between it and the last one is greater than tick/2, but not - * if the interval since the first discard exceeds 30 s. + * The signal is first processed by a frequency discriminator + * which rejects noise and input signals with frequencies + * outside the range 1 +-MAXFREQ PPS. If two hits occur in the + * same second, we ignore the later hit; if not and a hit occurs + * outside the range gate, keep the later hit but do not + * process it. */ - time_status |= STA_PPSSIGNAL; - time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); - pps_valid = 0; - u_usec = -tvp->tv_usec; - if (u_usec < -500000) - u_usec += 1000000; - v_usec = pps_offset - u_usec; - if (v_usec < 0) - v_usec = -v_usec; - if (v_usec > (tick >> 1)) { - if (pps_glitch > MAXGLITCH) { - pps_glitch = 0; - pps_tf[2] = u_usec; - pps_tf[1] = u_usec; - } else { - pps_glitch++; - u_usec = pps_offset; - } - } else - pps_glitch = 0; + time_status |= STA_PPSSIGNAL | STA_PPSJITTER; + time_status &= ~(STA_PPSWANDER | STA_PPSERROR); + pps_valid = PPS_VALID; + u_sec = tsp->tv_sec; + u_nsec = tsp->tv_nsec; + if (u_nsec >= (NANOSECOND >> 1)) { + u_nsec -= NANOSECOND; + u_sec++; + } + v_nsec = u_nsec - pps_tf[0].nsec; + if (u_sec == pps_tf[0].sec && v_nsec < -MAXFREQ) { + return; + } + pps_tf[2] = pps_tf[1]; + pps_tf[1] = pps_tf[0]; + pps_tf[0].sec = u_sec; + pps_tf[0].nsec = u_nsec; /* - * A three-stage median filter is used to help deglitch the pps + * Compute the difference between the current and previous + * counter values. If the difference exceeds 0.5 s, assume it + * has wrapped around, so correct 1.0 s. If the result exceeds + * the tick interval, the sample point has crossed a tick + * boundary during the last second, so correct the tick. Very + * intricate. + */ + u_nsec = nsec - pps_lastcount; + pps_lastcount = nsec; + if (u_nsec > (NANOSECOND >> 1)) + u_nsec -= NANOSECOND; + else if (u_nsec < -(NANOSECOND >> 1)) + u_nsec += NANOSECOND; + if (u_nsec > (time_tick >> 1)) + u_nsec -= time_tick; + else if (u_nsec < -(time_tick >> 1)) + u_nsec += time_tick; + pps_tf[0].count = pps_tf[1].count + u_nsec; + if (v_nsec > MAXFREQ) { + return; + } + time_status &= ~STA_PPSJITTER; + + /* + * A three-stage median filter is used to help denoise the PPS * time. The median sample becomes the time offset estimate; the * difference between the other two samples becomes the time * dispersion (jitter) estimate. */ - pps_tf[2] = pps_tf[1]; - pps_tf[1] = pps_tf[0]; - pps_tf[0] = u_usec; - MEDIAN3(pps_tf, pps_offset, v_usec); - if (v_usec > MAXTIME) - pps_jitcnt++; - v_usec = (v_usec << PPS_AVG) - pps_jitter; - if (v_usec < 0) - pps_jitter -= -v_usec >> PPS_AVG; - else - pps_jitter += v_usec >> PPS_AVG; - if (pps_jitter > (MAXTIME >> 1)) - time_status |= STA_PPSJITTER; + if (pps_tf[0].nsec > pps_tf[1].nsec) { + if (pps_tf[1].nsec > pps_tf[2].nsec) { + pps_filt = pps_tf[1]; /* 0 1 2 */ + u_nsec = pps_tf[0].nsec - pps_tf[2].nsec; + } else if (pps_tf[2].nsec > pps_tf[0].nsec) { + pps_filt = pps_tf[0]; /* 2 0 1 */ + u_nsec = pps_tf[2].nsec - pps_tf[1].nsec; + } else { + pps_filt = pps_tf[2]; /* 0 2 1 */ + u_nsec = pps_tf[0].nsec - pps_tf[1].nsec; + } + } else { + if (pps_tf[1].nsec < pps_tf[2].nsec) { + pps_filt = pps_tf[1]; /* 2 1 0 */ + u_nsec = pps_tf[2].nsec - pps_tf[0].nsec; + } else if (pps_tf[2].nsec < pps_tf[0].nsec) { + pps_filt = pps_tf[0]; /* 1 0 2 */ + u_nsec = pps_tf[1].nsec - pps_tf[2].nsec; + } else { + pps_filt = pps_tf[2]; /* 1 2 0 */ + u_nsec = pps_tf[1].nsec - pps_tf[0].nsec; + } + } /* - * During the calibration interval adjust the starting time when - * the tick overflows. At the end of the interval compute the - * duration of the interval and the difference of the hardware - * counters at the beginning and end of the interval. This code - * is deliciously complicated by the fact valid differences may - * exceed the value of tick when using long calibration - * intervals and small ticks. Note that the counter can be - * greater than tick if caught at just the wrong instant, but - * the values returned and used here are correct. + * Nominal jitter is due to PPS signal noise and interrupt + * latency. If it exceeds the jitter limit, the sample is + * discarded. otherwise, if so enabled, the time offset is + * updated. The offsets are accumulated over the phase averaging + * interval to improve accuracy. The jitter is averaged only for + * performance monitoring. We can tolerate a modest loss of data + * here without degrading time accuracy. */ - bigtick = (long)tick << SHIFT_USEC; - pps_usec -= pps_freq; - if (pps_usec >= bigtick) - pps_usec -= bigtick; - if (pps_usec < 0) - pps_usec += bigtick; - pps_time.tv_sec++; - pps_count++; - if (pps_count < (1 << pps_shift)) - return; - pps_count = 0; - pps_calcnt++; - u_usec = p_usec << SHIFT_USEC; - v_usec = pps_usec - u_usec; - if (v_usec >= bigtick >> 1) - v_usec -= bigtick; - if (v_usec < -(bigtick >> 1)) - v_usec += bigtick; - if (v_usec < 0) - v_usec = -(-v_usec >> pps_shift); - else - v_usec = v_usec >> pps_shift; - pps_usec = u_usec; - cal_sec = tvp->tv_sec; - cal_usec = tvp->tv_usec; - cal_sec -= pps_time.tv_sec; - cal_usec -= pps_time.tv_usec; - if (cal_usec < 0) { - cal_usec += 1000000; - cal_sec--; + if (u_nsec > MAXTIME) { + time_status |= STA_PPSJITTER; + pps_jitcnt++; + } else if (time_status & STA_PPSTIME) { + pps_offacc -= pps_filt.nsec; + pps_offcnt++; } - pps_time = *tvp; + if (pps_offcnt >= (1 << PPS_PAVG)) { + if (time_status & STA_PPSTIME) { + L_LINT(time_offset, pps_offacc); + L_RSHIFT(time_offset, PPS_PAVG); + } + pps_offacc = 0; + pps_offcnt = 0; + + } + pps_jitter += (u_nsec - pps_jitter) >> PPS_FAVG; + u_sec = pps_tf[0].sec - pps_lastsec; + if (u_sec < (1 << pps_shift)) + return; /* - * Check for lost interrupts, noise, excessive jitter and - * excessive frequency error. The number of timer ticks during - * the interval may vary +-1 tick. Add to this a margin of one - * tick for the PPS signal jitter and maximum frequency - * deviation. If the limits are exceeded, the calibration - * interval is reset to the minimum and we start over. + * At the end of the calibration interval the difference between + * the first and last counter values becomes the scaled + * frequency. It will later be divided by the length of the + * interval to determine the frequency update. If the frequency + * exceeds a sanity threshold, or if the actual calibration + * interval is not equal to the expected length, the data are + * discarded. We can tolerate a modest loss of data here without + * degrading frequency ccuracy. */ - u_usec = (long)tick << 1; - if (!((cal_sec == -1 && cal_usec > (1000000 - u_usec)) - || (cal_sec == 0 && cal_usec < u_usec)) - || v_usec > time_tolerance || v_usec < -time_tolerance) { - pps_errcnt++; - pps_shift = PPS_SHIFT; - pps_intcnt = 0; + pps_calcnt++; + v_nsec = -pps_filt.count; + pps_lastsec = pps_tf[0].sec; + pps_tf[0].count = 0; + u_nsec = MAXFREQ << pps_shift; + if (v_nsec > u_nsec || v_nsec < -u_nsec || u_sec != (1 << + pps_shift)) { time_status |= STA_PPSERROR; + pps_errcnt++; return; } /* - * A three-stage median filter is used to help deglitch the pps - * frequency. The median sample becomes the frequency offset - * estimate; the difference between the other two samples - * becomes the frequency dispersion (stability) estimate. + * If the actual calibration interval is not equal to the + * expected length, the data are discarded. If the wander is + * less than the wander threshold for four consecutive + * intervals, the interval is doubled; if it is greater than the + * threshold for four consecutive intervals, the interval is + * halved. The scaled frequency offset is converted to frequency + * offset. The stability metric is calculated as the average of + * recent frequency changes, but is used only for performance + * monitoring. */ - pps_ff[2] = pps_ff[1]; - pps_ff[1] = pps_ff[0]; - pps_ff[0] = v_usec; - MEDIAN3(pps_ff, u_usec, v_usec); - - /* - * Here the frequency dispersion (stability) is updated. If it - * is less than one-fourth the maximum (MAXFREQ), the frequency - * offset is updated as well, but clamped to the tolerance. It - * will be processed later by the hardclock() routine. - */ - v_usec = (v_usec >> 1) - pps_stabil; - if (v_usec < 0) - pps_stabil -= -v_usec >> PPS_AVG; - else - pps_stabil += v_usec >> PPS_AVG; - if (pps_stabil > MAXFREQ >> 2) { + L_LINT(ftemp, v_nsec); + L_RSHIFT(ftemp, pps_shift); + L_SUB(ftemp, pps_freq); + u_nsec = L_GINT(ftemp); + if (u_nsec > MAXWANDER) { + L_LINT(ftemp, MAXWANDER); + pps_intcnt--; + time_status |= STA_PPSWANDER; pps_stbcnt++; + } else if (u_nsec < -MAXWANDER) { + L_LINT(ftemp, -MAXWANDER); + pps_intcnt--; time_status |= STA_PPSWANDER; - return; + pps_stbcnt++; + } else { + pps_intcnt++; } - if (time_status & STA_PPSFREQ) { - if (u_usec < 0) { - pps_freq -= -u_usec >> PPS_AVG; - if (pps_freq < -time_tolerance) - pps_freq = -time_tolerance; - u_usec = -u_usec; - } else { - pps_freq += u_usec >> PPS_AVG; - if (pps_freq > time_tolerance) - pps_freq = time_tolerance; + if (pps_intcnt >= 4) { + pps_intcnt = 4; + if (pps_shift < PPS_FAVGMAX) { + pps_shift++; + pps_intcnt = 0; + } + } else if (pps_intcnt <= -4) { + pps_intcnt = -4; + if (pps_shift > PPS_FAVG) { + pps_shift--; + pps_intcnt = 0; } } + if (u_nsec < 0) + u_nsec = -u_nsec; + pps_stabil += (u_nsec * SCALE_PPM - pps_stabil) >> PPS_FAVG; /* - * Here the calibration interval is adjusted. If the maximum - * time difference is greater than tick / 4, reduce the interval - * by half. If this is not the case for four consecutive - * intervals, double the interval. + * The frequency offset is averaged into the PPS frequency. If + * enabled, the system clock frequency is updated as well. */ - if (u_usec << pps_shift > bigtick >> 2) { - pps_intcnt = 0; - if (pps_shift > PPS_SHIFT) - pps_shift--; - } else if (pps_intcnt >= 4) { - pps_intcnt = 0; - if (pps_shift < PPS_SHIFTMAX) - pps_shift++; - } else - pps_intcnt++; + L_RSHIFT(ftemp, PPS_FAVG); + L_ADD(pps_freq, ftemp); + u_nsec = L_GINT(pps_freq); + if (u_nsec > MAXFREQ) + L_LINT(pps_freq, MAXFREQ); + else if (u_nsec < -MAXFREQ) + L_LINT(pps_freq, -MAXFREQ); + if (time_status & STA_PPSFREQ) + time_freq = pps_freq; } - #endif /* PPS_SYNC */ int diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c index 0b35622..1c536ee 100644 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 - * $Id: kern_clock.c,v 1.87 1999/02/19 14:25:34 luoqi Exp $ + * $Id: kern_clock.c,v 1.88 1999/02/19 19:34:49 luoqi Exp $ */ #include <sys/param.h> @@ -675,10 +675,7 @@ tco_setscales(struct timecounter *tc) u_int64_t scale; scale = 1000000000LL << 32; - if (tc->tc_adjustment > 0) - scale += (tc->tc_adjustment * 1000LL) << 10; - else - scale -= (-tc->tc_adjustment * 1000LL) << 10; + scale += tc->tc_adjustment; scale /= tc->tc_frequency; tc->tc_scale_micro = scale / 1000; tc->tc_scale_nano_f = scale & 0xffffffff; diff --git a/sys/sys/time.h b/sys/sys/time.h index b6b7d28..e117c74 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)time.h 8.5 (Berkeley) 5/4/95 - * $Id: time.h,v 1.34 1998/10/23 10:42:42 phk Exp $ + * $Id: time.h,v 1.35 1998/12/15 17:38:32 des Exp $ */ #ifndef _SYS_TIME_H_ @@ -141,7 +141,7 @@ struct timecounter { char *tc_name; void *tc_priv; /* These fields will be managed by the generic code. */ - int32_t tc_adjustment; + int64_t tc_adjustment; u_int32_t tc_scale_micro; u_int32_t tc_scale_nano_i; u_int32_t tc_scale_nano_f; diff --git a/sys/sys/timetc.h b/sys/sys/timetc.h index b6b7d28..e117c74 100644 --- a/sys/sys/timetc.h +++ b/sys/sys/timetc.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)time.h 8.5 (Berkeley) 5/4/95 - * $Id: time.h,v 1.34 1998/10/23 10:42:42 phk Exp $ + * $Id: time.h,v 1.35 1998/12/15 17:38:32 des Exp $ */ #ifndef _SYS_TIME_H_ @@ -141,7 +141,7 @@ struct timecounter { char *tc_name; void *tc_priv; /* These fields will be managed by the generic code. */ - int32_t tc_adjustment; + int64_t tc_adjustment; u_int32_t tc_scale_micro; u_int32_t tc_scale_nano_i; u_int32_t tc_scale_nano_f; diff --git a/sys/sys/timex.h b/sys/sys/timex.h index 47fd808..a829045 100644 --- a/sys/sys/timex.h +++ b/sys/sys/timex.h @@ -1,22 +1,27 @@ -/****************************************************************************** - * * - * Copyright (c) David L. Mills 1993, 1994 * - * * - * Permission to use, copy, modify, and distribute this software and its * - * documentation for any purpose and without fee is hereby granted, provided * - * that the above copyright notice appears in all copies and that both the * - * copyright notice and this permission notice appear in supporting * - * documentation, and that the name University of Delaware not be used in * - * advertising or publicity pertaining to distribution of the software * - * without specific, written prior permission. The University of Delaware * - * makes no representations about the suitability this software for any * - * purpose. It is provided "as is" without express or implied warranty. * - * * - ******************************************************************************/ +/*********************************************************************** + * * + * Copyright (c) David L. Mills 1993-1998 * + * * + * Permission to use, copy, modify, and distribute this software and * + * its documentation for any purpose and without fee is hereby * + * granted, provided that the above copyright notice appears in all * + * copies and that both the copyright notice and this permission * + * notice appear in supporting documentation, and that the name * + * University of Delaware not be used in advertising or publicity * + * pertaining to distribution of the software without specific, * + * written prior permission. The University of Delaware makes no * + * representations about the suitability this software for any * + * purpose. It is provided "as is" without express or implied * + * warranty. * + * * + **********************************************************************/ /* * Modification history timex.h * + * 17 Nov 98 David L. Mills + * Revised for nanosecond kernel and user interface. + * * 26 Sep 94 David L. Mills * Added defines for hybrid phase/frequency-lock loop. * @@ -38,31 +43,50 @@ /* * This header file defines the Network Time Protocol (NTP) interfaces * for user and daemon application programs. These are implemented using - * private syscalls and data structures and require specific kernel + * defined syscalls and data structures and require specific kernel * support. * + * The original precision time kernels developed from 1993 have an + * ultimate resolution of one microsecond; however, the most recent + * kernels have an ultimate resolution of one nanosecond. In these + * kernels, a ntp_adjtime() syscalls can be used to determine which + * resolution is in use and to select either one at any time. The + * resolution selected affects the scaling of certain fields in the + * ntp_gettime() and ntp_adjtime() syscalls, as described below. + * * NAME * ntp_gettime - NTP user application interface * * SYNOPSIS * #include <sys/timex.h> + * #include <sys/syscall.h> * - * int syscall(SYS_ntp_gettime, tptr) + * int syscall(SYS_ntp_gettime, tptr); + * int SYS_ntp_gettime; + * struct ntptimeval *tptr; * - * int SYS_ntp_gettime defined in syscall.h header file - * struct ntptimeval *tptr pointer to ntptimeval structure + * DESCRIPTION + * The time returned by ntp_gettime() is in a timeval structure, + * but may be in either microsecond (seconds and microseconds) or + * nanosecond (seconds and nanoseconds) format. The particular + * format in use is determined by the STA_NANO bit of the status + * word returned by the ntp_adjtime() syscall. * * NAME * ntp_adjtime - NTP daemon application interface * * SYNOPSIS * #include <sys/timex.h> + * #include <sys/syscall.h> * - * int syscall(SYS_ntp_adjtime, mode, tptr) - * - * int SYS_ntp_adjtime defined in syscall.h header file - * struct timex *tptr pointer to timex structure + * int syscall(SYS_ntp_adjtime, tptr); + * struct timex *tptr; * + * DESCRIPTION + * Certain fields of the timex structure are interpreted in either + * microseconds or nanoseconds according to the state of the + * STA_NANO bit in the status word. See the description below for + * further information. */ #ifndef _SYS_TIMEX_H_ #define _SYS_TIMEX_H_ 1 @@ -72,138 +96,40 @@ #endif /* MSDOS */ /* - * The following defines establish the engineering parameters of the - * phase-lock loop (PLL) model used in the kernel implementation. These - * parameters have been carefully chosen by analysis for good stability - * and wide dynamic range. - * - * The hz variable is defined in the kernel build environment. It - * establishes the timer interrupt frequency, 100 Hz for the SunOS - * kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the OSF/1 - * kernel. SHIFT_HZ expresses the same value as the nearest power of two - * in order to avoid hardware multiply operations. - * - * SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen - * for a slightly underdamped convergence characteristic. SHIFT_KH - * establishes the damping of the FLL and is chosen by wisdom and black - * art. - * - * MAXTC establishes the maximum time constant of the PLL. With the - * SHIFT_KG and SHIFT_KF values given and a time constant range from - * zero to MAXTC, the PLL will converge in 15 minutes to 16 hours, - * respectively. - */ -#define SHIFT_HZ 7 /* log2(hz) */ -#define SHIFT_KG 6 /* phase factor (shift) */ -#define SHIFT_KF 16 /* PLL frequency factor (shift) */ -#define SHIFT_KH 2 /* FLL frequency factor (shift) */ -#define MAXTC 6 /* maximum time constant (shift) */ - -/* - * The following defines establish the scaling of the various variables - * used by the PLL. They are chosen to allow the greatest precision - * possible without overflow of a 32-bit word. - * - * SHIFT_SCALE defines the scaling (shift) of the time_phase variable, - * which serves as a an extension to the low-order bits of the system - * clock variable time.tv_usec. - * - * SHIFT_UPDATE defines the scaling (shift) of the time_offset variable, - * which represents the current time offset with respect to standard - * time. - * - * SHIFT_USEC defines the scaling (shift) of the time_freq and - * time_tolerance variables, which represent the current frequency - * offset and maximum frequency tolerance. - * - * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable. - */ -#define SHIFT_SCALE 22 /* phase scale (shift) */ -#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */ -#define SHIFT_USEC 16 /* frequency offset scale (shift) */ -#define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */ - -/* - * The following defines establish the performance envelope of the PLL. - * They insure it operates within predefined limits, in order to satisfy - * correctness assertions. An excursion which exceeds these bounds is - * clamped to the bound and operation proceeds accordingly. In practice, - * this can occur only if something has failed or is operating out of - * tolerance, but otherwise the PLL continues to operate in a stable - * mode. - * - * MAXPHASE must be set greater than or equal to CLOCK.MAX (128 ms), as - * defined in the NTP specification. CLOCK.MAX establishes the maximum - * time offset allowed before the system time is reset, rather than - * incrementally adjusted. Here, the maximum offset is clamped to - * MAXPHASE only in order to prevent overflow errors due to defective - * protocol implementations. - * - * MAXFREQ is the maximum frequency tolerance of the CPU clock - * oscillator plus the maximum slew rate allowed by the protocol. It - * should be set to at least the frequency tolerance of the oscillator - * plus 100 ppm for vernier frequency adjustments. If the kernel - * PPS discipline code is configured (PPS_SYNC), the oscillator time and - * frequency are disciplined to an external source, presumably with - * negligible time and frequency error relative to UTC, and MAXFREQ can - * be reduced. - * - * MAXTIME is the maximum jitter tolerance of the PPS signal if the - * kernel PPS discipline code is configured (PPS_SYNC). - * - * MINSEC and MAXSEC define the lower and upper bounds on the interval - * between protocol updates. - */ -#define MAXPHASE 512000L /* max phase error (us) */ -#ifdef PPS_SYNC -#define MAXFREQ (512L << SHIFT_USEC) /* max freq error (100 ppm) */ -#define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */ -#else -#define MAXFREQ (512L << SHIFT_USEC) /* max freq error (200 ppm) */ -#endif /* PPS_SYNC */ -#define MINSEC 16L /* min interval between updates (s) */ -#define MAXSEC 1200L /* max interval between updates (s) */ - -/* - * The following defines are used only if a pulse-per-second (PPS) - * signal is available and connected via a modem control lead, such as - * produced by the optional ppsclock feature incorporated in the Sun - * asynch driver. They establish the design parameters of the frequency- - * lock loop used to discipline the CPU clock oscillator to the PPS - * signal. - * - * PPS_AVG is the averaging factor for the frequency loop, as well as - * the time and frequency dispersion. - * - * PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum - * calibration intervals, respectively, in seconds as a power of two. - * - * PPS_VALID is the maximum interval before the PPS signal is considered - * invalid and protocol updates used directly instead. - * - * MAXGLITCH is the maximum interval before a time offset of more than - * MAXTIME is believed. + * The following defines establish the performance envelope of the + * kernel discipline loop. Phase or frequency errors greater than + * NAXPHASE or MAXFREQ are clamped to these maxima. For update intervals + * less than MINSEC, the loop always operates in PLL mode; while, for + * update intervals greater than MAXSEC, the loop always operates in FLL + * mode. Between these two limits the operating mode is selected by the + * STA_FLL bit in the status word. */ -#define PPS_AVG 2 /* pps averaging constant (shift) */ -#define PPS_SHIFT 2 /* min interval duration (s) (shift) */ -#define PPS_SHIFTMAX 8 /* max interval duration (s) (shift) */ -#define PPS_VALID 120 /* pps signal watchdog max (s) */ -#define MAXGLITCH 30 /* pps signal glitch max (s) */ +#define MAXPHASE 500000000L /* max phase error (ns) */ +#define MAXFREQ 500000L /* max freq error (ns/s) */ +#define MINSEC 256 /* min FLL update interval (s) */ +#define MAXSEC 1600 /* max PLL update interval (s) */ +#define NANOSECOND 1000000000L /* nanoseconds in one second */ +#define SCALE_PPM (65536 / 1000) /* crude ns/s to scaled PPM */ +#define MAXTC 10 /* max time constant in PLL mode */ /* * The following defines and structures define the user interface for - * the ntp_gettime() and ntp_adjtime() system calls. + * the ntp_gettime() and ntp_adjtime() syscalls. * - * Control mode codes (timex.modes) + * Control mode codes (timex.modes and nanotimex.modes) */ #define MOD_OFFSET 0x0001 /* set time offset */ #define MOD_FREQUENCY 0x0002 /* set frequency offset */ #define MOD_MAXERROR 0x0004 /* set maximum time error */ #define MOD_ESTERROR 0x0008 /* set estimated time error */ #define MOD_STATUS 0x0010 /* set clock status bits */ -#define MOD_TIMECONST 0x0020 /* set pll time constant */ -#define MOD_CANSCALE 0x0040 /* kernel can scale offset field */ -#define MOD_DOSCALE 0x0080 /* userland wants to scale offset field */ +#define MOD_TIMECONST 0x0020 /* set PLL time constant */ +#define MOD_PLL 0x0400 /* select default PLL mode */ +#define MOD_FLL 0x0800 /* select default FLL mode */ +#define MOD_MICRO 0x1000 /* select microsecond resolution */ +#define MOD_NANO 0x2000 /* select nanosecond resolution */ +#define MOD_CLKB 0x4000 /* select clock B */ +#define MOD_CLKA 0x8000 /* select clock A */ /* * Status codes (timex.status) @@ -211,22 +137,22 @@ #define STA_PLL 0x0001 /* enable PLL updates (rw) */ #define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */ #define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */ -#define STA_FLL 0x0008 /* select frequency-lock mode (rw) */ - +#define STA_FLL 0x0008 /* enable FLL mode (rw) */ #define STA_INS 0x0010 /* insert leap (rw) */ #define STA_DEL 0x0020 /* delete leap (rw) */ #define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */ #define STA_FREQHOLD 0x0080 /* hold frequency (rw) */ - #define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */ #define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */ #define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */ #define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */ - #define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */ +#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */ +#define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */ +#define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */ #define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ - STA_PPSERROR | STA_CLOCKERR) /* read-only bits */ + STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK) /* * Clock states (time_state) @@ -236,74 +162,65 @@ #define TIME_DEL 2 /* delete leap second warning */ #define TIME_OOP 3 /* leap second in progress */ #define TIME_WAIT 4 /* leap second has occured */ -#define TIME_ERROR 5 /* clock not synchronized */ +#define TIME_ERROR 5 /* error (see status word) */ /* * NTP user interface (ntp_gettime()) - used to read kernel clock values * - * Note: maximum error = NTP synch distance = dispersion + delay / 2; - * estimated error = NTP dispersion. + * Note: The time member is in microseconds if STA_NANO is zero and + * nanoseconds if not. */ struct ntptimeval { - struct timeval time; /* current time (ro) */ + struct timespec time; /* current time (ns) (ro) */ long maxerror; /* maximum error (us) (ro) */ long esterror; /* estimated error (us) (ro) */ - int time_state; /* what ntp_gettime returns */ + int time_state; /* time status */ }; /* - * NTP daemon interface - (ntp_adjtime()) used to discipline CPU clock - * oscillator + * NTP daemon interface (ntp_adjtime()) - used to discipline CPU clock + * oscillator and determine status. + * + * Note: The offset, precision and jitter members are in microseconds if + * STA_NANO is zero and nanoseconds if not. */ struct timex { unsigned int modes; /* clock mode bits (wo) */ - long offset; /* time offset (us) (rw) */ - long freq; /* frequency offset (scaled ppm) (rw) */ - long maxerror; /* maximum error (us) (rw) */ - long esterror; /* estimated error (us) (rw) */ - int status; /* clock status bits (rw) */ - long constant; /* pll time constant (rw) */ - long precision; /* clock precision (us) (ro) */ - long tolerance; /* clock frequency tolerance (scaled - * ppm) (ro) */ + long offset; /* time offset (ns/us) (rw) */ + long freq; /* frequency offset (scaled PPM) (rw) */ + long maxerror; /* maximum error (us) (rw) */ + long esterror; /* estimated error (us) (rw) */ + int status; /* clock status bits (rw) */ + long constant; /* poll interval (log2 s) (rw) */ + long precision; /* clock precision (ns/us) (ro) */ + long tolerance; /* clock frequency tolerance (scaled + * PPM) (ro) */ /* * The following read-only structure members are implemented * only if the PPS signal discipline is configured in the - * kernel. + * kernel. They are included in all configurations to insure + * portability. */ - long ppsfreq; /* pps frequency (scaled ppm) (ro) */ - long jitter; /* pps jitter (us) (ro) */ - int shift; /* interval duration (s) (shift) (ro) */ - long stabil; /* pps stability (scaled ppm) (ro) */ - long jitcnt; /* jitter limit exceeded (ro) */ - long calcnt; /* calibration intervals (ro) */ - long errcnt; /* calibration errors (ro) */ - long stbcnt; /* stability limit exceeded (ro) */ - + long ppsfreq; /* PPS frequency (scaled PPM) (ro) */ + long jitter; /* PPS jitter (ns/us) (ro) */ + int shift; /* interval duration (s) (shift) (ro) */ + long stabil; /* PPS stability (scaled PPM) (ro) */ + long jitcnt; /* jitter limit exceeded (ro) */ + long calcnt; /* calibration intervals (ro) */ + long errcnt; /* calibration errors (ro) */ + long stbcnt; /* stability limit exceeded (ro) */ }; -#ifdef __FreeBSD__ -/* - * sysctl identifiers underneath kern.ntp_pll - */ -#define NTP_PLL_GETTIME 1 /* used by ntp_gettime() */ -#define NTP_PLL_MAXID 2 /* number of valid ids */ - -#define NTP_PLL_NAMES { \ - { 0, 0 }, \ - { "gettime", CTLTYPE_STRUCT }, \ - } +#ifdef __FreeBSD__ #ifdef KERNEL void ntp_update_second __P((struct timecounter *tc)); -extern long time_phase; -extern long time_adj; #else #include <sys/cdefs.h> __BEGIN_DECLS -extern int ntp_gettime __P((struct ntptimeval *)); -extern int ntp_adjtime __P((struct timex *)); +extern int ntp_gettime __P((struct ntptimeval *)); +extern int ntp_adjtime __P((struct timex *)); __END_DECLS #endif /* not KERNEL */ |