13f31c649SGarrett Wollman /****************************************************************************** 23f31c649SGarrett Wollman * * 33f31c649SGarrett Wollman * Copyright (c) David L. Mills 1993, 1994 * 43f31c649SGarrett Wollman * * 53f31c649SGarrett Wollman * Permission to use, copy, modify, and distribute this software and its * 63f31c649SGarrett Wollman * documentation for any purpose and without fee is hereby granted, provided * 73f31c649SGarrett Wollman * that the above copyright notice appears in all copies and that both the * 83f31c649SGarrett Wollman * copyright notice and this permission notice appear in supporting * 93f31c649SGarrett Wollman * documentation, and that the name University of Delaware not be used in * 103f31c649SGarrett Wollman * advertising or publicity pertaining to distribution of the software * 113f31c649SGarrett Wollman * without specific, written prior permission. The University of Delaware * 123f31c649SGarrett Wollman * makes no representations about the suitability this software for any * 133f31c649SGarrett Wollman * purpose. It is provided "as is" without express or implied warranty. * 143f31c649SGarrett Wollman * * 153f31c649SGarrett Wollman ******************************************************************************/ 163f31c649SGarrett Wollman 173f31c649SGarrett Wollman /* 183f31c649SGarrett Wollman * Modification history kern_ntptime.c 193f31c649SGarrett Wollman * 20885bd8e4SJohn Hay * 24 Sep 94 David L. Mills 21885bd8e4SJohn Hay * Tightened code at exits. 22885bd8e4SJohn Hay * 233f31c649SGarrett Wollman * 24 Mar 94 David L. Mills 243f31c649SGarrett Wollman * Revised syscall interface to include new variables for PPS 253f31c649SGarrett Wollman * time discipline. 263f31c649SGarrett Wollman * 273f31c649SGarrett Wollman * 14 Feb 94 David L. Mills 283f31c649SGarrett Wollman * Added code for external clock 293f31c649SGarrett Wollman * 303f31c649SGarrett Wollman * 28 Nov 93 David L. Mills 313f31c649SGarrett Wollman * Revised frequency scaling to conform with adjusted parameters 323f31c649SGarrett Wollman * 333f31c649SGarrett Wollman * 17 Sep 93 David L. Mills 343f31c649SGarrett Wollman * Created file 353f31c649SGarrett Wollman */ 363f31c649SGarrett Wollman /* 373f31c649SGarrett Wollman * ntp_gettime(), ntp_adjtime() - precision time interface for SunOS 38885bd8e4SJohn Hay * V4.1.1 and V4.1.3 393f31c649SGarrett Wollman * 403f31c649SGarrett Wollman * These routines consitute the Network Time Protocol (NTP) interfaces 413f31c649SGarrett Wollman * for user and daemon application programs. The ntp_gettime() routine 423f31c649SGarrett Wollman * provides the time, maximum error (synch distance) and estimated error 433f31c649SGarrett Wollman * (dispersion) to client user application programs. The ntp_adjtime() 443f31c649SGarrett Wollman * routine is used by the NTP daemon to adjust the system clock to an 453f31c649SGarrett Wollman * externally derived time. The time offset and related variables set by 463f31c649SGarrett Wollman * this routine are used by hardclock() to adjust the phase and 473f31c649SGarrett Wollman * frequency of the phase-lock loop which controls the system clock. 483f31c649SGarrett Wollman */ 49e0d781f3SEivind Eklund 50e0d781f3SEivind Eklund #include "opt_ntp.h" 51e0d781f3SEivind Eklund 523f31c649SGarrett Wollman #include <sys/param.h> 533f31c649SGarrett Wollman #include <sys/systm.h> 54d2d3e875SBruce Evans #include <sys/sysproto.h> 553f31c649SGarrett Wollman #include <sys/kernel.h> 563f31c649SGarrett Wollman #include <sys/proc.h> 573f31c649SGarrett Wollman #include <sys/timex.h> 583f31c649SGarrett Wollman #include <sys/sysctl.h> 593f31c649SGarrett Wollman 603f31c649SGarrett Wollman /* 616f70df15SPoul-Henning Kamp * Phase/frequency-lock loop (PLL/FLL) definitions 626f70df15SPoul-Henning Kamp * 636f70df15SPoul-Henning Kamp * The following variables are read and set by the ntp_adjtime() system 646f70df15SPoul-Henning Kamp * call. 656f70df15SPoul-Henning Kamp * 666f70df15SPoul-Henning Kamp * time_state shows the state of the system clock, with values defined 676f70df15SPoul-Henning Kamp * in the timex.h header file. 686f70df15SPoul-Henning Kamp * 696f70df15SPoul-Henning Kamp * time_status shows the status of the system clock, with bits defined 706f70df15SPoul-Henning Kamp * in the timex.h header file. 716f70df15SPoul-Henning Kamp * 726f70df15SPoul-Henning Kamp * time_offset is used by the PLL/FLL to adjust the system time in small 736f70df15SPoul-Henning Kamp * increments. 746f70df15SPoul-Henning Kamp * 756f70df15SPoul-Henning Kamp * time_constant determines the bandwidth or "stiffness" of the PLL. 766f70df15SPoul-Henning Kamp * 776f70df15SPoul-Henning Kamp * time_tolerance determines maximum frequency error or tolerance of the 786f70df15SPoul-Henning Kamp * CPU clock oscillator and is a property of the architecture; however, 796f70df15SPoul-Henning Kamp * in principle it could change as result of the presence of external 806f70df15SPoul-Henning Kamp * discipline signals, for instance. 816f70df15SPoul-Henning Kamp * 826f70df15SPoul-Henning Kamp * time_precision is usually equal to the kernel tick variable; however, 836f70df15SPoul-Henning Kamp * in cases where a precision clock counter or external clock is 846f70df15SPoul-Henning Kamp * available, the resolution can be much less than this and depend on 856f70df15SPoul-Henning Kamp * whether the external clock is working or not. 866f70df15SPoul-Henning Kamp * 876f70df15SPoul-Henning Kamp * time_maxerror is initialized by a ntp_adjtime() call and increased by 886f70df15SPoul-Henning Kamp * the kernel once each second to reflect the maximum error 896f70df15SPoul-Henning Kamp * bound growth. 906f70df15SPoul-Henning Kamp * 916f70df15SPoul-Henning Kamp * time_esterror is set and read by the ntp_adjtime() call, but 926f70df15SPoul-Henning Kamp * otherwise not used by the kernel. 933f31c649SGarrett Wollman */ 946f70df15SPoul-Henning Kamp static int time_status = STA_UNSYNC; /* clock status bits */ 956f70df15SPoul-Henning Kamp static int time_state = TIME_OK; /* clock state */ 966f70df15SPoul-Henning Kamp static long time_offset = 0; /* time offset (us) */ 976f70df15SPoul-Henning Kamp static long time_constant = 0; /* pll time constant */ 986f70df15SPoul-Henning Kamp static long time_tolerance = MAXFREQ; /* frequency tolerance (scaled ppm) */ 996f70df15SPoul-Henning Kamp static long time_precision = 1; /* clock precision (us) */ 1006f70df15SPoul-Henning Kamp static long time_maxerror = MAXPHASE; /* maximum error (us) */ 1016f70df15SPoul-Henning Kamp static long time_esterror = MAXPHASE; /* estimated error (us) */ 1026f70df15SPoul-Henning Kamp 1036f70df15SPoul-Henning Kamp /* 1046f70df15SPoul-Henning Kamp * The following variables establish the state of the PLL/FLL and the 1056f70df15SPoul-Henning Kamp * residual time and frequency offset of the local clock. The scale 1066f70df15SPoul-Henning Kamp * factors are defined in the timex.h header file. 1076f70df15SPoul-Henning Kamp * 1086f70df15SPoul-Henning Kamp * time_phase and time_freq are the phase increment and the frequency 1096f70df15SPoul-Henning Kamp * increment, respectively, of the kernel time variable at each tick of 1106f70df15SPoul-Henning Kamp * the clock. 1116f70df15SPoul-Henning Kamp * 1126f70df15SPoul-Henning Kamp * time_freq is set via ntp_adjtime() from a value stored in a file when 1136f70df15SPoul-Henning Kamp * the synchronization daemon is first started. Its value is retrieved 1146f70df15SPoul-Henning Kamp * via ntp_adjtime() and written to the file about once per hour by the 1156f70df15SPoul-Henning Kamp * daemon. 1166f70df15SPoul-Henning Kamp * 1176f70df15SPoul-Henning Kamp * time_adj is the adjustment added to the value of tick at each timer 1186f70df15SPoul-Henning Kamp * interrupt and is recomputed from time_phase and time_freq at each 1196f70df15SPoul-Henning Kamp * seconds rollover. 1206f70df15SPoul-Henning Kamp * 1216f70df15SPoul-Henning Kamp * time_reftime is the second's portion of the system time on the last 1226f70df15SPoul-Henning Kamp * call to ntp_adjtime(). It is used to adjust the time_freq variable 1236f70df15SPoul-Henning Kamp * and to increase the time_maxerror as the time since last update 1246f70df15SPoul-Henning Kamp * increases. 1256f70df15SPoul-Henning Kamp */ 1266f70df15SPoul-Henning Kamp long time_phase = 0; /* phase offset (scaled us) */ 1276f70df15SPoul-Henning Kamp static long time_freq = 0; /* frequency offset (scaled ppm) */ 1286f70df15SPoul-Henning Kamp long time_adj = 0; /* tick adjust (scaled 1 / hz) */ 1296f70df15SPoul-Henning Kamp static long time_reftime = 0; /* time at last adjustment (s) */ 1303f31c649SGarrett Wollman 1313f31c649SGarrett Wollman #ifdef PPS_SYNC 1323f31c649SGarrett Wollman /* 1336f70df15SPoul-Henning Kamp * The following variables are used only if the kernel PPS discipline 1346f70df15SPoul-Henning Kamp * code is configured (PPS_SYNC). The scale factors are defined in the 1356f70df15SPoul-Henning Kamp * timex.h header file. 1366f70df15SPoul-Henning Kamp * 1376f70df15SPoul-Henning Kamp * pps_time contains the time at each calibration interval, as read by 1386f70df15SPoul-Henning Kamp * microtime(). pps_count counts the seconds of the calibration 1396f70df15SPoul-Henning Kamp * interval, the duration of which is nominally pps_shift in powers of 1406f70df15SPoul-Henning Kamp * two. 1416f70df15SPoul-Henning Kamp * 1426f70df15SPoul-Henning Kamp * pps_offset is the time offset produced by the time median filter 1436f70df15SPoul-Henning Kamp * pps_tf[], while pps_jitter is the dispersion (jitter) measured by 1446f70df15SPoul-Henning Kamp * this filter. 1456f70df15SPoul-Henning Kamp * 1466f70df15SPoul-Henning Kamp * pps_freq is the frequency offset produced by the frequency median 1476f70df15SPoul-Henning Kamp * filter pps_ff[], while pps_stabil is the dispersion (wander) measured 1486f70df15SPoul-Henning Kamp * by this filter. 1496f70df15SPoul-Henning Kamp * 1506f70df15SPoul-Henning Kamp * pps_usec is latched from a high resolution counter or external clock 1516f70df15SPoul-Henning Kamp * at pps_time. Here we want the hardware counter contents only, not the 1526f70df15SPoul-Henning Kamp * contents plus the time_tv.usec as usual. 1536f70df15SPoul-Henning Kamp * 1546f70df15SPoul-Henning Kamp * pps_valid counts the number of seconds since the last PPS update. It 1556f70df15SPoul-Henning Kamp * is used as a watchdog timer to disable the PPS discipline should the 1566f70df15SPoul-Henning Kamp * PPS signal be lost. 1576f70df15SPoul-Henning Kamp * 1586f70df15SPoul-Henning Kamp * pps_glitch counts the number of seconds since the beginning of an 1596f70df15SPoul-Henning Kamp * offset burst more than tick/2 from current nominal offset. It is used 1606f70df15SPoul-Henning Kamp * mainly to suppress error bursts due to priority conflicts between the 1616f70df15SPoul-Henning Kamp * PPS interrupt and timer interrupt. 1626f70df15SPoul-Henning Kamp * 1636f70df15SPoul-Henning Kamp * pps_intcnt counts the calibration intervals for use in the interval- 1646f70df15SPoul-Henning Kamp * adaptation algorithm. It's just too complicated for words. 1653f31c649SGarrett Wollman */ 1666f70df15SPoul-Henning Kamp static struct timeval pps_time; /* kernel time at last interval */ 1676f70df15SPoul-Henning Kamp static long pps_offset = 0; /* pps time offset (us) */ 1686f70df15SPoul-Henning Kamp static long pps_jitter = MAXTIME; /* pps time dispersion (jitter) (us) */ 1696f70df15SPoul-Henning Kamp static long pps_tf[] = {0, 0, 0}; /* pps time offset median filter (us) */ 1706f70df15SPoul-Henning Kamp static long pps_freq = 0; /* frequency offset (scaled ppm) */ 1716f70df15SPoul-Henning Kamp static long pps_stabil = MAXFREQ; /* frequency dispersion (scaled ppm) */ 1726f70df15SPoul-Henning Kamp static long pps_ff[] = {0, 0, 0}; /* frequency offset median filter */ 1736f70df15SPoul-Henning Kamp static long pps_usec = 0; /* microsec counter at last interval */ 1746f70df15SPoul-Henning Kamp static long pps_valid = PPS_VALID; /* pps signal watchdog counter */ 1756f70df15SPoul-Henning Kamp static int pps_glitch = 0; /* pps signal glitch counter */ 1766f70df15SPoul-Henning Kamp static int pps_count = 0; /* calibration interval counter (s) */ 1776f70df15SPoul-Henning Kamp static int pps_shift = PPS_SHIFT; /* interval duration (s) (shift) */ 1786f70df15SPoul-Henning Kamp static int pps_intcnt = 0; /* intervals at current duration */ 1796f70df15SPoul-Henning Kamp 1806f70df15SPoul-Henning Kamp /* 1816f70df15SPoul-Henning Kamp * PPS signal quality monitors 1826f70df15SPoul-Henning Kamp * 1836f70df15SPoul-Henning Kamp * pps_jitcnt counts the seconds that have been discarded because the 1846f70df15SPoul-Henning Kamp * jitter measured by the time median filter exceeds the limit MAXTIME 1856f70df15SPoul-Henning Kamp * (100 us). 1866f70df15SPoul-Henning Kamp * 1876f70df15SPoul-Henning Kamp * pps_calcnt counts the frequency calibration intervals, which are 1886f70df15SPoul-Henning Kamp * variable from 4 s to 256 s. 1896f70df15SPoul-Henning Kamp * 1906f70df15SPoul-Henning Kamp * pps_errcnt counts the calibration intervals which have been discarded 1916f70df15SPoul-Henning Kamp * because the wander exceeds the limit MAXFREQ (100 ppm) or where the 1926f70df15SPoul-Henning Kamp * calibration interval jitter exceeds two ticks. 1936f70df15SPoul-Henning Kamp * 1946f70df15SPoul-Henning Kamp * pps_stbcnt counts the calibration intervals that have been discarded 1956f70df15SPoul-Henning Kamp * because the frequency wander exceeds the limit MAXFREQ / 4 (25 us). 1966f70df15SPoul-Henning Kamp */ 1976f70df15SPoul-Henning Kamp static long pps_jitcnt = 0; /* jitter limit exceeded */ 1986f70df15SPoul-Henning Kamp static long pps_calcnt = 0; /* calibration intervals */ 1996f70df15SPoul-Henning Kamp static long pps_errcnt = 0; /* calibration errors */ 2006f70df15SPoul-Henning Kamp static long pps_stbcnt = 0; /* stability limit exceeded */ 2013f31c649SGarrett Wollman #endif /* PPS_SYNC */ 2023f31c649SGarrett Wollman 2036f70df15SPoul-Henning Kamp static void hardupdate __P((long offset)); 2046f70df15SPoul-Henning Kamp 2056f70df15SPoul-Henning Kamp /* 2066f70df15SPoul-Henning Kamp * hardupdate() - local clock update 2076f70df15SPoul-Henning Kamp * 2086f70df15SPoul-Henning Kamp * This routine is called by ntp_adjtime() to update the local clock 2096f70df15SPoul-Henning Kamp * phase and frequency. The implementation is of an adaptive-parameter, 2106f70df15SPoul-Henning Kamp * hybrid phase/frequency-lock loop (PLL/FLL). The routine computes new 2116f70df15SPoul-Henning Kamp * time and frequency offset estimates for each call. If the kernel PPS 2126f70df15SPoul-Henning Kamp * discipline code is configured (PPS_SYNC), the PPS signal itself 2136f70df15SPoul-Henning Kamp * determines the new time offset, instead of the calling argument. 2146f70df15SPoul-Henning Kamp * Presumably, calls to ntp_adjtime() occur only when the caller 2156f70df15SPoul-Henning Kamp * believes the local clock is valid within some bound (+-128 ms with 2166f70df15SPoul-Henning Kamp * NTP). If the caller's time is far different than the PPS time, an 2176f70df15SPoul-Henning Kamp * argument will ensue, and it's not clear who will lose. 2186f70df15SPoul-Henning Kamp * 2196f70df15SPoul-Henning Kamp * For uncompensated quartz crystal oscillatores and nominal update 2206f70df15SPoul-Henning Kamp * intervals less than 1024 s, operation should be in phase-lock mode 2216f70df15SPoul-Henning Kamp * (STA_FLL = 0), where the loop is disciplined to phase. For update 2226f70df15SPoul-Henning Kamp * intervals greater than thiss, operation should be in frequency-lock 2236f70df15SPoul-Henning Kamp * mode (STA_FLL = 1), where the loop is disciplined to frequency. 2246f70df15SPoul-Henning Kamp * 2256f70df15SPoul-Henning Kamp * Note: splclock() is in effect. 2266f70df15SPoul-Henning Kamp */ 2276f70df15SPoul-Henning Kamp static void 2286f70df15SPoul-Henning Kamp hardupdate(offset) 2296f70df15SPoul-Henning Kamp long offset; 2306f70df15SPoul-Henning Kamp { 2316f70df15SPoul-Henning Kamp long ltemp, mtemp; 2326f70df15SPoul-Henning Kamp 2336f70df15SPoul-Henning Kamp if (!(time_status & STA_PLL) && !(time_status & STA_PPSTIME)) 2346f70df15SPoul-Henning Kamp return; 2356f70df15SPoul-Henning Kamp ltemp = offset; 2366f70df15SPoul-Henning Kamp #ifdef PPS_SYNC 2376f70df15SPoul-Henning Kamp if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL) 2386f70df15SPoul-Henning Kamp ltemp = pps_offset; 2396f70df15SPoul-Henning Kamp #endif /* PPS_SYNC */ 2406f70df15SPoul-Henning Kamp 2416f70df15SPoul-Henning Kamp /* 2426f70df15SPoul-Henning Kamp * Scale the phase adjustment and clamp to the operating range. 2436f70df15SPoul-Henning Kamp */ 2446f70df15SPoul-Henning Kamp if (ltemp > MAXPHASE) 2456f70df15SPoul-Henning Kamp time_offset = MAXPHASE << SHIFT_UPDATE; 2466f70df15SPoul-Henning Kamp else if (ltemp < -MAXPHASE) 2476f70df15SPoul-Henning Kamp time_offset = -(MAXPHASE << SHIFT_UPDATE); 2486f70df15SPoul-Henning Kamp else 2496f70df15SPoul-Henning Kamp time_offset = ltemp << SHIFT_UPDATE; 2506f70df15SPoul-Henning Kamp 2516f70df15SPoul-Henning Kamp /* 2526f70df15SPoul-Henning Kamp * Select whether the frequency is to be controlled and in which 2536f70df15SPoul-Henning Kamp * mode (PLL or FLL). Clamp to the operating range. Ugly 2546f70df15SPoul-Henning Kamp * multiply/divide should be replaced someday. 2556f70df15SPoul-Henning Kamp */ 2566f70df15SPoul-Henning Kamp if (time_status & STA_FREQHOLD || time_reftime == 0) 2576f70df15SPoul-Henning Kamp time_reftime = time.tv_sec; 2586f70df15SPoul-Henning Kamp mtemp = time.tv_sec - time_reftime; 2596f70df15SPoul-Henning Kamp time_reftime = time.tv_sec; 2606f70df15SPoul-Henning Kamp if (time_status & STA_FLL) { 2616f70df15SPoul-Henning Kamp if (mtemp >= MINSEC) { 2626f70df15SPoul-Henning Kamp ltemp = ((time_offset / mtemp) << (SHIFT_USEC - 2636f70df15SPoul-Henning Kamp SHIFT_UPDATE)); 2646f70df15SPoul-Henning Kamp if (ltemp < 0) 2656f70df15SPoul-Henning Kamp time_freq -= -ltemp >> SHIFT_KH; 2666f70df15SPoul-Henning Kamp else 2676f70df15SPoul-Henning Kamp time_freq += ltemp >> SHIFT_KH; 2686f70df15SPoul-Henning Kamp } 2696f70df15SPoul-Henning Kamp } else { 2706f70df15SPoul-Henning Kamp if (mtemp < MAXSEC) { 2716f70df15SPoul-Henning Kamp ltemp *= mtemp; 2726f70df15SPoul-Henning Kamp if (ltemp < 0) 2736f70df15SPoul-Henning Kamp time_freq -= -ltemp >> (time_constant + 2746f70df15SPoul-Henning Kamp time_constant + SHIFT_KF - 2756f70df15SPoul-Henning Kamp SHIFT_USEC); 2766f70df15SPoul-Henning Kamp else 2776f70df15SPoul-Henning Kamp time_freq += ltemp >> (time_constant + 2786f70df15SPoul-Henning Kamp time_constant + SHIFT_KF - 2796f70df15SPoul-Henning Kamp SHIFT_USEC); 2806f70df15SPoul-Henning Kamp } 2816f70df15SPoul-Henning Kamp } 2826f70df15SPoul-Henning Kamp if (time_freq > time_tolerance) 2836f70df15SPoul-Henning Kamp time_freq = time_tolerance; 2846f70df15SPoul-Henning Kamp else if (time_freq < -time_tolerance) 2856f70df15SPoul-Henning Kamp time_freq = -time_tolerance; 2866f70df15SPoul-Henning Kamp } 2876f70df15SPoul-Henning Kamp 2886f70df15SPoul-Henning Kamp void 2896f70df15SPoul-Henning Kamp ntp_update_second(long *newsec) 2906f70df15SPoul-Henning Kamp { 2916f70df15SPoul-Henning Kamp long ltemp; 2926f70df15SPoul-Henning Kamp 2936f70df15SPoul-Henning Kamp time_maxerror += time_tolerance >> SHIFT_USEC; 2946f70df15SPoul-Henning Kamp 2956f70df15SPoul-Henning Kamp /* 2966f70df15SPoul-Henning Kamp * Compute the phase adjustment for the next second. In 2976f70df15SPoul-Henning Kamp * PLL mode, the offset is reduced by a fixed factor 2986f70df15SPoul-Henning Kamp * times the time constant. In FLL mode the offset is 2996f70df15SPoul-Henning Kamp * used directly. In either mode, the maximum phase 3006f70df15SPoul-Henning Kamp * adjustment for each second is clamped so as to spread 3016f70df15SPoul-Henning Kamp * the adjustment over not more than the number of 3026f70df15SPoul-Henning Kamp * seconds between updates. 3036f70df15SPoul-Henning Kamp */ 3046f70df15SPoul-Henning Kamp if (time_offset < 0) { 3056f70df15SPoul-Henning Kamp ltemp = -time_offset; 3066f70df15SPoul-Henning Kamp if (!(time_status & STA_FLL)) 3076f70df15SPoul-Henning Kamp ltemp >>= SHIFT_KG + time_constant; 3086f70df15SPoul-Henning Kamp if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE) 3096f70df15SPoul-Henning Kamp ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE; 3106f70df15SPoul-Henning Kamp time_offset += ltemp; 3116f70df15SPoul-Henning Kamp time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); 3126f70df15SPoul-Henning Kamp } else { 3136f70df15SPoul-Henning Kamp ltemp = time_offset; 3146f70df15SPoul-Henning Kamp if (!(time_status & STA_FLL)) 3156f70df15SPoul-Henning Kamp ltemp >>= SHIFT_KG + time_constant; 3166f70df15SPoul-Henning Kamp if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE) 3176f70df15SPoul-Henning Kamp ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE; 3186f70df15SPoul-Henning Kamp time_offset -= ltemp; 3196f70df15SPoul-Henning Kamp time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); 3206f70df15SPoul-Henning Kamp } 3216f70df15SPoul-Henning Kamp 3226f70df15SPoul-Henning Kamp /* 3236f70df15SPoul-Henning Kamp * Compute the frequency estimate and additional phase 3246f70df15SPoul-Henning Kamp * adjustment due to frequency error for the next 3256f70df15SPoul-Henning Kamp * second. When the PPS signal is engaged, gnaw on the 3266f70df15SPoul-Henning Kamp * watchdog counter and update the frequency computed by 3276f70df15SPoul-Henning Kamp * the pll and the PPS signal. 3286f70df15SPoul-Henning Kamp */ 3296f70df15SPoul-Henning Kamp #ifdef PPS_SYNC 3306f70df15SPoul-Henning Kamp pps_valid++; 3316f70df15SPoul-Henning Kamp if (pps_valid == PPS_VALID) { 3326f70df15SPoul-Henning Kamp pps_jitter = MAXTIME; 3336f70df15SPoul-Henning Kamp pps_stabil = MAXFREQ; 3346f70df15SPoul-Henning Kamp time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | 3356f70df15SPoul-Henning Kamp STA_PPSWANDER | STA_PPSERROR); 3366f70df15SPoul-Henning Kamp } 3376f70df15SPoul-Henning Kamp ltemp = time_freq + pps_freq; 3386f70df15SPoul-Henning Kamp #else 3396f70df15SPoul-Henning Kamp ltemp = time_freq; 3406f70df15SPoul-Henning Kamp #endif /* PPS_SYNC */ 3416f70df15SPoul-Henning Kamp if (ltemp < 0) 3426f70df15SPoul-Henning Kamp time_adj -= -ltemp >> (SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE); 3436f70df15SPoul-Henning Kamp else 3446f70df15SPoul-Henning Kamp time_adj += ltemp >> (SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE); 3456f70df15SPoul-Henning Kamp 3466f70df15SPoul-Henning Kamp #if SHIFT_HZ == 7 3476f70df15SPoul-Henning Kamp /* 3486f70df15SPoul-Henning Kamp * When the CPU clock oscillator frequency is not a 3496f70df15SPoul-Henning Kamp * power of two in Hz, the SHIFT_HZ is only an 3506f70df15SPoul-Henning Kamp * approximate scale factor. In the SunOS kernel, this 3516f70df15SPoul-Henning Kamp * results in a PLL gain factor of 1/1.28 = 0.78 what it 3526f70df15SPoul-Henning Kamp * should be. In the following code the overall gain is 3536f70df15SPoul-Henning Kamp * increased by a factor of 1.25, which results in a 3546f70df15SPoul-Henning Kamp * residual error less than 3 percent. 3556f70df15SPoul-Henning Kamp */ 3566f70df15SPoul-Henning Kamp /* Same thing applies for FreeBSD --GAW */ 3576f70df15SPoul-Henning Kamp if (hz == 100) { 3586f70df15SPoul-Henning Kamp if (time_adj < 0) 3596f70df15SPoul-Henning Kamp time_adj -= -time_adj >> 2; 3606f70df15SPoul-Henning Kamp else 3616f70df15SPoul-Henning Kamp time_adj += time_adj >> 2; 3626f70df15SPoul-Henning Kamp } 3636f70df15SPoul-Henning Kamp #endif /* SHIFT_HZ */ 3646f70df15SPoul-Henning Kamp 3656f70df15SPoul-Henning Kamp /* XXX - this is really bogus, but can't be fixed until 3666f70df15SPoul-Henning Kamp xntpd's idea of the system clock is fixed to know how 3676f70df15SPoul-Henning Kamp the user wants leap seconds handled; in the mean time, 3686f70df15SPoul-Henning Kamp we assume that users of NTP are running without proper 3696f70df15SPoul-Henning Kamp leap second support (this is now the default anyway) */ 3706f70df15SPoul-Henning Kamp /* 3716f70df15SPoul-Henning Kamp * Leap second processing. If in leap-insert state at 3726f70df15SPoul-Henning Kamp * the end of the day, the system clock is set back one 3736f70df15SPoul-Henning Kamp * second; if in leap-delete state, the system clock is 3746f70df15SPoul-Henning Kamp * set ahead one second. The microtime() routine or 3756f70df15SPoul-Henning Kamp * external clock driver will insure that reported time 3766f70df15SPoul-Henning Kamp * is always monotonic. The ugly divides should be 3776f70df15SPoul-Henning Kamp * replaced. 3786f70df15SPoul-Henning Kamp */ 3796f70df15SPoul-Henning Kamp switch (time_state) { 3806f70df15SPoul-Henning Kamp 3816f70df15SPoul-Henning Kamp case TIME_OK: 3826f70df15SPoul-Henning Kamp if (time_status & STA_INS) 3836f70df15SPoul-Henning Kamp time_state = TIME_INS; 3846f70df15SPoul-Henning Kamp else if (time_status & STA_DEL) 3856f70df15SPoul-Henning Kamp time_state = TIME_DEL; 3866f70df15SPoul-Henning Kamp break; 3876f70df15SPoul-Henning Kamp 3886f70df15SPoul-Henning Kamp case TIME_INS: 3896f70df15SPoul-Henning Kamp if ((*newsec) % 86400 == 0) { 3906f70df15SPoul-Henning Kamp (*newsec)--; 3916f70df15SPoul-Henning Kamp time_state = TIME_OOP; 3926f70df15SPoul-Henning Kamp } 3936f70df15SPoul-Henning Kamp break; 3946f70df15SPoul-Henning Kamp 3956f70df15SPoul-Henning Kamp case TIME_DEL: 3966f70df15SPoul-Henning Kamp if (((*newsec) + 1) % 86400 == 0) { 3976f70df15SPoul-Henning Kamp (*newsec)++; 3986f70df15SPoul-Henning Kamp time_state = TIME_WAIT; 3996f70df15SPoul-Henning Kamp } 4006f70df15SPoul-Henning Kamp break; 4016f70df15SPoul-Henning Kamp 4026f70df15SPoul-Henning Kamp case TIME_OOP: 4036f70df15SPoul-Henning Kamp time_state = TIME_WAIT; 4046f70df15SPoul-Henning Kamp break; 4056f70df15SPoul-Henning Kamp 4066f70df15SPoul-Henning Kamp case TIME_WAIT: 4076f70df15SPoul-Henning Kamp if (!(time_status & (STA_INS | STA_DEL))) 4086f70df15SPoul-Henning Kamp time_state = TIME_OK; 4096f70df15SPoul-Henning Kamp break; 4106f70df15SPoul-Henning Kamp } 4116f70df15SPoul-Henning Kamp } 4129ada5a50SPoul-Henning Kamp 413a52752a4SPoul-Henning Kamp static int 414a52752a4SPoul-Henning Kamp ntp_sysctl SYSCTL_HANDLER_ARGS 4153f31c649SGarrett Wollman { 4163f31c649SGarrett Wollman struct timeval atv; 4173f31c649SGarrett Wollman struct ntptimeval ntv; 4183f31c649SGarrett Wollman int s; 4193f31c649SGarrett Wollman 4203f31c649SGarrett Wollman s = splclock(); 4213f31c649SGarrett Wollman microtime(&atv); 4223f31c649SGarrett Wollman ntv.time = atv; 4233f31c649SGarrett Wollman ntv.maxerror = time_maxerror; 4243f31c649SGarrett Wollman ntv.esterror = time_esterror; 4253f31c649SGarrett Wollman splx(s); 4263f31c649SGarrett Wollman 4273f31c649SGarrett Wollman ntv.time_state = time_state; 4283f31c649SGarrett Wollman 4293f31c649SGarrett Wollman /* 4303f31c649SGarrett Wollman * Status word error decode. If any of these conditions 4313f31c649SGarrett Wollman * occur, an error is returned, instead of the status 4323f31c649SGarrett Wollman * word. Most applications will care only about the fact 4333f31c649SGarrett Wollman * the system clock may not be trusted, not about the 4343f31c649SGarrett Wollman * details. 4353f31c649SGarrett Wollman * 4363f31c649SGarrett Wollman * Hardware or software error 4373f31c649SGarrett Wollman */ 4383f31c649SGarrett Wollman if (time_status & (STA_UNSYNC | STA_CLOCKERR)) { 4393f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 4403f31c649SGarrett Wollman } 4413f31c649SGarrett Wollman 4423f31c649SGarrett Wollman /* 4433f31c649SGarrett Wollman * PPS signal lost when either time or frequency 4443f31c649SGarrett Wollman * synchronization requested 4453f31c649SGarrett Wollman */ 4463f31c649SGarrett Wollman if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 4473f31c649SGarrett Wollman !(time_status & STA_PPSSIGNAL)) { 4483f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 4493f31c649SGarrett Wollman } 4503f31c649SGarrett Wollman 4513f31c649SGarrett Wollman /* 4523f31c649SGarrett Wollman * PPS jitter exceeded when time synchronization 4533f31c649SGarrett Wollman * requested 4543f31c649SGarrett Wollman */ 4553f31c649SGarrett Wollman if (time_status & STA_PPSTIME && 4563f31c649SGarrett Wollman time_status & STA_PPSJITTER) { 4573f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 4583f31c649SGarrett Wollman } 4593f31c649SGarrett Wollman 4603f31c649SGarrett Wollman /* 4613f31c649SGarrett Wollman * PPS wander exceeded or calibration error when 4623f31c649SGarrett Wollman * frequency synchronization requested 4633f31c649SGarrett Wollman */ 4643f31c649SGarrett Wollman if (time_status & STA_PPSFREQ && 4653f31c649SGarrett Wollman time_status & (STA_PPSWANDER | STA_PPSERROR)) { 4663f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 4673f31c649SGarrett Wollman } 468a52752a4SPoul-Henning Kamp return (sysctl_handle_opaque(oidp, &ntv, sizeof ntv, req)); 4693f31c649SGarrett Wollman } 4703f31c649SGarrett Wollman 471a52752a4SPoul-Henning Kamp SYSCTL_NODE(_kern, KERN_NTP_PLL, ntp_pll, CTLFLAG_RW, 0, 472a52752a4SPoul-Henning Kamp "NTP kernel PLL related stuff"); 473a52752a4SPoul-Henning Kamp SYSCTL_PROC(_kern_ntp_pll, NTP_PLL_GETTIME, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD, 474946bb7a2SPoul-Henning Kamp 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", ""); 475a52752a4SPoul-Henning Kamp 4763f31c649SGarrett Wollman /* 4773f31c649SGarrett Wollman * ntp_adjtime() - NTP daemon application interface 4783f31c649SGarrett Wollman */ 479d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 4803f31c649SGarrett Wollman struct ntp_adjtime_args { 4813f31c649SGarrett Wollman struct timex *tp; 4823f31c649SGarrett Wollman }; 483d2d3e875SBruce Evans #endif 4843f31c649SGarrett Wollman 4853f31c649SGarrett Wollman int 486cb226aaaSPoul-Henning Kamp ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap) 4873f31c649SGarrett Wollman { 4883f31c649SGarrett Wollman struct timex ntv; 4893f31c649SGarrett Wollman int modes; 4903f31c649SGarrett Wollman int s; 4913f31c649SGarrett Wollman int error; 4923f31c649SGarrett Wollman 4933f31c649SGarrett Wollman error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv)); 4943f31c649SGarrett Wollman if (error) 4953f31c649SGarrett Wollman return error; 4963f31c649SGarrett Wollman 4973f31c649SGarrett Wollman /* 4983f31c649SGarrett Wollman * Update selected clock variables - only the superuser can 4993f31c649SGarrett Wollman * change anything. Note that there is no error checking here on 5003f31c649SGarrett Wollman * the assumption the superuser should know what it is doing. 5013f31c649SGarrett Wollman */ 5023f31c649SGarrett Wollman modes = ntv.modes; 5033f31c649SGarrett Wollman if ((modes != 0) 5043f31c649SGarrett Wollman && (error = suser(p->p_cred->pc_ucred, &p->p_acflag))) 5053f31c649SGarrett Wollman return error; 5063f31c649SGarrett Wollman 5073f31c649SGarrett Wollman s = splclock(); 5083f31c649SGarrett Wollman if (modes & MOD_FREQUENCY) 5093f31c649SGarrett Wollman #ifdef PPS_SYNC 5103f31c649SGarrett Wollman time_freq = ntv.freq - pps_freq; 5113f31c649SGarrett Wollman #else /* PPS_SYNC */ 5123f31c649SGarrett Wollman time_freq = ntv.freq; 5133f31c649SGarrett Wollman #endif /* PPS_SYNC */ 5143f31c649SGarrett Wollman if (modes & MOD_MAXERROR) 5153f31c649SGarrett Wollman time_maxerror = ntv.maxerror; 5163f31c649SGarrett Wollman if (modes & MOD_ESTERROR) 5173f31c649SGarrett Wollman time_esterror = ntv.esterror; 5183f31c649SGarrett Wollman if (modes & MOD_STATUS) { 5193f31c649SGarrett Wollman time_status &= STA_RONLY; 5203f31c649SGarrett Wollman time_status |= ntv.status & ~STA_RONLY; 5213f31c649SGarrett Wollman } 5223f31c649SGarrett Wollman if (modes & MOD_TIMECONST) 5233f31c649SGarrett Wollman time_constant = ntv.constant; 5243f31c649SGarrett Wollman if (modes & MOD_OFFSET) 5253f31c649SGarrett Wollman hardupdate(ntv.offset); 5263f31c649SGarrett Wollman 5273f31c649SGarrett Wollman /* 5283f31c649SGarrett Wollman * Retrieve all clock variables 5293f31c649SGarrett Wollman */ 5303f31c649SGarrett Wollman if (time_offset < 0) 5313f31c649SGarrett Wollman ntv.offset = -(-time_offset >> SHIFT_UPDATE); 5323f31c649SGarrett Wollman else 5333f31c649SGarrett Wollman ntv.offset = time_offset >> SHIFT_UPDATE; 5343f31c649SGarrett Wollman #ifdef PPS_SYNC 5353f31c649SGarrett Wollman ntv.freq = time_freq + pps_freq; 5363f31c649SGarrett Wollman #else /* PPS_SYNC */ 5373f31c649SGarrett Wollman ntv.freq = time_freq; 5383f31c649SGarrett Wollman #endif /* PPS_SYNC */ 5393f31c649SGarrett Wollman ntv.maxerror = time_maxerror; 5403f31c649SGarrett Wollman ntv.esterror = time_esterror; 5413f31c649SGarrett Wollman ntv.status = time_status; 5423f31c649SGarrett Wollman ntv.constant = time_constant; 5433f31c649SGarrett Wollman ntv.precision = time_precision; 5443f31c649SGarrett Wollman ntv.tolerance = time_tolerance; 5453f31c649SGarrett Wollman #ifdef PPS_SYNC 5463f31c649SGarrett Wollman ntv.shift = pps_shift; 5473f31c649SGarrett Wollman ntv.ppsfreq = pps_freq; 5483f31c649SGarrett Wollman ntv.jitter = pps_jitter >> PPS_AVG; 5493f31c649SGarrett Wollman ntv.stabil = pps_stabil; 5503f31c649SGarrett Wollman ntv.calcnt = pps_calcnt; 5513f31c649SGarrett Wollman ntv.errcnt = pps_errcnt; 5523f31c649SGarrett Wollman ntv.jitcnt = pps_jitcnt; 5533f31c649SGarrett Wollman ntv.stbcnt = pps_stbcnt; 5543f31c649SGarrett Wollman #endif /* PPS_SYNC */ 5553f31c649SGarrett Wollman (void)splx(s); 5563f31c649SGarrett Wollman 5573f31c649SGarrett Wollman error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv)); 5583f31c649SGarrett Wollman if (!error) { 5593f31c649SGarrett Wollman /* 5603f31c649SGarrett Wollman * Status word error decode. See comments in 5613f31c649SGarrett Wollman * ntp_gettime() routine. 5623f31c649SGarrett Wollman */ 563cb226aaaSPoul-Henning Kamp p->p_retval[0] = time_state; 5643f31c649SGarrett Wollman if (time_status & (STA_UNSYNC | STA_CLOCKERR)) 565cb226aaaSPoul-Henning Kamp p->p_retval[0] = TIME_ERROR; 5663f31c649SGarrett Wollman if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 5673f31c649SGarrett Wollman !(time_status & STA_PPSSIGNAL)) 568cb226aaaSPoul-Henning Kamp p->p_retval[0] = TIME_ERROR; 5693f31c649SGarrett Wollman if (time_status & STA_PPSTIME && 5703f31c649SGarrett Wollman time_status & STA_PPSJITTER) 571cb226aaaSPoul-Henning Kamp p->p_retval[0] = TIME_ERROR; 5723f31c649SGarrett Wollman if (time_status & STA_PPSFREQ && 5733f31c649SGarrett Wollman time_status & (STA_PPSWANDER | STA_PPSERROR)) 574cb226aaaSPoul-Henning Kamp p->p_retval[0] = TIME_ERROR; 5753f31c649SGarrett Wollman } 5763f31c649SGarrett Wollman return error; 5773f31c649SGarrett Wollman } 5783f31c649SGarrett Wollman 5796f70df15SPoul-Henning Kamp #ifdef PPS_SYNC 5803f31c649SGarrett Wollman 5819ada5a50SPoul-Henning Kamp /* We need this ugly monster twice, so let's macroize it. */ 5826f70df15SPoul-Henning Kamp 5836f70df15SPoul-Henning Kamp #define MEDIAN3X(a, m, s, i1, i2, i3) \ 5846f70df15SPoul-Henning Kamp do { \ 5856f70df15SPoul-Henning Kamp m = a[i2]; \ 5866f70df15SPoul-Henning Kamp s = a[i1] - a[i3]; \ 5876f70df15SPoul-Henning Kamp } while (0) 5886f70df15SPoul-Henning Kamp 5896f70df15SPoul-Henning Kamp #define MEDIAN3(a, m, s) \ 5906f70df15SPoul-Henning Kamp do { \ 5916f70df15SPoul-Henning Kamp if (a[0] > a[1]) { \ 5926f70df15SPoul-Henning Kamp if (a[1] > a[2]) \ 5936f70df15SPoul-Henning Kamp MEDIAN3X(a, m, s, 0, 1, 2); \ 5946f70df15SPoul-Henning Kamp else if (a[2] > a[0]) \ 5956f70df15SPoul-Henning Kamp MEDIAN3X(a, m, s, 2, 0, 1); \ 5966f70df15SPoul-Henning Kamp else \ 5976f70df15SPoul-Henning Kamp MEDIAN3X(a, m, s, 0, 2, 1); \ 5986f70df15SPoul-Henning Kamp } else { \ 5996f70df15SPoul-Henning Kamp if (a[2] > a[1]) \ 6006f70df15SPoul-Henning Kamp MEDIAN3X(a, m, s, 2, 1, 0); \ 6016f70df15SPoul-Henning Kamp else if (a[0] > a[2]) \ 6026f70df15SPoul-Henning Kamp MEDIAN3X(a, m, s, 1, 0, 2); \ 6036f70df15SPoul-Henning Kamp else \ 6046f70df15SPoul-Henning Kamp MEDIAN3X(a, m, s, 1, 2, 0); \ 6056f70df15SPoul-Henning Kamp } \ 6066f70df15SPoul-Henning Kamp } while (0) 6076f70df15SPoul-Henning Kamp 6086f70df15SPoul-Henning Kamp /* 6096f70df15SPoul-Henning Kamp * hardpps() - discipline CPU clock oscillator to external PPS signal 6106f70df15SPoul-Henning Kamp * 6116f70df15SPoul-Henning Kamp * This routine is called at each PPS interrupt in order to discipline 6126f70df15SPoul-Henning Kamp * the CPU clock oscillator to the PPS signal. It measures the PPS phase 6136f70df15SPoul-Henning Kamp * and leaves it in a handy spot for the hardclock() routine. It 6146f70df15SPoul-Henning Kamp * integrates successive PPS phase differences and calculates the 6156f70df15SPoul-Henning Kamp * frequency offset. This is used in hardclock() to discipline the CPU 6166f70df15SPoul-Henning Kamp * clock oscillator so that intrinsic frequency error is cancelled out. 6176f70df15SPoul-Henning Kamp * The code requires the caller to capture the time and hardware counter 6186f70df15SPoul-Henning Kamp * value at the on-time PPS signal transition. 6196f70df15SPoul-Henning Kamp * 6206f70df15SPoul-Henning Kamp * Note that, on some Unix systems, this routine runs at an interrupt 6216f70df15SPoul-Henning Kamp * priority level higher than the timer interrupt routine hardclock(). 6226f70df15SPoul-Henning Kamp * Therefore, the variables used are distinct from the hardclock() 6236f70df15SPoul-Henning Kamp * variables, except for certain exceptions: The PPS frequency pps_freq 6246f70df15SPoul-Henning Kamp * and phase pps_offset variables are determined by this routine and 6256f70df15SPoul-Henning Kamp * updated atomically. The time_tolerance variable can be considered a 6266f70df15SPoul-Henning Kamp * constant, since it is infrequently changed, and then only when the 6276f70df15SPoul-Henning Kamp * PPS signal is disabled. The watchdog counter pps_valid is updated 6286f70df15SPoul-Henning Kamp * once per second by hardclock() and is atomically cleared in this 6296f70df15SPoul-Henning Kamp * routine. 6306f70df15SPoul-Henning Kamp */ 6316f70df15SPoul-Henning Kamp void 6326f70df15SPoul-Henning Kamp hardpps(tvp, p_usec) 6336f70df15SPoul-Henning Kamp struct timeval *tvp; /* time at PPS */ 6346f70df15SPoul-Henning Kamp long p_usec; /* hardware counter at PPS */ 6356f70df15SPoul-Henning Kamp { 6366f70df15SPoul-Henning Kamp long u_usec, v_usec, bigtick; 6376f70df15SPoul-Henning Kamp long cal_sec, cal_usec; 6386f70df15SPoul-Henning Kamp 6396f70df15SPoul-Henning Kamp /* 6406f70df15SPoul-Henning Kamp * An occasional glitch can be produced when the PPS interrupt 6416f70df15SPoul-Henning Kamp * occurs in the hardclock() routine before the time variable is 6426f70df15SPoul-Henning Kamp * updated. Here the offset is discarded when the difference 6436f70df15SPoul-Henning Kamp * between it and the last one is greater than tick/2, but not 6446f70df15SPoul-Henning Kamp * if the interval since the first discard exceeds 30 s. 6456f70df15SPoul-Henning Kamp */ 6466f70df15SPoul-Henning Kamp time_status |= STA_PPSSIGNAL; 6476f70df15SPoul-Henning Kamp time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); 6486f70df15SPoul-Henning Kamp pps_valid = 0; 6496f70df15SPoul-Henning Kamp u_usec = -tvp->tv_usec; 6506f70df15SPoul-Henning Kamp if (u_usec < -500000) 6516f70df15SPoul-Henning Kamp u_usec += 1000000; 6526f70df15SPoul-Henning Kamp v_usec = pps_offset - u_usec; 6536f70df15SPoul-Henning Kamp if (v_usec < 0) 6546f70df15SPoul-Henning Kamp v_usec = -v_usec; 6556f70df15SPoul-Henning Kamp if (v_usec > (tick >> 1)) { 6566f70df15SPoul-Henning Kamp if (pps_glitch > MAXGLITCH) { 6576f70df15SPoul-Henning Kamp pps_glitch = 0; 6586f70df15SPoul-Henning Kamp pps_tf[2] = u_usec; 6596f70df15SPoul-Henning Kamp pps_tf[1] = u_usec; 6606f70df15SPoul-Henning Kamp } else { 6616f70df15SPoul-Henning Kamp pps_glitch++; 6626f70df15SPoul-Henning Kamp u_usec = pps_offset; 6636f70df15SPoul-Henning Kamp } 6646f70df15SPoul-Henning Kamp } else 6656f70df15SPoul-Henning Kamp pps_glitch = 0; 6666f70df15SPoul-Henning Kamp 6676f70df15SPoul-Henning Kamp /* 6686f70df15SPoul-Henning Kamp * A three-stage median filter is used to help deglitch the pps 6696f70df15SPoul-Henning Kamp * time. The median sample becomes the time offset estimate; the 6706f70df15SPoul-Henning Kamp * difference between the other two samples becomes the time 6716f70df15SPoul-Henning Kamp * dispersion (jitter) estimate. 6726f70df15SPoul-Henning Kamp */ 6736f70df15SPoul-Henning Kamp pps_tf[2] = pps_tf[1]; 6746f70df15SPoul-Henning Kamp pps_tf[1] = pps_tf[0]; 6756f70df15SPoul-Henning Kamp pps_tf[0] = u_usec; 6766f70df15SPoul-Henning Kamp MEDIAN3(pps_tf, pps_offset, v_usec); 6776f70df15SPoul-Henning Kamp if (v_usec > MAXTIME) 6786f70df15SPoul-Henning Kamp pps_jitcnt++; 6796f70df15SPoul-Henning Kamp v_usec = (v_usec << PPS_AVG) - pps_jitter; 6806f70df15SPoul-Henning Kamp if (v_usec < 0) 6816f70df15SPoul-Henning Kamp pps_jitter -= -v_usec >> PPS_AVG; 6826f70df15SPoul-Henning Kamp else 6836f70df15SPoul-Henning Kamp pps_jitter += v_usec >> PPS_AVG; 6846f70df15SPoul-Henning Kamp if (pps_jitter > (MAXTIME >> 1)) 6856f70df15SPoul-Henning Kamp time_status |= STA_PPSJITTER; 6866f70df15SPoul-Henning Kamp 6876f70df15SPoul-Henning Kamp /* 6886f70df15SPoul-Henning Kamp * During the calibration interval adjust the starting time when 6896f70df15SPoul-Henning Kamp * the tick overflows. At the end of the interval compute the 6906f70df15SPoul-Henning Kamp * duration of the interval and the difference of the hardware 6916f70df15SPoul-Henning Kamp * counters at the beginning and end of the interval. This code 6926f70df15SPoul-Henning Kamp * is deliciously complicated by the fact valid differences may 6936f70df15SPoul-Henning Kamp * exceed the value of tick when using long calibration 6946f70df15SPoul-Henning Kamp * intervals and small ticks. Note that the counter can be 6956f70df15SPoul-Henning Kamp * greater than tick if caught at just the wrong instant, but 6966f70df15SPoul-Henning Kamp * the values returned and used here are correct. 6976f70df15SPoul-Henning Kamp */ 6986f70df15SPoul-Henning Kamp bigtick = (long)tick << SHIFT_USEC; 6996f70df15SPoul-Henning Kamp pps_usec -= pps_freq; 7006f70df15SPoul-Henning Kamp if (pps_usec >= bigtick) 7016f70df15SPoul-Henning Kamp pps_usec -= bigtick; 7026f70df15SPoul-Henning Kamp if (pps_usec < 0) 7036f70df15SPoul-Henning Kamp pps_usec += bigtick; 7046f70df15SPoul-Henning Kamp pps_time.tv_sec++; 7056f70df15SPoul-Henning Kamp pps_count++; 7066f70df15SPoul-Henning Kamp if (pps_count < (1 << pps_shift)) 7076f70df15SPoul-Henning Kamp return; 7086f70df15SPoul-Henning Kamp pps_count = 0; 7096f70df15SPoul-Henning Kamp pps_calcnt++; 7106f70df15SPoul-Henning Kamp u_usec = p_usec << SHIFT_USEC; 7116f70df15SPoul-Henning Kamp v_usec = pps_usec - u_usec; 7126f70df15SPoul-Henning Kamp if (v_usec >= bigtick >> 1) 7136f70df15SPoul-Henning Kamp v_usec -= bigtick; 7146f70df15SPoul-Henning Kamp if (v_usec < -(bigtick >> 1)) 7156f70df15SPoul-Henning Kamp v_usec += bigtick; 7166f70df15SPoul-Henning Kamp if (v_usec < 0) 7176f70df15SPoul-Henning Kamp v_usec = -(-v_usec >> pps_shift); 7186f70df15SPoul-Henning Kamp else 7196f70df15SPoul-Henning Kamp v_usec = v_usec >> pps_shift; 7206f70df15SPoul-Henning Kamp pps_usec = u_usec; 7216f70df15SPoul-Henning Kamp cal_sec = tvp->tv_sec; 7226f70df15SPoul-Henning Kamp cal_usec = tvp->tv_usec; 7236f70df15SPoul-Henning Kamp cal_sec -= pps_time.tv_sec; 7246f70df15SPoul-Henning Kamp cal_usec -= pps_time.tv_usec; 7256f70df15SPoul-Henning Kamp if (cal_usec < 0) { 7266f70df15SPoul-Henning Kamp cal_usec += 1000000; 7276f70df15SPoul-Henning Kamp cal_sec--; 7286f70df15SPoul-Henning Kamp } 7296f70df15SPoul-Henning Kamp pps_time = *tvp; 7306f70df15SPoul-Henning Kamp 7316f70df15SPoul-Henning Kamp /* 7326f70df15SPoul-Henning Kamp * Check for lost interrupts, noise, excessive jitter and 7336f70df15SPoul-Henning Kamp * excessive frequency error. The number of timer ticks during 7346f70df15SPoul-Henning Kamp * the interval may vary +-1 tick. Add to this a margin of one 7356f70df15SPoul-Henning Kamp * tick for the PPS signal jitter and maximum frequency 7366f70df15SPoul-Henning Kamp * deviation. If the limits are exceeded, the calibration 7376f70df15SPoul-Henning Kamp * interval is reset to the minimum and we start over. 7386f70df15SPoul-Henning Kamp */ 7396f70df15SPoul-Henning Kamp u_usec = (long)tick << 1; 7406f70df15SPoul-Henning Kamp if (!((cal_sec == -1 && cal_usec > (1000000 - u_usec)) 7416f70df15SPoul-Henning Kamp || (cal_sec == 0 && cal_usec < u_usec)) 7426f70df15SPoul-Henning Kamp || v_usec > time_tolerance || v_usec < -time_tolerance) { 7436f70df15SPoul-Henning Kamp pps_errcnt++; 7446f70df15SPoul-Henning Kamp pps_shift = PPS_SHIFT; 7456f70df15SPoul-Henning Kamp pps_intcnt = 0; 7466f70df15SPoul-Henning Kamp time_status |= STA_PPSERROR; 7476f70df15SPoul-Henning Kamp return; 7486f70df15SPoul-Henning Kamp } 7496f70df15SPoul-Henning Kamp 7506f70df15SPoul-Henning Kamp /* 7516f70df15SPoul-Henning Kamp * A three-stage median filter is used to help deglitch the pps 7526f70df15SPoul-Henning Kamp * frequency. The median sample becomes the frequency offset 7536f70df15SPoul-Henning Kamp * estimate; the difference between the other two samples 7546f70df15SPoul-Henning Kamp * becomes the frequency dispersion (stability) estimate. 7556f70df15SPoul-Henning Kamp */ 7566f70df15SPoul-Henning Kamp pps_ff[2] = pps_ff[1]; 7576f70df15SPoul-Henning Kamp pps_ff[1] = pps_ff[0]; 7586f70df15SPoul-Henning Kamp pps_ff[0] = v_usec; 7596f70df15SPoul-Henning Kamp MEDIAN3(pps_ff, u_usec, v_usec); 7606f70df15SPoul-Henning Kamp 7616f70df15SPoul-Henning Kamp /* 7626f70df15SPoul-Henning Kamp * Here the frequency dispersion (stability) is updated. If it 7636f70df15SPoul-Henning Kamp * is less than one-fourth the maximum (MAXFREQ), the frequency 7646f70df15SPoul-Henning Kamp * offset is updated as well, but clamped to the tolerance. It 7656f70df15SPoul-Henning Kamp * will be processed later by the hardclock() routine. 7666f70df15SPoul-Henning Kamp */ 7676f70df15SPoul-Henning Kamp v_usec = (v_usec >> 1) - pps_stabil; 7686f70df15SPoul-Henning Kamp if (v_usec < 0) 7696f70df15SPoul-Henning Kamp pps_stabil -= -v_usec >> PPS_AVG; 7706f70df15SPoul-Henning Kamp else 7716f70df15SPoul-Henning Kamp pps_stabil += v_usec >> PPS_AVG; 7726f70df15SPoul-Henning Kamp if (pps_stabil > MAXFREQ >> 2) { 7736f70df15SPoul-Henning Kamp pps_stbcnt++; 7746f70df15SPoul-Henning Kamp time_status |= STA_PPSWANDER; 7756f70df15SPoul-Henning Kamp return; 7766f70df15SPoul-Henning Kamp } 7776f70df15SPoul-Henning Kamp if (time_status & STA_PPSFREQ) { 7786f70df15SPoul-Henning Kamp if (u_usec < 0) { 7796f70df15SPoul-Henning Kamp pps_freq -= -u_usec >> PPS_AVG; 7806f70df15SPoul-Henning Kamp if (pps_freq < -time_tolerance) 7816f70df15SPoul-Henning Kamp pps_freq = -time_tolerance; 7826f70df15SPoul-Henning Kamp u_usec = -u_usec; 7836f70df15SPoul-Henning Kamp } else { 7846f70df15SPoul-Henning Kamp pps_freq += u_usec >> PPS_AVG; 7856f70df15SPoul-Henning Kamp if (pps_freq > time_tolerance) 7866f70df15SPoul-Henning Kamp pps_freq = time_tolerance; 7876f70df15SPoul-Henning Kamp } 7886f70df15SPoul-Henning Kamp } 7896f70df15SPoul-Henning Kamp 7906f70df15SPoul-Henning Kamp /* 7916f70df15SPoul-Henning Kamp * Here the calibration interval is adjusted. If the maximum 7926f70df15SPoul-Henning Kamp * time difference is greater than tick / 4, reduce the interval 7936f70df15SPoul-Henning Kamp * by half. If this is not the case for four consecutive 7946f70df15SPoul-Henning Kamp * intervals, double the interval. 7956f70df15SPoul-Henning Kamp */ 7966f70df15SPoul-Henning Kamp if (u_usec << pps_shift > bigtick >> 2) { 7976f70df15SPoul-Henning Kamp pps_intcnt = 0; 7986f70df15SPoul-Henning Kamp if (pps_shift > PPS_SHIFT) 7996f70df15SPoul-Henning Kamp pps_shift--; 8006f70df15SPoul-Henning Kamp } else if (pps_intcnt >= 4) { 8016f70df15SPoul-Henning Kamp pps_intcnt = 0; 8026f70df15SPoul-Henning Kamp if (pps_shift < PPS_SHIFTMAX) 8036f70df15SPoul-Henning Kamp pps_shift++; 8046f70df15SPoul-Henning Kamp } else 8056f70df15SPoul-Henning Kamp pps_intcnt++; 8066f70df15SPoul-Henning Kamp } 8079ada5a50SPoul-Henning Kamp 8086f70df15SPoul-Henning Kamp #endif /* PPS_SYNC */ 809