162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NTP state machine interfaces and logic. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This code was mainly moved from kernel/timer.c and kernel/time.c 662306a36Sopenharmony_ci * Please see those files for relevant copyright info and historical 762306a36Sopenharmony_ci * changelogs. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/capability.h> 1062306a36Sopenharmony_ci#include <linux/clocksource.h> 1162306a36Sopenharmony_ci#include <linux/workqueue.h> 1262306a36Sopenharmony_ci#include <linux/hrtimer.h> 1362306a36Sopenharmony_ci#include <linux/jiffies.h> 1462306a36Sopenharmony_ci#include <linux/math64.h> 1562306a36Sopenharmony_ci#include <linux/timex.h> 1662306a36Sopenharmony_ci#include <linux/time.h> 1762306a36Sopenharmony_ci#include <linux/mm.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/rtc.h> 2062306a36Sopenharmony_ci#include <linux/audit.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "ntp_internal.h" 2362306a36Sopenharmony_ci#include "timekeeping_internal.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * NTP timekeeping variables: 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * Note: All of the NTP state is protected by the timekeeping locks. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* USER_HZ period (usecs): */ 3462306a36Sopenharmony_ciunsigned long tick_usec = USER_TICK_USEC; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* SHIFTED_HZ period (nsecs): */ 3762306a36Sopenharmony_ciunsigned long tick_nsec; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic u64 tick_length; 4062306a36Sopenharmony_cistatic u64 tick_length_base; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define SECS_PER_DAY 86400 4362306a36Sopenharmony_ci#define MAX_TICKADJ 500LL /* usecs */ 4462306a36Sopenharmony_ci#define MAX_TICKADJ_SCALED \ 4562306a36Sopenharmony_ci (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) 4662306a36Sopenharmony_ci#define MAX_TAI_OFFSET 100000 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * phase-lock loop variables 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * clock synchronization status 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * (TIME_ERROR prevents overwriting the CMOS clock) 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_cistatic int time_state = TIME_OK; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* clock status bits: */ 6062306a36Sopenharmony_cistatic int time_status = STA_UNSYNC; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* time adjustment (nsecs): */ 6362306a36Sopenharmony_cistatic s64 time_offset; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* pll time constant: */ 6662306a36Sopenharmony_cistatic long time_constant = 2; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* maximum error (usecs): */ 6962306a36Sopenharmony_cistatic long time_maxerror = NTP_PHASE_LIMIT; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* estimated error (usecs): */ 7262306a36Sopenharmony_cistatic long time_esterror = NTP_PHASE_LIMIT; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* frequency offset (scaled nsecs/secs): */ 7562306a36Sopenharmony_cistatic s64 time_freq; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* time at last adjustment (secs): */ 7862306a36Sopenharmony_cistatic time64_t time_reftime; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic long time_adjust; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* constant (boot-param configurable) NTP tick adjustment (upscaled) */ 8362306a36Sopenharmony_cistatic s64 ntp_tick_adj; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* second value of the next pending leapsecond, or TIME64_MAX if no leap */ 8662306a36Sopenharmony_cistatic time64_t ntp_next_leap_sec = TIME64_MAX; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#ifdef CONFIG_NTP_PPS 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * The following variables are used when a pulse-per-second (PPS) signal 9262306a36Sopenharmony_ci * is available. They establish the engineering parameters of the clock 9362306a36Sopenharmony_ci * discipline loop when controlled by the PPS signal. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci#define PPS_VALID 10 /* PPS signal watchdog max (s) */ 9662306a36Sopenharmony_ci#define PPS_POPCORN 4 /* popcorn spike threshold (shift) */ 9762306a36Sopenharmony_ci#define PPS_INTMIN 2 /* min freq interval (s) (shift) */ 9862306a36Sopenharmony_ci#define PPS_INTMAX 8 /* max freq interval (s) (shift) */ 9962306a36Sopenharmony_ci#define PPS_INTCOUNT 4 /* number of consecutive good intervals to 10062306a36Sopenharmony_ci increase pps_shift or consecutive bad 10162306a36Sopenharmony_ci intervals to decrease it */ 10262306a36Sopenharmony_ci#define PPS_MAXWANDER 100000 /* max PPS freq wander (ns/s) */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int pps_valid; /* signal watchdog counter */ 10562306a36Sopenharmony_cistatic long pps_tf[3]; /* phase median filter */ 10662306a36Sopenharmony_cistatic long pps_jitter; /* current jitter (ns) */ 10762306a36Sopenharmony_cistatic struct timespec64 pps_fbase; /* beginning of the last freq interval */ 10862306a36Sopenharmony_cistatic int pps_shift; /* current interval duration (s) (shift) */ 10962306a36Sopenharmony_cistatic int pps_intcnt; /* interval counter */ 11062306a36Sopenharmony_cistatic s64 pps_freq; /* frequency offset (scaled ns/s) */ 11162306a36Sopenharmony_cistatic long pps_stabil; /* current stability (scaled ns/s) */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * PPS signal quality monitors 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic long pps_calcnt; /* calibration intervals */ 11762306a36Sopenharmony_cistatic long pps_jitcnt; /* jitter limit exceeded */ 11862306a36Sopenharmony_cistatic long pps_stbcnt; /* stability limit exceeded */ 11962306a36Sopenharmony_cistatic long pps_errcnt; /* calibration errors */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* PPS kernel consumer compensates the whole phase error immediately. 12362306a36Sopenharmony_ci * Otherwise, reduce the offset by a fixed factor times the time constant. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic inline s64 ntp_offset_chunk(s64 offset) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL) 12862306a36Sopenharmony_ci return offset; 12962306a36Sopenharmony_ci else 13062306a36Sopenharmony_ci return shift_right(offset, SHIFT_PLL + time_constant); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic inline void pps_reset_freq_interval(void) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci /* the PPS calibration interval may end 13662306a36Sopenharmony_ci surprisingly early */ 13762306a36Sopenharmony_ci pps_shift = PPS_INTMIN; 13862306a36Sopenharmony_ci pps_intcnt = 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/** 14262306a36Sopenharmony_ci * pps_clear - Clears the PPS state variables 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_cistatic inline void pps_clear(void) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci pps_reset_freq_interval(); 14762306a36Sopenharmony_ci pps_tf[0] = 0; 14862306a36Sopenharmony_ci pps_tf[1] = 0; 14962306a36Sopenharmony_ci pps_tf[2] = 0; 15062306a36Sopenharmony_ci pps_fbase.tv_sec = pps_fbase.tv_nsec = 0; 15162306a36Sopenharmony_ci pps_freq = 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* Decrease pps_valid to indicate that another second has passed since 15562306a36Sopenharmony_ci * the last PPS signal. When it reaches 0, indicate that PPS signal is 15662306a36Sopenharmony_ci * missing. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_cistatic inline void pps_dec_valid(void) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci if (pps_valid > 0) 16162306a36Sopenharmony_ci pps_valid--; 16262306a36Sopenharmony_ci else { 16362306a36Sopenharmony_ci time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | 16462306a36Sopenharmony_ci STA_PPSWANDER | STA_PPSERROR); 16562306a36Sopenharmony_ci pps_clear(); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic inline void pps_set_freq(s64 freq) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci pps_freq = freq; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic inline int is_error_status(int status) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci return (status & (STA_UNSYNC|STA_CLOCKERR)) 17762306a36Sopenharmony_ci /* PPS signal lost when either PPS time or 17862306a36Sopenharmony_ci * PPS frequency synchronization requested 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_ci || ((status & (STA_PPSFREQ|STA_PPSTIME)) 18162306a36Sopenharmony_ci && !(status & STA_PPSSIGNAL)) 18262306a36Sopenharmony_ci /* PPS jitter exceeded when 18362306a36Sopenharmony_ci * PPS time synchronization requested */ 18462306a36Sopenharmony_ci || ((status & (STA_PPSTIME|STA_PPSJITTER)) 18562306a36Sopenharmony_ci == (STA_PPSTIME|STA_PPSJITTER)) 18662306a36Sopenharmony_ci /* PPS wander exceeded or calibration error when 18762306a36Sopenharmony_ci * PPS frequency synchronization requested 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci || ((status & STA_PPSFREQ) 19062306a36Sopenharmony_ci && (status & (STA_PPSWANDER|STA_PPSERROR))); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic inline void pps_fill_timex(struct __kernel_timex *txc) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci txc->ppsfreq = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) * 19662306a36Sopenharmony_ci PPM_SCALE_INV, NTP_SCALE_SHIFT); 19762306a36Sopenharmony_ci txc->jitter = pps_jitter; 19862306a36Sopenharmony_ci if (!(time_status & STA_NANO)) 19962306a36Sopenharmony_ci txc->jitter = pps_jitter / NSEC_PER_USEC; 20062306a36Sopenharmony_ci txc->shift = pps_shift; 20162306a36Sopenharmony_ci txc->stabil = pps_stabil; 20262306a36Sopenharmony_ci txc->jitcnt = pps_jitcnt; 20362306a36Sopenharmony_ci txc->calcnt = pps_calcnt; 20462306a36Sopenharmony_ci txc->errcnt = pps_errcnt; 20562306a36Sopenharmony_ci txc->stbcnt = pps_stbcnt; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#else /* !CONFIG_NTP_PPS */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic inline s64 ntp_offset_chunk(s64 offset) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci return shift_right(offset, SHIFT_PLL + time_constant); 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic inline void pps_reset_freq_interval(void) {} 21662306a36Sopenharmony_cistatic inline void pps_clear(void) {} 21762306a36Sopenharmony_cistatic inline void pps_dec_valid(void) {} 21862306a36Sopenharmony_cistatic inline void pps_set_freq(s64 freq) {} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic inline int is_error_status(int status) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci return status & (STA_UNSYNC|STA_CLOCKERR); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic inline void pps_fill_timex(struct __kernel_timex *txc) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci /* PPS is not implemented, so these are zero */ 22862306a36Sopenharmony_ci txc->ppsfreq = 0; 22962306a36Sopenharmony_ci txc->jitter = 0; 23062306a36Sopenharmony_ci txc->shift = 0; 23162306a36Sopenharmony_ci txc->stabil = 0; 23262306a36Sopenharmony_ci txc->jitcnt = 0; 23362306a36Sopenharmony_ci txc->calcnt = 0; 23462306a36Sopenharmony_ci txc->errcnt = 0; 23562306a36Sopenharmony_ci txc->stbcnt = 0; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci#endif /* CONFIG_NTP_PPS */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * ntp_synced - Returns 1 if the NTP status is not UNSYNC 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_cistatic inline int ntp_synced(void) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci return !(time_status & STA_UNSYNC); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* 25262306a36Sopenharmony_ci * NTP methods: 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * Update (tick_length, tick_length_base, tick_nsec), based 25762306a36Sopenharmony_ci * on (tick_usec, ntp_tick_adj, time_freq): 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_cistatic void ntp_update_frequency(void) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci u64 second_length; 26262306a36Sopenharmony_ci u64 new_base; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) 26562306a36Sopenharmony_ci << NTP_SCALE_SHIFT; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci second_length += ntp_tick_adj; 26862306a36Sopenharmony_ci second_length += time_freq; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT; 27162306a36Sopenharmony_ci new_base = div_u64(second_length, NTP_INTERVAL_FREQ); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* 27462306a36Sopenharmony_ci * Don't wait for the next second_overflow, apply 27562306a36Sopenharmony_ci * the change to the tick length immediately: 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci tick_length += new_base - tick_length_base; 27862306a36Sopenharmony_ci tick_length_base = new_base; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic inline s64 ntp_update_offset_fll(s64 offset64, long secs) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci time_status &= ~STA_MODE; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (secs < MINSEC) 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (!(time_status & STA_FLL) && (secs <= MAXSEC)) 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci time_status |= STA_MODE; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void ntp_update_offset(long offset) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci s64 freq_adj; 29962306a36Sopenharmony_ci s64 offset64; 30062306a36Sopenharmony_ci long secs; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (!(time_status & STA_PLL)) 30362306a36Sopenharmony_ci return; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!(time_status & STA_NANO)) { 30662306a36Sopenharmony_ci /* Make sure the multiplication below won't overflow */ 30762306a36Sopenharmony_ci offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC); 30862306a36Sopenharmony_ci offset *= NSEC_PER_USEC; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* 31262306a36Sopenharmony_ci * Scale the phase adjustment and 31362306a36Sopenharmony_ci * clamp to the operating range. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci offset = clamp(offset, -MAXPHASE, MAXPHASE); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* 31862306a36Sopenharmony_ci * Select how the frequency is to be controlled 31962306a36Sopenharmony_ci * and in which mode (PLL or FLL). 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_ci secs = (long)(__ktime_get_real_seconds() - time_reftime); 32262306a36Sopenharmony_ci if (unlikely(time_status & STA_FREQHOLD)) 32362306a36Sopenharmony_ci secs = 0; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci time_reftime = __ktime_get_real_seconds(); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci offset64 = offset; 32862306a36Sopenharmony_ci freq_adj = ntp_update_offset_fll(offset64, secs); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* 33162306a36Sopenharmony_ci * Clamp update interval to reduce PLL gain with low 33262306a36Sopenharmony_ci * sampling rate (e.g. intermittent network connection) 33362306a36Sopenharmony_ci * to avoid instability. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci if (unlikely(secs > 1 << (SHIFT_PLL + 1 + time_constant))) 33662306a36Sopenharmony_ci secs = 1 << (SHIFT_PLL + 1 + time_constant); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci freq_adj += (offset64 * secs) << 33962306a36Sopenharmony_ci (NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant)); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci freq_adj = min(freq_adj + time_freq, MAXFREQ_SCALED); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci time_freq = max(freq_adj, -MAXFREQ_SCALED); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/** 34962306a36Sopenharmony_ci * ntp_clear - Clears the NTP state variables 35062306a36Sopenharmony_ci */ 35162306a36Sopenharmony_civoid ntp_clear(void) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci time_adjust = 0; /* stop active adjtime() */ 35462306a36Sopenharmony_ci time_status |= STA_UNSYNC; 35562306a36Sopenharmony_ci time_maxerror = NTP_PHASE_LIMIT; 35662306a36Sopenharmony_ci time_esterror = NTP_PHASE_LIMIT; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ntp_update_frequency(); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci tick_length = tick_length_base; 36162306a36Sopenharmony_ci time_offset = 0; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci ntp_next_leap_sec = TIME64_MAX; 36462306a36Sopenharmony_ci /* Clear PPS state variables */ 36562306a36Sopenharmony_ci pps_clear(); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ciu64 ntp_tick_length(void) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci return tick_length; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci/** 37562306a36Sopenharmony_ci * ntp_get_next_leap - Returns the next leapsecond in CLOCK_REALTIME ktime_t 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * Provides the time of the next leapsecond against CLOCK_REALTIME in 37862306a36Sopenharmony_ci * a ktime_t format. Returns KTIME_MAX if no leapsecond is pending. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ciktime_t ntp_get_next_leap(void) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci ktime_t ret; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if ((time_state == TIME_INS) && (time_status & STA_INS)) 38562306a36Sopenharmony_ci return ktime_set(ntp_next_leap_sec, 0); 38662306a36Sopenharmony_ci ret = KTIME_MAX; 38762306a36Sopenharmony_ci return ret; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci/* 39162306a36Sopenharmony_ci * this routine handles the overflow of the microsecond field 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * The tricky bits of code to handle the accurate clock support 39462306a36Sopenharmony_ci * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. 39562306a36Sopenharmony_ci * They were originally developed for SUN and DEC kernels. 39662306a36Sopenharmony_ci * All the kudos should go to Dave for this stuff. 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * Also handles leap second processing, and returns leap offset 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ciint second_overflow(time64_t secs) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci s64 delta; 40362306a36Sopenharmony_ci int leap = 0; 40462306a36Sopenharmony_ci s32 rem; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* 40762306a36Sopenharmony_ci * Leap second processing. If in leap-insert state at the end of the 40862306a36Sopenharmony_ci * day, the system clock is set back one second; if in leap-delete 40962306a36Sopenharmony_ci * state, the system clock is set ahead one second. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci switch (time_state) { 41262306a36Sopenharmony_ci case TIME_OK: 41362306a36Sopenharmony_ci if (time_status & STA_INS) { 41462306a36Sopenharmony_ci time_state = TIME_INS; 41562306a36Sopenharmony_ci div_s64_rem(secs, SECS_PER_DAY, &rem); 41662306a36Sopenharmony_ci ntp_next_leap_sec = secs + SECS_PER_DAY - rem; 41762306a36Sopenharmony_ci } else if (time_status & STA_DEL) { 41862306a36Sopenharmony_ci time_state = TIME_DEL; 41962306a36Sopenharmony_ci div_s64_rem(secs + 1, SECS_PER_DAY, &rem); 42062306a36Sopenharmony_ci ntp_next_leap_sec = secs + SECS_PER_DAY - rem; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci case TIME_INS: 42462306a36Sopenharmony_ci if (!(time_status & STA_INS)) { 42562306a36Sopenharmony_ci ntp_next_leap_sec = TIME64_MAX; 42662306a36Sopenharmony_ci time_state = TIME_OK; 42762306a36Sopenharmony_ci } else if (secs == ntp_next_leap_sec) { 42862306a36Sopenharmony_ci leap = -1; 42962306a36Sopenharmony_ci time_state = TIME_OOP; 43062306a36Sopenharmony_ci printk(KERN_NOTICE 43162306a36Sopenharmony_ci "Clock: inserting leap second 23:59:60 UTC\n"); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case TIME_DEL: 43562306a36Sopenharmony_ci if (!(time_status & STA_DEL)) { 43662306a36Sopenharmony_ci ntp_next_leap_sec = TIME64_MAX; 43762306a36Sopenharmony_ci time_state = TIME_OK; 43862306a36Sopenharmony_ci } else if (secs == ntp_next_leap_sec) { 43962306a36Sopenharmony_ci leap = 1; 44062306a36Sopenharmony_ci ntp_next_leap_sec = TIME64_MAX; 44162306a36Sopenharmony_ci time_state = TIME_WAIT; 44262306a36Sopenharmony_ci printk(KERN_NOTICE 44362306a36Sopenharmony_ci "Clock: deleting leap second 23:59:59 UTC\n"); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci case TIME_OOP: 44762306a36Sopenharmony_ci ntp_next_leap_sec = TIME64_MAX; 44862306a36Sopenharmony_ci time_state = TIME_WAIT; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci case TIME_WAIT: 45162306a36Sopenharmony_ci if (!(time_status & (STA_INS | STA_DEL))) 45262306a36Sopenharmony_ci time_state = TIME_OK; 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* Bump the maxerror field */ 45862306a36Sopenharmony_ci time_maxerror += MAXFREQ / NSEC_PER_USEC; 45962306a36Sopenharmony_ci if (time_maxerror > NTP_PHASE_LIMIT) { 46062306a36Sopenharmony_ci time_maxerror = NTP_PHASE_LIMIT; 46162306a36Sopenharmony_ci time_status |= STA_UNSYNC; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Compute the phase adjustment for the next second */ 46562306a36Sopenharmony_ci tick_length = tick_length_base; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci delta = ntp_offset_chunk(time_offset); 46862306a36Sopenharmony_ci time_offset -= delta; 46962306a36Sopenharmony_ci tick_length += delta; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Check PPS signal */ 47262306a36Sopenharmony_ci pps_dec_valid(); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!time_adjust) 47562306a36Sopenharmony_ci goto out; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (time_adjust > MAX_TICKADJ) { 47862306a36Sopenharmony_ci time_adjust -= MAX_TICKADJ; 47962306a36Sopenharmony_ci tick_length += MAX_TICKADJ_SCALED; 48062306a36Sopenharmony_ci goto out; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (time_adjust < -MAX_TICKADJ) { 48462306a36Sopenharmony_ci time_adjust += MAX_TICKADJ; 48562306a36Sopenharmony_ci tick_length -= MAX_TICKADJ_SCALED; 48662306a36Sopenharmony_ci goto out; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) 49062306a36Sopenharmony_ci << NTP_SCALE_SHIFT; 49162306a36Sopenharmony_ci time_adjust = 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ciout: 49462306a36Sopenharmony_ci return leap; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC) 49862306a36Sopenharmony_cistatic void sync_hw_clock(struct work_struct *work); 49962306a36Sopenharmony_cistatic DECLARE_WORK(sync_work, sync_hw_clock); 50062306a36Sopenharmony_cistatic struct hrtimer sync_hrtimer; 50162306a36Sopenharmony_ci#define SYNC_PERIOD_NS (11ULL * 60 * NSEC_PER_SEC) 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic enum hrtimer_restart sync_timer_callback(struct hrtimer *timer) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci queue_work(system_freezable_power_efficient_wq, &sync_work); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return HRTIMER_NORESTART; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic void sched_sync_hw_clock(unsigned long offset_nsec, bool retry) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci ktime_t exp = ktime_set(ktime_get_real_seconds(), 0); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (retry) 51562306a36Sopenharmony_ci exp = ktime_add_ns(exp, 2ULL * NSEC_PER_SEC - offset_nsec); 51662306a36Sopenharmony_ci else 51762306a36Sopenharmony_ci exp = ktime_add_ns(exp, SYNC_PERIOD_NS - offset_nsec); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci hrtimer_start(&sync_hrtimer, exp, HRTIMER_MODE_ABS); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/* 52362306a36Sopenharmony_ci * Check whether @now is correct versus the required time to update the RTC 52462306a36Sopenharmony_ci * and calculate the value which needs to be written to the RTC so that the 52562306a36Sopenharmony_ci * next seconds increment of the RTC after the write is aligned with the next 52662306a36Sopenharmony_ci * seconds increment of clock REALTIME. 52762306a36Sopenharmony_ci * 52862306a36Sopenharmony_ci * tsched t1 write(t2.tv_sec - 1sec)) t2 RTC increments seconds 52962306a36Sopenharmony_ci * 53062306a36Sopenharmony_ci * t2.tv_nsec == 0 53162306a36Sopenharmony_ci * tsched = t2 - set_offset_nsec 53262306a36Sopenharmony_ci * newval = t2 - NSEC_PER_SEC 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * ==> neval = tsched + set_offset_nsec - NSEC_PER_SEC 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * As the execution of this code is not guaranteed to happen exactly at 53762306a36Sopenharmony_ci * tsched this allows it to happen within a fuzzy region: 53862306a36Sopenharmony_ci * 53962306a36Sopenharmony_ci * abs(now - tsched) < FUZZ 54062306a36Sopenharmony_ci * 54162306a36Sopenharmony_ci * If @now is not inside the allowed window the function returns false. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_cistatic inline bool rtc_tv_nsec_ok(unsigned long set_offset_nsec, 54462306a36Sopenharmony_ci struct timespec64 *to_set, 54562306a36Sopenharmony_ci const struct timespec64 *now) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci /* Allowed error in tv_nsec, arbitrarily set to 5 jiffies in ns. */ 54862306a36Sopenharmony_ci const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5; 54962306a36Sopenharmony_ci struct timespec64 delay = {.tv_sec = -1, 55062306a36Sopenharmony_ci .tv_nsec = set_offset_nsec}; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci *to_set = timespec64_add(*now, delay); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) { 55562306a36Sopenharmony_ci to_set->tv_nsec = 0; 55662306a36Sopenharmony_ci return true; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) { 56062306a36Sopenharmony_ci to_set->tv_sec++; 56162306a36Sopenharmony_ci to_set->tv_nsec = 0; 56262306a36Sopenharmony_ci return true; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci return false; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci#ifdef CONFIG_GENERIC_CMOS_UPDATE 56862306a36Sopenharmony_ciint __weak update_persistent_clock64(struct timespec64 now64) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci return -ENODEV; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci#else 57362306a36Sopenharmony_cistatic inline int update_persistent_clock64(struct timespec64 now64) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci return -ENODEV; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci#endif 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci#ifdef CONFIG_RTC_SYSTOHC 58062306a36Sopenharmony_ci/* Save NTP synchronized time to the RTC */ 58162306a36Sopenharmony_cistatic int update_rtc(struct timespec64 *to_set, unsigned long *offset_nsec) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct rtc_device *rtc; 58462306a36Sopenharmony_ci struct rtc_time tm; 58562306a36Sopenharmony_ci int err = -ENODEV; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE); 58862306a36Sopenharmony_ci if (!rtc) 58962306a36Sopenharmony_ci return -ENODEV; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!rtc->ops || !rtc->ops->set_time) 59262306a36Sopenharmony_ci goto out_close; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* First call might not have the correct offset */ 59562306a36Sopenharmony_ci if (*offset_nsec == rtc->set_offset_nsec) { 59662306a36Sopenharmony_ci rtc_time64_to_tm(to_set->tv_sec, &tm); 59762306a36Sopenharmony_ci err = rtc_set_time(rtc, &tm); 59862306a36Sopenharmony_ci } else { 59962306a36Sopenharmony_ci /* Store the update offset and let the caller try again */ 60062306a36Sopenharmony_ci *offset_nsec = rtc->set_offset_nsec; 60162306a36Sopenharmony_ci err = -EAGAIN; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ciout_close: 60462306a36Sopenharmony_ci rtc_class_close(rtc); 60562306a36Sopenharmony_ci return err; 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci#else 60862306a36Sopenharmony_cistatic inline int update_rtc(struct timespec64 *to_set, unsigned long *offset_nsec) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci return -ENODEV; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci#endif 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* 61562306a36Sopenharmony_ci * If we have an externally synchronized Linux clock, then update RTC clock 61662306a36Sopenharmony_ci * accordingly every ~11 minutes. Generally RTCs can only store second 61762306a36Sopenharmony_ci * precision, but many RTCs will adjust the phase of their second tick to 61862306a36Sopenharmony_ci * match the moment of update. This infrastructure arranges to call to the RTC 61962306a36Sopenharmony_ci * set at the correct moment to phase synchronize the RTC second tick over 62062306a36Sopenharmony_ci * with the kernel clock. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_cistatic void sync_hw_clock(struct work_struct *work) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci /* 62562306a36Sopenharmony_ci * The default synchronization offset is 500ms for the deprecated 62662306a36Sopenharmony_ci * update_persistent_clock64() under the assumption that it uses 62762306a36Sopenharmony_ci * the infamous CMOS clock (MC146818). 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci static unsigned long offset_nsec = NSEC_PER_SEC / 2; 63062306a36Sopenharmony_ci struct timespec64 now, to_set; 63162306a36Sopenharmony_ci int res = -EAGAIN; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* 63462306a36Sopenharmony_ci * Don't update if STA_UNSYNC is set and if ntp_notify_cmos_timer() 63562306a36Sopenharmony_ci * managed to schedule the work between the timer firing and the 63662306a36Sopenharmony_ci * work being able to rearm the timer. Wait for the timer to expire. 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci if (!ntp_synced() || hrtimer_is_queued(&sync_hrtimer)) 63962306a36Sopenharmony_ci return; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci ktime_get_real_ts64(&now); 64262306a36Sopenharmony_ci /* If @now is not in the allowed window, try again */ 64362306a36Sopenharmony_ci if (!rtc_tv_nsec_ok(offset_nsec, &to_set, &now)) 64462306a36Sopenharmony_ci goto rearm; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Take timezone adjusted RTCs into account */ 64762306a36Sopenharmony_ci if (persistent_clock_is_local) 64862306a36Sopenharmony_ci to_set.tv_sec -= (sys_tz.tz_minuteswest * 60); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* Try the legacy RTC first. */ 65162306a36Sopenharmony_ci res = update_persistent_clock64(to_set); 65262306a36Sopenharmony_ci if (res != -ENODEV) 65362306a36Sopenharmony_ci goto rearm; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* Try the RTC class */ 65662306a36Sopenharmony_ci res = update_rtc(&to_set, &offset_nsec); 65762306a36Sopenharmony_ci if (res == -ENODEV) 65862306a36Sopenharmony_ci return; 65962306a36Sopenharmony_cirearm: 66062306a36Sopenharmony_ci sched_sync_hw_clock(offset_nsec, res != 0); 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_civoid ntp_notify_cmos_timer(void) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * When the work is currently executed but has not yet the timer 66762306a36Sopenharmony_ci * rearmed this queues the work immediately again. No big issue, 66862306a36Sopenharmony_ci * just a pointless work scheduled. 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci if (ntp_synced() && !hrtimer_is_queued(&sync_hrtimer)) 67162306a36Sopenharmony_ci queue_work(system_freezable_power_efficient_wq, &sync_work); 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic void __init ntp_init_cmos_sync(void) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci hrtimer_init(&sync_hrtimer, CLOCK_REALTIME, HRTIMER_MODE_ABS); 67762306a36Sopenharmony_ci sync_hrtimer.function = sync_timer_callback; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci#else /* CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC) */ 68062306a36Sopenharmony_cistatic inline void __init ntp_init_cmos_sync(void) { } 68162306a36Sopenharmony_ci#endif /* !CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC) */ 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci/* 68462306a36Sopenharmony_ci * Propagate a new txc->status value into the NTP state: 68562306a36Sopenharmony_ci */ 68662306a36Sopenharmony_cistatic inline void process_adj_status(const struct __kernel_timex *txc) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) { 68962306a36Sopenharmony_ci time_state = TIME_OK; 69062306a36Sopenharmony_ci time_status = STA_UNSYNC; 69162306a36Sopenharmony_ci ntp_next_leap_sec = TIME64_MAX; 69262306a36Sopenharmony_ci /* restart PPS frequency calibration */ 69362306a36Sopenharmony_ci pps_reset_freq_interval(); 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* 69762306a36Sopenharmony_ci * If we turn on PLL adjustments then reset the 69862306a36Sopenharmony_ci * reference time to current time. 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci if (!(time_status & STA_PLL) && (txc->status & STA_PLL)) 70162306a36Sopenharmony_ci time_reftime = __ktime_get_real_seconds(); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* only set allowed bits */ 70462306a36Sopenharmony_ci time_status &= STA_RONLY; 70562306a36Sopenharmony_ci time_status |= txc->status & ~STA_RONLY; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic inline void process_adjtimex_modes(const struct __kernel_timex *txc, 71062306a36Sopenharmony_ci s32 *time_tai) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci if (txc->modes & ADJ_STATUS) 71362306a36Sopenharmony_ci process_adj_status(txc); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (txc->modes & ADJ_NANO) 71662306a36Sopenharmony_ci time_status |= STA_NANO; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (txc->modes & ADJ_MICRO) 71962306a36Sopenharmony_ci time_status &= ~STA_NANO; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci if (txc->modes & ADJ_FREQUENCY) { 72262306a36Sopenharmony_ci time_freq = txc->freq * PPM_SCALE; 72362306a36Sopenharmony_ci time_freq = min(time_freq, MAXFREQ_SCALED); 72462306a36Sopenharmony_ci time_freq = max(time_freq, -MAXFREQ_SCALED); 72562306a36Sopenharmony_ci /* update pps_freq */ 72662306a36Sopenharmony_ci pps_set_freq(time_freq); 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (txc->modes & ADJ_MAXERROR) 73062306a36Sopenharmony_ci time_maxerror = txc->maxerror; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (txc->modes & ADJ_ESTERROR) 73362306a36Sopenharmony_ci time_esterror = txc->esterror; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (txc->modes & ADJ_TIMECONST) { 73662306a36Sopenharmony_ci time_constant = txc->constant; 73762306a36Sopenharmony_ci if (!(time_status & STA_NANO)) 73862306a36Sopenharmony_ci time_constant += 4; 73962306a36Sopenharmony_ci time_constant = min(time_constant, (long)MAXTC); 74062306a36Sopenharmony_ci time_constant = max(time_constant, 0l); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (txc->modes & ADJ_TAI && 74462306a36Sopenharmony_ci txc->constant >= 0 && txc->constant <= MAX_TAI_OFFSET) 74562306a36Sopenharmony_ci *time_tai = txc->constant; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (txc->modes & ADJ_OFFSET) 74862306a36Sopenharmony_ci ntp_update_offset(txc->offset); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (txc->modes & ADJ_TICK) 75162306a36Sopenharmony_ci tick_usec = txc->tick; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET)) 75462306a36Sopenharmony_ci ntp_update_frequency(); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci/* 75962306a36Sopenharmony_ci * adjtimex mainly allows reading (and writing, if superuser) of 76062306a36Sopenharmony_ci * kernel time-keeping variables. used by xntpd. 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_ciint __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts, 76362306a36Sopenharmony_ci s32 *time_tai, struct audit_ntp_data *ad) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci int result; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (txc->modes & ADJ_ADJTIME) { 76862306a36Sopenharmony_ci long save_adjust = time_adjust; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (!(txc->modes & ADJ_OFFSET_READONLY)) { 77162306a36Sopenharmony_ci /* adjtime() is independent from ntp_adjtime() */ 77262306a36Sopenharmony_ci time_adjust = txc->offset; 77362306a36Sopenharmony_ci ntp_update_frequency(); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci audit_ntp_set_old(ad, AUDIT_NTP_ADJUST, save_adjust); 77662306a36Sopenharmony_ci audit_ntp_set_new(ad, AUDIT_NTP_ADJUST, time_adjust); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci txc->offset = save_adjust; 77962306a36Sopenharmony_ci } else { 78062306a36Sopenharmony_ci /* If there are input parameters, then process them: */ 78162306a36Sopenharmony_ci if (txc->modes) { 78262306a36Sopenharmony_ci audit_ntp_set_old(ad, AUDIT_NTP_OFFSET, time_offset); 78362306a36Sopenharmony_ci audit_ntp_set_old(ad, AUDIT_NTP_FREQ, time_freq); 78462306a36Sopenharmony_ci audit_ntp_set_old(ad, AUDIT_NTP_STATUS, time_status); 78562306a36Sopenharmony_ci audit_ntp_set_old(ad, AUDIT_NTP_TAI, *time_tai); 78662306a36Sopenharmony_ci audit_ntp_set_old(ad, AUDIT_NTP_TICK, tick_usec); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci process_adjtimex_modes(txc, time_tai); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci audit_ntp_set_new(ad, AUDIT_NTP_OFFSET, time_offset); 79162306a36Sopenharmony_ci audit_ntp_set_new(ad, AUDIT_NTP_FREQ, time_freq); 79262306a36Sopenharmony_ci audit_ntp_set_new(ad, AUDIT_NTP_STATUS, time_status); 79362306a36Sopenharmony_ci audit_ntp_set_new(ad, AUDIT_NTP_TAI, *time_tai); 79462306a36Sopenharmony_ci audit_ntp_set_new(ad, AUDIT_NTP_TICK, tick_usec); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, 79862306a36Sopenharmony_ci NTP_SCALE_SHIFT); 79962306a36Sopenharmony_ci if (!(time_status & STA_NANO)) 80062306a36Sopenharmony_ci txc->offset = (u32)txc->offset / NSEC_PER_USEC; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci result = time_state; /* mostly `TIME_OK' */ 80462306a36Sopenharmony_ci /* check for errors */ 80562306a36Sopenharmony_ci if (is_error_status(time_status)) 80662306a36Sopenharmony_ci result = TIME_ERROR; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci txc->freq = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) * 80962306a36Sopenharmony_ci PPM_SCALE_INV, NTP_SCALE_SHIFT); 81062306a36Sopenharmony_ci txc->maxerror = time_maxerror; 81162306a36Sopenharmony_ci txc->esterror = time_esterror; 81262306a36Sopenharmony_ci txc->status = time_status; 81362306a36Sopenharmony_ci txc->constant = time_constant; 81462306a36Sopenharmony_ci txc->precision = 1; 81562306a36Sopenharmony_ci txc->tolerance = MAXFREQ_SCALED / PPM_SCALE; 81662306a36Sopenharmony_ci txc->tick = tick_usec; 81762306a36Sopenharmony_ci txc->tai = *time_tai; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* fill PPS status fields */ 82062306a36Sopenharmony_ci pps_fill_timex(txc); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci txc->time.tv_sec = ts->tv_sec; 82362306a36Sopenharmony_ci txc->time.tv_usec = ts->tv_nsec; 82462306a36Sopenharmony_ci if (!(time_status & STA_NANO)) 82562306a36Sopenharmony_ci txc->time.tv_usec = ts->tv_nsec / NSEC_PER_USEC; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci /* Handle leapsec adjustments */ 82862306a36Sopenharmony_ci if (unlikely(ts->tv_sec >= ntp_next_leap_sec)) { 82962306a36Sopenharmony_ci if ((time_state == TIME_INS) && (time_status & STA_INS)) { 83062306a36Sopenharmony_ci result = TIME_OOP; 83162306a36Sopenharmony_ci txc->tai++; 83262306a36Sopenharmony_ci txc->time.tv_sec--; 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci if ((time_state == TIME_DEL) && (time_status & STA_DEL)) { 83562306a36Sopenharmony_ci result = TIME_WAIT; 83662306a36Sopenharmony_ci txc->tai--; 83762306a36Sopenharmony_ci txc->time.tv_sec++; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci if ((time_state == TIME_OOP) && 84062306a36Sopenharmony_ci (ts->tv_sec == ntp_next_leap_sec)) { 84162306a36Sopenharmony_ci result = TIME_WAIT; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return result; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci#ifdef CONFIG_NTP_PPS 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/* actually struct pps_normtime is good old struct timespec, but it is 85162306a36Sopenharmony_ci * semantically different (and it is the reason why it was invented): 85262306a36Sopenharmony_ci * pps_normtime.nsec has a range of ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] 85362306a36Sopenharmony_ci * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC) */ 85462306a36Sopenharmony_cistruct pps_normtime { 85562306a36Sopenharmony_ci s64 sec; /* seconds */ 85662306a36Sopenharmony_ci long nsec; /* nanoseconds */ 85762306a36Sopenharmony_ci}; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci/* normalize the timestamp so that nsec is in the 86062306a36Sopenharmony_ci ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval */ 86162306a36Sopenharmony_cistatic inline struct pps_normtime pps_normalize_ts(struct timespec64 ts) 86262306a36Sopenharmony_ci{ 86362306a36Sopenharmony_ci struct pps_normtime norm = { 86462306a36Sopenharmony_ci .sec = ts.tv_sec, 86562306a36Sopenharmony_ci .nsec = ts.tv_nsec 86662306a36Sopenharmony_ci }; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (norm.nsec > (NSEC_PER_SEC >> 1)) { 86962306a36Sopenharmony_ci norm.nsec -= NSEC_PER_SEC; 87062306a36Sopenharmony_ci norm.sec++; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci return norm; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci/* get current phase correction and jitter */ 87762306a36Sopenharmony_cistatic inline long pps_phase_filter_get(long *jitter) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci *jitter = pps_tf[0] - pps_tf[1]; 88062306a36Sopenharmony_ci if (*jitter < 0) 88162306a36Sopenharmony_ci *jitter = -*jitter; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* TODO: test various filters */ 88462306a36Sopenharmony_ci return pps_tf[0]; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci/* add the sample to the phase filter */ 88862306a36Sopenharmony_cistatic inline void pps_phase_filter_add(long err) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci pps_tf[2] = pps_tf[1]; 89162306a36Sopenharmony_ci pps_tf[1] = pps_tf[0]; 89262306a36Sopenharmony_ci pps_tf[0] = err; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci/* decrease frequency calibration interval length. 89662306a36Sopenharmony_ci * It is halved after four consecutive unstable intervals. 89762306a36Sopenharmony_ci */ 89862306a36Sopenharmony_cistatic inline void pps_dec_freq_interval(void) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci if (--pps_intcnt <= -PPS_INTCOUNT) { 90162306a36Sopenharmony_ci pps_intcnt = -PPS_INTCOUNT; 90262306a36Sopenharmony_ci if (pps_shift > PPS_INTMIN) { 90362306a36Sopenharmony_ci pps_shift--; 90462306a36Sopenharmony_ci pps_intcnt = 0; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci/* increase frequency calibration interval length. 91062306a36Sopenharmony_ci * It is doubled after four consecutive stable intervals. 91162306a36Sopenharmony_ci */ 91262306a36Sopenharmony_cistatic inline void pps_inc_freq_interval(void) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci if (++pps_intcnt >= PPS_INTCOUNT) { 91562306a36Sopenharmony_ci pps_intcnt = PPS_INTCOUNT; 91662306a36Sopenharmony_ci if (pps_shift < PPS_INTMAX) { 91762306a36Sopenharmony_ci pps_shift++; 91862306a36Sopenharmony_ci pps_intcnt = 0; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci/* update clock frequency based on MONOTONIC_RAW clock PPS signal 92462306a36Sopenharmony_ci * timestamps 92562306a36Sopenharmony_ci * 92662306a36Sopenharmony_ci * At the end of the calibration interval the difference between the 92762306a36Sopenharmony_ci * first and last MONOTONIC_RAW clock timestamps divided by the length 92862306a36Sopenharmony_ci * of the interval becomes the frequency update. If the interval was 92962306a36Sopenharmony_ci * too long, the data are discarded. 93062306a36Sopenharmony_ci * Returns the difference between old and new frequency values. 93162306a36Sopenharmony_ci */ 93262306a36Sopenharmony_cistatic long hardpps_update_freq(struct pps_normtime freq_norm) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci long delta, delta_mod; 93562306a36Sopenharmony_ci s64 ftemp; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* check if the frequency interval was too long */ 93862306a36Sopenharmony_ci if (freq_norm.sec > (2 << pps_shift)) { 93962306a36Sopenharmony_ci time_status |= STA_PPSERROR; 94062306a36Sopenharmony_ci pps_errcnt++; 94162306a36Sopenharmony_ci pps_dec_freq_interval(); 94262306a36Sopenharmony_ci printk_deferred(KERN_ERR 94362306a36Sopenharmony_ci "hardpps: PPSERROR: interval too long - %lld s\n", 94462306a36Sopenharmony_ci freq_norm.sec); 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci /* here the raw frequency offset and wander (stability) is 94962306a36Sopenharmony_ci * calculated. If the wander is less than the wander threshold 95062306a36Sopenharmony_ci * the interval is increased; otherwise it is decreased. 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT, 95362306a36Sopenharmony_ci freq_norm.sec); 95462306a36Sopenharmony_ci delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT); 95562306a36Sopenharmony_ci pps_freq = ftemp; 95662306a36Sopenharmony_ci if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) { 95762306a36Sopenharmony_ci printk_deferred(KERN_WARNING 95862306a36Sopenharmony_ci "hardpps: PPSWANDER: change=%ld\n", delta); 95962306a36Sopenharmony_ci time_status |= STA_PPSWANDER; 96062306a36Sopenharmony_ci pps_stbcnt++; 96162306a36Sopenharmony_ci pps_dec_freq_interval(); 96262306a36Sopenharmony_ci } else { /* good sample */ 96362306a36Sopenharmony_ci pps_inc_freq_interval(); 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* the stability metric is calculated as the average of recent 96762306a36Sopenharmony_ci * frequency changes, but is used only for performance 96862306a36Sopenharmony_ci * monitoring 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_ci delta_mod = delta; 97162306a36Sopenharmony_ci if (delta_mod < 0) 97262306a36Sopenharmony_ci delta_mod = -delta_mod; 97362306a36Sopenharmony_ci pps_stabil += (div_s64(((s64)delta_mod) << 97462306a36Sopenharmony_ci (NTP_SCALE_SHIFT - SHIFT_USEC), 97562306a36Sopenharmony_ci NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* if enabled, the system clock frequency is updated */ 97862306a36Sopenharmony_ci if ((time_status & STA_PPSFREQ) != 0 && 97962306a36Sopenharmony_ci (time_status & STA_FREQHOLD) == 0) { 98062306a36Sopenharmony_ci time_freq = pps_freq; 98162306a36Sopenharmony_ci ntp_update_frequency(); 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return delta; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci/* correct REALTIME clock phase error against PPS signal */ 98862306a36Sopenharmony_cistatic void hardpps_update_phase(long error) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci long correction = -error; 99162306a36Sopenharmony_ci long jitter; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* add the sample to the median filter */ 99462306a36Sopenharmony_ci pps_phase_filter_add(correction); 99562306a36Sopenharmony_ci correction = pps_phase_filter_get(&jitter); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* Nominal jitter is due to PPS signal noise. If it exceeds the 99862306a36Sopenharmony_ci * threshold, the sample is discarded; otherwise, if so enabled, 99962306a36Sopenharmony_ci * the time offset is updated. 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci if (jitter > (pps_jitter << PPS_POPCORN)) { 100262306a36Sopenharmony_ci printk_deferred(KERN_WARNING 100362306a36Sopenharmony_ci "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n", 100462306a36Sopenharmony_ci jitter, (pps_jitter << PPS_POPCORN)); 100562306a36Sopenharmony_ci time_status |= STA_PPSJITTER; 100662306a36Sopenharmony_ci pps_jitcnt++; 100762306a36Sopenharmony_ci } else if (time_status & STA_PPSTIME) { 100862306a36Sopenharmony_ci /* correct the time using the phase offset */ 100962306a36Sopenharmony_ci time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, 101062306a36Sopenharmony_ci NTP_INTERVAL_FREQ); 101162306a36Sopenharmony_ci /* cancel running adjtime() */ 101262306a36Sopenharmony_ci time_adjust = 0; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci /* update jitter */ 101562306a36Sopenharmony_ci pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci/* 101962306a36Sopenharmony_ci * __hardpps() - discipline CPU clock oscillator to external PPS signal 102062306a36Sopenharmony_ci * 102162306a36Sopenharmony_ci * This routine is called at each PPS signal arrival in order to 102262306a36Sopenharmony_ci * discipline the CPU clock oscillator to the PPS signal. It takes two 102362306a36Sopenharmony_ci * parameters: REALTIME and MONOTONIC_RAW clock timestamps. The former 102462306a36Sopenharmony_ci * is used to correct clock phase error and the latter is used to 102562306a36Sopenharmony_ci * correct the frequency. 102662306a36Sopenharmony_ci * 102762306a36Sopenharmony_ci * This code is based on David Mills's reference nanokernel 102862306a36Sopenharmony_ci * implementation. It was mostly rewritten but keeps the same idea. 102962306a36Sopenharmony_ci */ 103062306a36Sopenharmony_civoid __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct pps_normtime pts_norm, freq_norm; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci pts_norm = pps_normalize_ts(*phase_ts); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* clear the error bits, they will be set again if needed */ 103762306a36Sopenharmony_ci time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci /* indicate signal presence */ 104062306a36Sopenharmony_ci time_status |= STA_PPSSIGNAL; 104162306a36Sopenharmony_ci pps_valid = PPS_VALID; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* when called for the first time, 104462306a36Sopenharmony_ci * just start the frequency interval */ 104562306a36Sopenharmony_ci if (unlikely(pps_fbase.tv_sec == 0)) { 104662306a36Sopenharmony_ci pps_fbase = *raw_ts; 104762306a36Sopenharmony_ci return; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci /* ok, now we have a base for frequency calculation */ 105162306a36Sopenharmony_ci freq_norm = pps_normalize_ts(timespec64_sub(*raw_ts, pps_fbase)); 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* check that the signal is in the range 105462306a36Sopenharmony_ci * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */ 105562306a36Sopenharmony_ci if ((freq_norm.sec == 0) || 105662306a36Sopenharmony_ci (freq_norm.nsec > MAXFREQ * freq_norm.sec) || 105762306a36Sopenharmony_ci (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) { 105862306a36Sopenharmony_ci time_status |= STA_PPSJITTER; 105962306a36Sopenharmony_ci /* restart the frequency calibration interval */ 106062306a36Sopenharmony_ci pps_fbase = *raw_ts; 106162306a36Sopenharmony_ci printk_deferred(KERN_ERR "hardpps: PPSJITTER: bad pulse\n"); 106262306a36Sopenharmony_ci return; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* signal is ok */ 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* check if the current frequency interval is finished */ 106862306a36Sopenharmony_ci if (freq_norm.sec >= (1 << pps_shift)) { 106962306a36Sopenharmony_ci pps_calcnt++; 107062306a36Sopenharmony_ci /* restart the frequency calibration interval */ 107162306a36Sopenharmony_ci pps_fbase = *raw_ts; 107262306a36Sopenharmony_ci hardpps_update_freq(freq_norm); 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci hardpps_update_phase(pts_norm.nsec); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci#endif /* CONFIG_NTP_PPS */ 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_cistatic int __init ntp_tick_adj_setup(char *str) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci int rc = kstrtos64(str, 0, &ntp_tick_adj); 108362306a36Sopenharmony_ci if (rc) 108462306a36Sopenharmony_ci return rc; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci ntp_tick_adj <<= NTP_SCALE_SHIFT; 108762306a36Sopenharmony_ci return 1; 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci__setup("ntp_tick_adj=", ntp_tick_adj_setup); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_civoid __init ntp_init(void) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci ntp_clear(); 109562306a36Sopenharmony_ci ntp_init_cmos_sync(); 109662306a36Sopenharmony_ci} 1097