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