#include <linux/capability.h>
#include <linux/clocksource.h>
#include <linux/workqueue.h>
#include <linux/hrtimer.h>
#include <linux/jiffies.h>
#include <linux/math64.h>
#include <linux/timex.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/audit.h>
#include "ntp_internal.h"
#include "timekeeping_internal.h"
unsigned long tick_usec = …;
unsigned long tick_nsec;
static u64 tick_length;
static u64 tick_length_base;
#define SECS_PER_DAY …
#define MAX_TICKADJ …
#define MAX_TICKADJ_SCALED …
#define MAX_TAI_OFFSET …
static int time_state = …;
static int time_status = …;
static s64 time_offset;
static long time_constant = …;
static long time_maxerror = …;
static long time_esterror = …;
static s64 time_freq;
static time64_t time_reftime;
static long time_adjust;
static s64 ntp_tick_adj;
static time64_t ntp_next_leap_sec = …;
#ifdef CONFIG_NTP_PPS
#define PPS_VALID …
#define PPS_POPCORN …
#define PPS_INTMIN …
#define PPS_INTMAX …
#define PPS_INTCOUNT …
#define PPS_MAXWANDER …
static int pps_valid;
static long pps_tf[3];
static long pps_jitter;
static struct timespec64 pps_fbase;
static int pps_shift;
static int pps_intcnt;
static s64 pps_freq;
static long pps_stabil;
static long pps_calcnt;
static long pps_jitcnt;
static long pps_stbcnt;
static long pps_errcnt;
static inline s64 ntp_offset_chunk(s64 offset)
{
if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL)
return offset;
else
return shift_right(offset, SHIFT_PLL + time_constant);
}
static inline void pps_reset_freq_interval(void)
{
pps_shift = PPS_INTMIN;
pps_intcnt = 0;
}
static inline void pps_clear(void)
{
pps_reset_freq_interval();
pps_tf[0] = 0;
pps_tf[1] = 0;
pps_tf[2] = 0;
pps_fbase.tv_sec = pps_fbase.tv_nsec = 0;
pps_freq = 0;
}
static inline void pps_dec_valid(void)
{
if (pps_valid > 0)
pps_valid--;
else {
time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER |
STA_PPSWANDER | STA_PPSERROR);
pps_clear();
}
}
static inline void pps_set_freq(s64 freq)
{
pps_freq = freq;
}
static inline int is_error_status(int status)
{
return (status & (STA_UNSYNC|STA_CLOCKERR))
|| ((status & (STA_PPSFREQ|STA_PPSTIME))
&& !(status & STA_PPSSIGNAL))
|| ((status & (STA_PPSTIME|STA_PPSJITTER))
== (STA_PPSTIME|STA_PPSJITTER))
|| ((status & STA_PPSFREQ)
&& (status & (STA_PPSWANDER|STA_PPSERROR)));
}
static inline void pps_fill_timex(struct __kernel_timex *txc)
{
txc->ppsfreq = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) *
PPM_SCALE_INV, NTP_SCALE_SHIFT);
txc->jitter = pps_jitter;
if (!(time_status & STA_NANO))
txc->jitter = pps_jitter / NSEC_PER_USEC;
txc->shift = pps_shift;
txc->stabil = pps_stabil;
txc->jitcnt = pps_jitcnt;
txc->calcnt = pps_calcnt;
txc->errcnt = pps_errcnt;
txc->stbcnt = pps_stbcnt;
}
#else
static inline s64 ntp_offset_chunk(s64 offset)
{ … }
static inline void pps_reset_freq_interval(void) { … }
static inline void pps_clear(void) { … }
static inline void pps_dec_valid(void) { … }
static inline void pps_set_freq(s64 freq) { … }
static inline int is_error_status(int status)
{ … }
static inline void pps_fill_timex(struct __kernel_timex *txc)
{ … }
#endif
static inline int ntp_synced(void)
{ … }
static void ntp_update_frequency(void)
{ … }
static inline s64 ntp_update_offset_fll(s64 offset64, long secs)
{ … }
static void ntp_update_offset(long offset)
{ … }
void ntp_clear(void)
{ … }
u64 ntp_tick_length(void)
{ … }
ktime_t ntp_get_next_leap(void)
{ … }
int second_overflow(time64_t secs)
{ … }
#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
static void sync_hw_clock(struct work_struct *work);
static DECLARE_WORK(sync_work, sync_hw_clock);
static struct hrtimer sync_hrtimer;
#define SYNC_PERIOD_NS …
static enum hrtimer_restart sync_timer_callback(struct hrtimer *timer)
{ … }
static void sched_sync_hw_clock(unsigned long offset_nsec, bool retry)
{ … }
static inline bool rtc_tv_nsec_ok(unsigned long set_offset_nsec,
struct timespec64 *to_set,
const struct timespec64 *now)
{ … }
#ifdef CONFIG_GENERIC_CMOS_UPDATE
int __weak update_persistent_clock64(struct timespec64 now64)
{ … }
#else
static inline int update_persistent_clock64(struct timespec64 now64)
{
return -ENODEV;
}
#endif
#ifdef CONFIG_RTC_SYSTOHC
static int update_rtc(struct timespec64 *to_set, unsigned long *offset_nsec)
{ … }
#else
static inline int update_rtc(struct timespec64 *to_set, unsigned long *offset_nsec)
{
return -ENODEV;
}
#endif
static void sync_hw_clock(struct work_struct *work)
{ … }
void ntp_notify_cmos_timer(void)
{ … }
static void __init ntp_init_cmos_sync(void)
{ … }
#else
static inline void __init ntp_init_cmos_sync(void) { }
#endif
static inline void process_adj_status(const struct __kernel_timex *txc)
{ … }
static inline void process_adjtimex_modes(const struct __kernel_timex *txc,
s32 *time_tai)
{ … }
int __do_adjtimex(struct __kernel_timex *txc, const struct timespec64 *ts,
s32 *time_tai, struct audit_ntp_data *ad)
{ … }
#ifdef CONFIG_NTP_PPS
struct pps_normtime {
s64 sec;
long nsec;
};
static inline struct pps_normtime pps_normalize_ts(struct timespec64 ts)
{
struct pps_normtime norm = {
.sec = ts.tv_sec,
.nsec = ts.tv_nsec
};
if (norm.nsec > (NSEC_PER_SEC >> 1)) {
norm.nsec -= NSEC_PER_SEC;
norm.sec++;
}
return norm;
}
static inline long pps_phase_filter_get(long *jitter)
{
*jitter = pps_tf[0] - pps_tf[1];
if (*jitter < 0)
*jitter = -*jitter;
return pps_tf[0];
}
static inline void pps_phase_filter_add(long err)
{
pps_tf[2] = pps_tf[1];
pps_tf[1] = pps_tf[0];
pps_tf[0] = err;
}
static inline void pps_dec_freq_interval(void)
{
if (--pps_intcnt <= -PPS_INTCOUNT) {
pps_intcnt = -PPS_INTCOUNT;
if (pps_shift > PPS_INTMIN) {
pps_shift--;
pps_intcnt = 0;
}
}
}
static inline void pps_inc_freq_interval(void)
{
if (++pps_intcnt >= PPS_INTCOUNT) {
pps_intcnt = PPS_INTCOUNT;
if (pps_shift < PPS_INTMAX) {
pps_shift++;
pps_intcnt = 0;
}
}
}
static long hardpps_update_freq(struct pps_normtime freq_norm)
{
long delta, delta_mod;
s64 ftemp;
if (freq_norm.sec > (2 << pps_shift)) {
time_status |= STA_PPSERROR;
pps_errcnt++;
pps_dec_freq_interval();
printk_deferred(KERN_ERR
"hardpps: PPSERROR: interval too long - %lld s\n",
freq_norm.sec);
return 0;
}
ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT,
freq_norm.sec);
delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT);
pps_freq = ftemp;
if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) {
printk_deferred(KERN_WARNING
"hardpps: PPSWANDER: change=%ld\n", delta);
time_status |= STA_PPSWANDER;
pps_stbcnt++;
pps_dec_freq_interval();
} else {
pps_inc_freq_interval();
}
delta_mod = delta;
if (delta_mod < 0)
delta_mod = -delta_mod;
pps_stabil += (div_s64(((s64)delta_mod) <<
(NTP_SCALE_SHIFT - SHIFT_USEC),
NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN;
if ((time_status & STA_PPSFREQ) != 0 &&
(time_status & STA_FREQHOLD) == 0) {
time_freq = pps_freq;
ntp_update_frequency();
}
return delta;
}
static void hardpps_update_phase(long error)
{
long correction = -error;
long jitter;
pps_phase_filter_add(correction);
correction = pps_phase_filter_get(&jitter);
if (jitter > (pps_jitter << PPS_POPCORN)) {
printk_deferred(KERN_WARNING
"hardpps: PPSJITTER: jitter=%ld, limit=%ld\n",
jitter, (pps_jitter << PPS_POPCORN));
time_status |= STA_PPSJITTER;
pps_jitcnt++;
} else if (time_status & STA_PPSTIME) {
time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT,
NTP_INTERVAL_FREQ);
time_adjust = 0;
}
pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN;
}
void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts)
{
struct pps_normtime pts_norm, freq_norm;
pts_norm = pps_normalize_ts(*phase_ts);
time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR);
time_status |= STA_PPSSIGNAL;
pps_valid = PPS_VALID;
if (unlikely(pps_fbase.tv_sec == 0)) {
pps_fbase = *raw_ts;
return;
}
freq_norm = pps_normalize_ts(timespec64_sub(*raw_ts, pps_fbase));
if ((freq_norm.sec == 0) ||
(freq_norm.nsec > MAXFREQ * freq_norm.sec) ||
(freq_norm.nsec < -MAXFREQ * freq_norm.sec)) {
time_status |= STA_PPSJITTER;
pps_fbase = *raw_ts;
printk_deferred(KERN_ERR "hardpps: PPSJITTER: bad pulse\n");
return;
}
if (freq_norm.sec >= (1 << pps_shift)) {
pps_calcnt++;
pps_fbase = *raw_ts;
hardpps_update_freq(freq_norm);
}
hardpps_update_phase(pts_norm.nsec);
}
#endif
static int __init ntp_tick_adj_setup(char *str)
{ … }
__setup(…);
void __init ntp_init(void)
{ … }