+/*
+ * Phase-lock loop (PLL) definitions
+ *
+ * The following defines establish the performance envelope of the PLL.
+ * They specify the maximum phase error (MAXPHASE), maximum frequency
+ * error (MAXFREQ), minimum interval between updates (MINSEC) and
+ * maximum interval between updates (MAXSEC). The intent of these bounds
+ * is to force the PLL to operate 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 reflects the manufacturing 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 frequency discipline code is installed (PPS_SYNC), the CPU
+ * oscillator frequency is disciplined to an external source, presumably
+ * with negligible frequency error, and MAXFREQ can be reduced.
+ */
+#define MAXPHASE 512000L /* max phase error (us) */
+#ifdef PPS_SYNC
+#define MAXFREQ (100L << SHIFT_USEC) /* max freq error (scaled ppm) */
+#else
+#define MAXFREQ (200L << SHIFT_USEC) /* max freq error (scaled ppm) */
+#endif /* PPS_SYNC */
+#define MINSEC 16L /* min interval between updates (s) */
+#define MAXSEC 1200L /* max interval between updates (s) */
+
+/*
+ * The following variables are read and set by the ntp_adjtime() system
+ * call. The ntp_pll.status variable defines the synchronization status of
+ * the system clock, with codes defined in the timex.h header file. The
+ * time_offset variable is used by the PLL to adjust the system time in
+ * small increments. The time_constant variable determines the bandwidth
+ * or "stiffness" of the PLL. The time_tolerance variable is the 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. The time_precision variable 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. The
+ * time_maxerror variable is initialized by a ntp_adjtime() call and
+ * increased by the kernel once each second to reflect the maximum error
+ * bound growth. The time_esterror variable is set and read by the
+ * ntp_adjtime() call, but otherwise not used by the kernel.
+ */
+/* - use appropriate fields in ntp_pll instead */
+#if 0
+int ntp_pll.status = TIME_BAD; /* clock synchronization status */
+long time_offset = 0; /* time adjustment (us) */
+long time_constant = 0; /* pll time constant */
+long time_tolerance = MAXFREQ; /* frequency tolerance (scaled ppm) */
+long time_precision = 1; /* clock precision (us) */
+long time_maxerror = MAXPHASE; /* maximum error (us) */
+long time_esterror = MAXPHASE; /* estimated error (us) */
+#endif
+
+/*
+ * The following variables establish the state of the PLL and the
+ * residual time and frequency offset of the local clock. The time_phase
+ * variable is the phase increment and the ntp_pll.frequency variable is the
+ * frequency increment of the kernel time variable at each tick of the
+ * clock. The ntp_pll.frequency variable 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. The time_adj variable is the
+ * adjustment added to the value of tick at each timer interrupt and is
+ * recomputed at each timer interrupt. The time_reftime variable is the
+ * second's portion of the system time on the last call to
+ * ntp_adjtime(). It is used to adjust the ntp_pll.frequency variable and to
+ * increase the time_maxerror as the time since last update increases.
+ * The scale factors are defined in the timex.h header file.
+ */
+long time_phase = 0; /* phase offset (scaled us) */
+#if 0
+long ntp_pll.frequency = 0; /* frequency offset (scaled ppm) */
+#endif
+long time_adj = 0; /* tick adjust (scaled 1 / hz) */
+long time_reftime; /* time at last adjustment (s) */
+
+#ifdef PPS_SYNC
+/*
+ * The following defines and declarations 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 asynch driver. They establish the design parameters of the PPS
+ * frequency-lock loop used to discipline the CPU clock oscillator to
+ * the PPS signal. PPS_AVG is the averaging factor for the frequency
+ * loop. PPS_SHIFT and PPS_SHIFTMAX specify the minimum and maximum
+ * intervals, respectively, in seconds as a power of two. The
+ * PPS_DISPINC is the initial increment to pps_disp at each second.
+ */
+#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_DISPINC 0L /* dispersion increment (us/s) */
+
+/*
+ * The pps_time variable contains the time at each calibration as read
+ * by microtime(). The pps_usec variable 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. The pps_ybar variable is the current CPU
+ * oscillator frequency offset estimate relative to the PPS signal. The
+ * pps_disp variable is the current error estimate, which is increased
+ * pps_dispinc once each second. Frequency updates are permitted only
+ * when pps_disp is below the pps_dispmax threshold. The pps-mf[] array
+ * is used as a median filter for the frequency estimate and to derive
+ * the error estimate.
+ */
+struct timeval pps_time; /* kernel time at last interval */
+long pps_usec = 0; /* usec counter at last interval */
+#if 0
+long pps_ybar = 0; /* frequency estimate (scaled ppm) */
+long pps_disp = MAXFREQ; /* dispersion estimate (scaled ppm) */
+#endif
+long pps_dispmax = MAXFREQ / 2; /* dispersion threshold */
+long pps_dispinc = PPS_DISPINC; /* pps dispersion increment/sec */
+long pps_mf[] = {0, 0, 0}; /* pps median filter */
+
+/*
+ * The pps_count variable counts the seconds of the calibration
+ * interval, the duration of which is pps_shift (s) in powers of two.
+ * The pps_intcnt variable counts the calibration intervals for use in
+ * the interval-adaptation algorithm. It's just too complicated for
+ * words.
+ */
+int pps_count = 0; /* calibration interval counter (s) */
+#if 0
+int pps_shift = PPS_SHIFT; /* interval duration (s) (shift) */
+#endif
+int pps_intcnt = 0; /* intervals at current duration */
+
+/*
+ * PPS signal quality monitors
+ */
+#if 0
+long pps_calcnt; /* calibration intervals */
+long pps_jitcnt; /* jitter limit exceeded */
+long pps_discnt; /* dispersion limit exceeded */
+#endif
+#endif /* PPS_SYNC */
+
+struct timex ntp_pll = {
+ 0, /* mode */
+ 0, /* offset */
+ 0, /* frequency */
+ MAXPHASE, /* maxerror */
+ MAXPHASE, /* esterror */
+ TIME_BAD, /* status */
+ 0, /* time_constant */
+ 1, /* precision */
+ MAXFREQ, /* tolerance */
+ 0, /* ybar */
+#ifdef PPS_SYNC
+ MAXFREQ, /* disp */
+ PPS_SHIFT, /* shift */
+ 0, /* calcnt */
+ 0, /* jitcnt */
+ 0 /* discnt */
+#endif
+};
+
+/*
+ * hardupdate() - local clock update
+ *
+ * This routine is called by ntp_adjtime() to update the local clock
+ * phase and frequency. This is used to implement an adaptive-parameter,
+ * first-order, type-II phase-lock loop. The code computes the time
+ * since the last update and clamps to a maximum (for robustness). Then
+ * it multiplies by the offset (sorry about the ugly multiply), scales
+ * by the time constant, and adds to the frequency variable. Then, it
+ * computes the phase variable as the offset scaled by the time
+ * constant. Note that all shifts are assumed to be positive. Only
+ * enough error checking is done to prevent bizarre behavior due to
+ * overflow problems.
+ *
+ * For default SHIFT_UPDATE = 12, the offset is limited to +-512 ms, the
+ * maximum interval between updates is 4096 s and the maximum frequency
+ * offset is +-31.25 ms/s.
+ */
+void
+hardupdate(offset)
+ long offset;
+{
+ long mtemp;
+
+ if (offset > MAXPHASE)
+ ntp_pll.offset = MAXPHASE << SHIFT_UPDATE;
+ else if (offset < -MAXPHASE)
+ ntp_pll.offset = -(MAXPHASE << SHIFT_UPDATE);
+ else
+ ntp_pll.offset = offset << SHIFT_UPDATE;
+ mtemp = time.tv_sec - time_reftime;
+ time_reftime = time.tv_sec;
+ if (mtemp > MAXSEC)
+ mtemp = 0;
+
+ /* ugly multiply should be replaced */
+ if (offset < 0)
+ ntp_pll.frequency -=
+ (-offset * mtemp) >> (ntp_pll.time_constant
+ + ntp_pll.time_constant
+ + SHIFT_KF
+ - SHIFT_USEC);
+ else
+ ntp_pll.frequency +=
+ (offset * mtemp) >> (ntp_pll.time_constant
+ + ntp_pll.time_constant
+ + SHIFT_KF
+ - SHIFT_USEC);
+ if (ntp_pll.frequency > ntp_pll.tolerance)
+ ntp_pll.frequency = ntp_pll.tolerance;
+ else if (ntp_pll.frequency < -ntp_pll.tolerance)
+ ntp_pll.frequency = -ntp_pll.tolerance;
+ if (ntp_pll.status == TIME_BAD)
+ ntp_pll.status = TIME_OK;
+}
+