summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_clock.c7
-rw-r--r--sys/kern/kern_ntptime.c1282
-rw-r--r--sys/kern/kern_tc.c7
-rw-r--r--sys/sys/time.h4
-rw-r--r--sys/sys/timetc.h4
-rw-r--r--sys/sys/timex.h297
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 */
OpenPOWER on IntegriCloud