summaryrefslogtreecommitdiffstats
path: root/freebsd/sys
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2013-10-29 15:22:58 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2013-10-31 13:18:53 +0100
commit89761ed7548cd45e9f01ade9e90ce9422ebfd99a (patch)
tree52e417de6e99951a599da4a5898de5ca1abdc107 /freebsd/sys
parentselectpollkqueue01: New test (diff)
downloadrtems-libbsd-89761ed7548cd45e9f01ade9e90ce9422ebfd99a.tar.bz2
Do not use FreeBSD time control
Diffstat (limited to 'freebsd/sys')
-rw-r--r--freebsd/sys/kern/kern_ntptime.c1045
-rw-r--r--freebsd/sys/kern/kern_tc.c968
2 files changed, 0 insertions, 2013 deletions
diff --git a/freebsd/sys/kern/kern_ntptime.c b/freebsd/sys/kern/kern_ntptime.c
deleted file mode 100644
index c49b82dd..00000000
--- a/freebsd/sys/kern/kern_ntptime.c
+++ /dev/null
@@ -1,1045 +0,0 @@
-#include <machine/rtems-bsd-config.h>
-
-/*-
- ***********************************************************************
- * *
- * Copyright (c) David L. Mills 1993-2001 *
- * *
- * Permission to use, copy, modify, and distribute this software and *
- * its documentation for any purpose and without fee is hereby *
- * granted, provided that the above copyright notice appears in all *
- * copies and that both the copyright notice and this permission *
- * notice appear in supporting documentation, and that the name *
- * University of Delaware not be used in advertising or publicity *
- * pertaining to distribution of the software without specific, *
- * written prior permission. The University of Delaware makes no *
- * representations about the suitability this software for any *
- * purpose. It is provided "as is" without express or implied *
- * warranty. *
- * *
- **********************************************************************/
-
-/*
- * Adapted from the original sources for FreeBSD and timecounters by:
- * Poul-Henning Kamp <phk@FreeBSD.org>.
- *
- * The 32bit version of the "LP" macros seems a bit past its "sell by"
- * date so I have retained only the 64bit version and included it directly
- * in this file.
- *
- * Only minor changes done to interface with the timecounters over in
- * sys/kern/kern_clock.c. Some of the comments below may be (even more)
- * confusing and/or plain wrong in that context.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <rtems/bsd/local/opt_ntp.h>
-
-#include <rtems/bsd/sys/param.h>
-#include <sys/systm.h>
-#include <sys/sysproto.h>
-#include <sys/eventhandler.h>
-#include <sys/kernel.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
-#include <rtems/bsd/sys/lock.h>
-#include <sys/mutex.h>
-#include <rtems/bsd/sys/time.h>
-#include <sys/timex.h>
-#include <sys/timetc.h>
-#include <sys/timepps.h>
-#include <sys/syscallsubr.h>
-#include <sys/sysctl.h>
-
-/*
- * Single-precision macros for 64-bit machines
- */
-typedef int64_t l_fp;
-#define L_ADD(v, u) ((v) += (u))
-#define L_SUB(v, u) ((v) -= (u))
-#define L_ADDHI(v, a) ((v) += (int64_t)(a) << 32)
-#define L_NEG(v) ((v) = -(v))
-#define L_RSHIFT(v, n) \
- do { \
- if ((v) < 0) \
- (v) = -(-(v) >> (n)); \
- else \
- (v) = (v) >> (n); \
- } while (0)
-#define L_MPY(v, a) ((v) *= (a))
-#define L_CLR(v) ((v) = 0)
-#define L_ISNEG(v) ((v) < 0)
-#define L_LINT(v, a) ((v) = (int64_t)(a) << 32)
-#define L_GINT(v) ((v) < 0 ? -(-(v) >> 32) : (v) >> 32)
-
-/*
- * Generic NTP kernel interface
- *
- * These routines constitute the Network Time Protocol (NTP) interfaces
- * for user and daemon application programs. The ntp_gettime() routine
- * provides the time, maximum error (synch distance) and estimated error
- * (dispersion) to client user application programs. The ntp_adjtime()
- * routine is used by the NTP daemon to adjust the system clock to an
- * externally derived time. The time offset and related variables set by
- * this routine are used by other routines in this module to adjust the
- * phase and frequency of the clock discipline loop which controls the
- * system clock.
- *
- * When the kernel time is reckoned directly in nanoseconds (NTP_NANO
- * defined), the time at each tick interrupt is derived directly from
- * the kernel time variable. When the kernel time is reckoned in
- * microseconds, (NTP_NANO undefined), the time is derived from the
- * kernel time variable together with a variable representing the
- * leftover nanoseconds at the last tick interrupt. In either case, the
- * current nanosecond time is reckoned from these values plus an
- * interpolated value derived by the clock routines in another
- * architecture-specific module. The interpolation can use either a
- * dedicated counter or a processor cycle counter (PCC) implemented in
- * some architectures.
- *
- * Note that all routines must run at priority splclock or higher.
- */
-/*
- * Phase/frequency-lock loop (PLL/FLL) definitions
- *
- * The nanosecond clock discipline uses two variable types, time
- * variables and frequency variables. Both types are represented as 64-
- * bit fixed-point quantities with the decimal point between two 32-bit
- * halves. On a 32-bit machine, each half is represented as a single
- * word and mathematical operations are done using multiple-precision
- * arithmetic. On a 64-bit machine, ordinary computer arithmetic is
- * used.
- *
- * A time variable is a signed 64-bit fixed-point number in ns and
- * fraction. It represents the remaining time offset to be amortized
- * over succeeding tick interrupts. The maximum time offset is about
- * 0.5 s and the resolution is about 2.3e-10 ns.
- *
- * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |s s s| ns |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | fraction |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * A frequency variable is a signed 64-bit fixed-point number in ns/s
- * and fraction. It represents the ns and fraction to be added to the
- * kernel time variable at each second. The maximum frequency offset is
- * about +-500000 ns/s and the resolution is about 2.3e-10 ns/s.
- *
- * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |s s s s s s s s s s s s s| ns/s |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | fraction |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
-/*
- * The following variables establish the state of the PLL/FLL and the
- * residual time and frequency offset of the local clock.
- */
-#define SHIFT_PLL 4 /* PLL loop gain (shift) */
-#define SHIFT_FLL 2 /* FLL loop gain (shift) */
-
-static int time_state = TIME_OK; /* clock state */
-static int time_status = STA_UNSYNC; /* clock status bits */
-static long time_tai; /* TAI offset (s) */
-static long time_monitor; /* last time offset scaled (ns) */
-static long time_constant; /* poll interval (shift) (s) */
-static long time_precision = 1; /* clock precision (ns) */
-static long time_maxerror = MAXPHASE / 1000; /* maximum error (us) */
-static long time_esterror = MAXPHASE / 1000; /* estimated error (us) */
-static long time_reftime; /* time at last adjustment (s) */
-static l_fp time_offset; /* time offset (ns) */
-static l_fp time_freq; /* frequency offset (ns/s) */
-static l_fp time_adj; /* tick adjust (ns/s) */
-
-static int64_t time_adjtime; /* correction from adjtime(2) (usec) */
-
-#ifdef PPS_SYNC
-/*
- * The following variables are used when a pulse-per-second (PPS) signal
- * is available and connected via a modem control lead. They establish
- * the engineering parameters of the clock discipline loop when
- * controlled by the PPS signal.
- */
-#define PPS_FAVG 2 /* min freq avg interval (s) (shift) */
-#define PPS_FAVGDEF 8 /* default freq avg int (s) (shift) */
-#define PPS_FAVGMAX 15 /* max freq avg interval (s) (shift) */
-#define PPS_PAVG 4 /* phase avg interval (s) (shift) */
-#define PPS_VALID 120 /* PPS signal watchdog max (s) */
-#define PPS_MAXWANDER 100000 /* max PPS wander (ns/s) */
-#define PPS_POPCORN 2 /* popcorn spike threshold (shift) */
-
-static struct timespec pps_tf[3]; /* phase median filter */
-static l_fp pps_freq; /* scaled frequency offset (ns/s) */
-static long pps_fcount; /* frequency accumulator */
-static long pps_jitter; /* nominal jitter (ns) */
-static long pps_stabil; /* nominal stability (scaled ns/s) */
-static long pps_lastsec; /* time at last calibration (s) */
-static int pps_valid; /* signal watchdog counter */
-static int pps_shift = PPS_FAVG; /* interval duration (s) (shift) */
-static int pps_shiftmax = PPS_FAVGDEF; /* max interval duration (s) (shift) */
-static int pps_intcnt; /* wander counter */
-
-/*
- * PPS signal quality monitors
- */
-static long pps_calcnt; /* calibration intervals */
-static long pps_jitcnt; /* jitter limit exceeded */
-static long pps_stbcnt; /* stability limit exceeded */
-static long pps_errcnt; /* calibration errors */
-#endif /* PPS_SYNC */
-/*
- * End of phase/frequency-lock loop (PLL/FLL) definitions
- */
-
-static void ntp_init(void);
-static void hardupdate(long offset);
-static void ntp_gettime1(struct ntptimeval *ntvp);
-static int ntp_is_time_error(void);
-
-#ifndef __rtems__
-static int
-ntp_is_time_error(void)
-{
- /*
- * Status word error decode. If any of these conditions occur,
- * an error is returned, instead of the status word. Most
- * applications will care only about the fact the system clock
- * may not be trusted, not about the details.
- *
- * Hardware or software error
- */
- if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
-
- /*
- * PPS signal lost when either time or frequency synchronization
- * requested
- */
- (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
- !(time_status & STA_PPSSIGNAL)) ||
-
- /*
- * PPS jitter exceeded when time synchronization requested
- */
- (time_status & STA_PPSTIME &&
- time_status & STA_PPSJITTER) ||
-
- /*
- * PPS wander exceeded or calibration error when frequency
- * synchronization requested
- */
- (time_status & STA_PPSFREQ &&
- time_status & (STA_PPSWANDER | STA_PPSERROR)))
- return (1);
-
- return (0);
-}
-
-static void
-ntp_gettime1(struct ntptimeval *ntvp)
-{
- struct timespec atv; /* nanosecond time */
-
- GIANT_REQUIRED;
-
- nanotime(&atv);
- ntvp->time.tv_sec = atv.tv_sec;
- ntvp->time.tv_nsec = atv.tv_nsec;
- ntvp->maxerror = time_maxerror;
- ntvp->esterror = time_esterror;
- ntvp->tai = time_tai;
- ntvp->time_state = time_state;
-
- if (ntp_is_time_error())
- ntvp->time_state = TIME_ERROR;
-}
-
-/*
- * ntp_gettime() - NTP user application interface
- *
- * See the timex.h header file for synopsis and API description. Note that
- * the TAI offset is returned in the ntvtimeval.tai structure member.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct ntp_gettime_args {
- struct ntptimeval *ntvp;
-};
-#endif
-/* ARGSUSED */
-int
-ntp_gettime(struct thread *td, struct ntp_gettime_args *uap)
-{
- struct ntptimeval ntv;
-
- mtx_lock(&Giant);
- ntp_gettime1(&ntv);
- mtx_unlock(&Giant);
-
- td->td_retval[0] = ntv.time_state;
- return (copyout(&ntv, uap->ntvp, sizeof(ntv)));
-}
-
-static int
-ntp_sysctl(SYSCTL_HANDLER_ARGS)
-{
- struct ntptimeval ntv; /* temporary structure */
-
- ntp_gettime1(&ntv);
-
- return (sysctl_handle_opaque(oidp, &ntv, sizeof(ntv), req));
-}
-
-SYSCTL_NODE(_kern, OID_AUTO, ntp_pll, CTLFLAG_RW, 0, "");
-SYSCTL_PROC(_kern_ntp_pll, OID_AUTO, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD,
- 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", "");
-
-#ifdef PPS_SYNC
-SYSCTL_INT(_kern_ntp_pll, OID_AUTO, pps_shiftmax, CTLFLAG_RW, &pps_shiftmax, 0, "");
-SYSCTL_INT(_kern_ntp_pll, OID_AUTO, pps_shift, CTLFLAG_RW, &pps_shift, 0, "");
-SYSCTL_INT(_kern_ntp_pll, OID_AUTO, time_monitor, CTLFLAG_RD, &time_monitor, 0, "");
-
-SYSCTL_OPAQUE(_kern_ntp_pll, OID_AUTO, pps_freq, CTLFLAG_RD, &pps_freq, sizeof(pps_freq), "I", "");
-SYSCTL_OPAQUE(_kern_ntp_pll, OID_AUTO, time_freq, CTLFLAG_RD, &time_freq, sizeof(time_freq), "I", "");
-#endif
-
-/*
- * ntp_adjtime() - NTP daemon application interface
- *
- * See the timex.h header file for synopsis and API description. Note that
- * the timex.constant structure member has a dual purpose to set the time
- * constant and to set the TAI offset.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct ntp_adjtime_args {
- struct timex *tp;
-};
-#endif
-
-int
-ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
-{
- struct timex ntv; /* temporary structure */
- long freq; /* frequency ns/s) */
- int modes; /* mode bits from structure */
- int s; /* caller priority */
- int error;
-
- error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv));
- if (error)
- return(error);
-
- /*
- * Update selected clock variables - only the superuser can
- * change anything. Note that there is no error checking here on
- * the assumption the superuser should know what it is doing.
- * Note that either the time constant or TAI offset are loaded
- * from the ntv.constant member, depending on the mode bits. If
- * the STA_PLL bit in the status word is cleared, the state and
- * status words are reset to the initial values at boot.
- */
- mtx_lock(&Giant);
- modes = ntv.modes;
- if (modes)
- error = priv_check(td, PRIV_NTP_ADJTIME);
- if (error)
- goto done2;
- s = splclock();
- if (modes & MOD_MAXERROR)
- time_maxerror = ntv.maxerror;
- if (modes & MOD_ESTERROR)
- time_esterror = ntv.esterror;
- if (modes & MOD_STATUS) {
- if (time_status & STA_PLL && !(ntv.status & STA_PLL)) {
- time_state = TIME_OK;
- time_status = STA_UNSYNC;
-#ifdef PPS_SYNC
- pps_shift = PPS_FAVG;
-#endif /* PPS_SYNC */
- }
- time_status &= STA_RONLY;
- time_status |= ntv.status & ~STA_RONLY;
- }
- if (modes & MOD_TIMECONST) {
- if (ntv.constant < 0)
- time_constant = 0;
- else if (ntv.constant > MAXTC)
- time_constant = MAXTC;
- else
- time_constant = ntv.constant;
- }
- if (modes & MOD_TAI) {
- if (ntv.constant > 0) /* XXX zero & negative numbers ? */
- time_tai = ntv.constant;
- }
-#ifdef PPS_SYNC
- if (modes & MOD_PPSMAX) {
- if (ntv.shift < PPS_FAVG)
- pps_shiftmax = PPS_FAVG;
- else if (ntv.shift > PPS_FAVGMAX)
- pps_shiftmax = PPS_FAVGMAX;
- else
- pps_shiftmax = ntv.shift;
- }
-#endif /* PPS_SYNC */
- if (modes & MOD_NANO)
- time_status |= STA_NANO;
- if (modes & MOD_MICRO)
- time_status &= ~STA_NANO;
- if (modes & MOD_CLKB)
- time_status |= STA_CLK;
- if (modes & MOD_CLKA)
- time_status &= ~STA_CLK;
- if (modes & MOD_FREQUENCY) {
- freq = (ntv.freq * 1000LL) >> 16;
- if (freq > MAXFREQ)
- L_LINT(time_freq, MAXFREQ);
- else if (freq < -MAXFREQ)
- L_LINT(time_freq, -MAXFREQ);
- else {
- /*
- * ntv.freq is [PPM * 2^16] = [us/s * 2^16]
- * time_freq is [ns/s * 2^32]
- */
- time_freq = ntv.freq * 1000LL * 65536LL;
- }
-#ifdef PPS_SYNC
- pps_freq = time_freq;
-#endif /* PPS_SYNC */
- }
- if (modes & MOD_OFFSET) {
- if (time_status & STA_NANO)
- hardupdate(ntv.offset);
- else
- hardupdate(ntv.offset * 1000);
- }
-
- /*
- * Retrieve all clock variables. Note that the TAI offset is
- * returned only by ntp_gettime();
- */
- if (time_status & STA_NANO)
- ntv.offset = L_GINT(time_offset);
- else
- ntv.offset = L_GINT(time_offset) / 1000; /* XXX rounding ? */
- ntv.freq = L_GINT((time_freq / 1000LL) << 16);
- ntv.maxerror = time_maxerror;
- ntv.esterror = time_esterror;
- ntv.status = time_status;
- ntv.constant = time_constant;
- if (time_status & STA_NANO)
- ntv.precision = time_precision;
- else
- ntv.precision = time_precision / 1000;
- ntv.tolerance = MAXFREQ * SCALE_PPM;
-#ifdef PPS_SYNC
- ntv.shift = pps_shift;
- ntv.ppsfreq = L_GINT((pps_freq / 1000LL) << 16);
- if (time_status & STA_NANO)
- ntv.jitter = pps_jitter;
- else
- ntv.jitter = pps_jitter / 1000;
- ntv.stabil = pps_stabil;
- ntv.calcnt = pps_calcnt;
- ntv.errcnt = pps_errcnt;
- ntv.jitcnt = pps_jitcnt;
- ntv.stbcnt = pps_stbcnt;
-#endif /* PPS_SYNC */
- splx(s);
-
- error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv));
- if (error)
- goto done2;
-
- if (ntp_is_time_error())
- td->td_retval[0] = TIME_ERROR;
- else
- td->td_retval[0] = time_state;
-
-done2:
- mtx_unlock(&Giant);
- return (error);
-}
-#endif /* __rtems__ */
-
-/*
- * second_overflow() - called after ntp_tick_adjust()
- *
- * This routine is ordinarily called immediately following the above
- * routine ntp_tick_adjust(). While these two routines are normally
- * combined, they are separated here only for the purposes of
- * simulation.
- */
-void
-ntp_update_second(int64_t *adjustment, time_t *newsec)
-{
- int tickrate;
- l_fp ftemp; /* 32/64-bit temporary */
-
- /*
- * On rollover of the second both the nanosecond and microsecond
- * clocks are updated and the state machine cranked as
- * necessary. The phase adjustment to be used for the next
- * second is calculated and the maximum error is increased by
- * the tolerance.
- */
- time_maxerror += MAXFREQ / 1000;
-
- /*
- * Leap second processing. If in leap-insert state at
- * the end of the day, the system clock is set back one
- * second; if in leap-delete state, the system clock is
- * set ahead one second. The nano_time() routine or
- * external clock driver will insure that reported time
- * is always monotonic.
- */
- switch (time_state) {
-
- /*
- * No warning.
- */
- case TIME_OK:
- if (time_status & STA_INS)
- time_state = TIME_INS;
- else if (time_status & STA_DEL)
- time_state = TIME_DEL;
- break;
-
- /*
- * Insert second 23:59:60 following second
- * 23:59:59.
- */
- case TIME_INS:
- if (!(time_status & STA_INS))
- time_state = TIME_OK;
- else if ((*newsec) % 86400 == 0) {
- (*newsec)--;
- time_state = TIME_OOP;
- time_tai++;
- }
- break;
-
- /*
- * Delete second 23:59:59.
- */
- case TIME_DEL:
- if (!(time_status & STA_DEL))
- time_state = TIME_OK;
- else if (((*newsec) + 1) % 86400 == 0) {
- (*newsec)++;
- time_tai--;
- time_state = TIME_WAIT;
- }
- break;
-
- /*
- * Insert second in progress.
- */
- case TIME_OOP:
- time_state = TIME_WAIT;
- break;
-
- /*
- * Wait for status bits to clear.
- */
- case TIME_WAIT:
- if (!(time_status & (STA_INS | STA_DEL)))
- time_state = TIME_OK;
- }
-
- /*
- * Compute the total time adjustment for the next second
- * in ns. The offset is reduced by a factor depending on
- * whether the PPS signal is operating. Note that the
- * value is in effect scaled by the clock frequency,
- * since the adjustment is added at each tick interrupt.
- */
- ftemp = time_offset;
-#ifdef PPS_SYNC
- /* XXX even if PPS signal dies we should finish adjustment ? */
- if (time_status & STA_PPSTIME && time_status &
- STA_PPSSIGNAL)
- L_RSHIFT(ftemp, pps_shift);
- else
- L_RSHIFT(ftemp, SHIFT_PLL + time_constant);
-#else
- L_RSHIFT(ftemp, SHIFT_PLL + time_constant);
-#endif /* PPS_SYNC */
- time_adj = ftemp;
- L_SUB(time_offset, ftemp);
- L_ADD(time_adj, time_freq);
-
- /*
- * Apply any correction from adjtime(2). If more than one second
- * off we slew at a rate of 5ms/s (5000 PPM) else 500us/s (500PPM)
- * until the last second is slewed the final < 500 usecs.
- */
- if (time_adjtime != 0) {
- if (time_adjtime > 1000000)
- tickrate = 5000;
- else if (time_adjtime < -1000000)
- tickrate = -5000;
- else if (time_adjtime > 500)
- tickrate = 500;
- else if (time_adjtime < -500)
- tickrate = -500;
- else
- tickrate = time_adjtime;
- time_adjtime -= tickrate;
- L_LINT(ftemp, tickrate * 1000);
- L_ADD(time_adj, ftemp);
- }
- *adjustment = time_adj;
-
-#ifdef PPS_SYNC
- if (pps_valid > 0)
- pps_valid--;
- else
- time_status &= ~STA_PPSSIGNAL;
-#endif /* PPS_SYNC */
-}
-
-#ifndef __rtems__
-/*
- * ntp_init() - initialize variables and structures
- *
- * This routine must be called after the kernel variables hz and tick
- * are set or changed and before the next tick interrupt. In this
- * particular implementation, these values are assumed set elsewhere in
- * the kernel. The design allows the clock frequency and tick interval
- * to be changed while the system is running. So, this routine should
- * probably be integrated with the code that does that.
- */
-static void
-ntp_init()
-{
-
- /*
- * The following variables are initialized only at startup. Only
- * those structures not cleared by the compiler need to be
- * initialized, and these only in the simulator. In the actual
- * kernel, any nonzero values here will quickly evaporate.
- */
- L_CLR(time_offset);
- L_CLR(time_freq);
-#ifdef PPS_SYNC
- pps_tf[0].tv_sec = pps_tf[0].tv_nsec = 0;
- pps_tf[1].tv_sec = pps_tf[1].tv_nsec = 0;
- pps_tf[2].tv_sec = pps_tf[2].tv_nsec = 0;
- pps_fcount = 0;
- L_CLR(pps_freq);
-#endif /* PPS_SYNC */
-}
-
-SYSINIT(ntpclocks, SI_SUB_CLOCKS, SI_ORDER_MIDDLE, ntp_init, NULL);
-
-/*
- * hardupdate() - local clock update
- *
- * This routine is called by ntp_adjtime() to update the local clock
- * phase and frequency. The implementation is of an adaptive-parameter,
- * hybrid phase/frequency-lock loop (PLL/FLL). The routine computes new
- * time and frequency offset estimates for each call. If the kernel PPS
- * discipline code is configured (PPS_SYNC), the PPS signal itself
- * determines the new time offset, instead of the calling argument.
- * Presumably, calls to ntp_adjtime() occur only when the caller
- * believes the local clock is valid within some bound (+-128 ms with
- * NTP). If the caller's time is far different than the PPS time, an
- * argument will ensue, and it's not clear who will lose.
- *
- * For uncompensated quartz crystal oscillators and nominal update
- * intervals less than 256 s, operation should be in phase-lock mode,
- * where the loop is disciplined to phase. For update intervals greater
- * than 1024 s, operation should be in frequency-lock mode, where the
- * loop is disciplined to frequency. Between 256 s and 1024 s, the mode
- * is selected by the STA_MODE status bit.
- */
-static void
-hardupdate(offset)
- long offset; /* clock offset (ns) */
-{
- long mtemp;
- l_fp ftemp;
-
- /*
- * Select how the phase is to be controlled and from which
- * source. If the PPS signal is present and enabled to
- * discipline the time, the PPS offset is used; otherwise, the
- * argument offset is used.
- */
- if (!(time_status & STA_PLL))
- return;
- if (!(time_status & STA_PPSTIME && time_status &
- STA_PPSSIGNAL)) {
- if (offset > MAXPHASE)
- time_monitor = MAXPHASE;
- else if (offset < -MAXPHASE)
- time_monitor = -MAXPHASE;
- else
- time_monitor = offset;
- L_LINT(time_offset, time_monitor);
- }
-
- /*
- * Select how the frequency is to be controlled and in which
- * mode (PLL or FLL). If the PPS signal is present and enabled
- * to discipline the frequency, the PPS frequency is used;
- * otherwise, the argument offset is used to compute it.
- */
- if (time_status & STA_PPSFREQ && time_status & STA_PPSSIGNAL) {
- time_reftime = time_second;
- return;
- }
- if (time_status & STA_FREQHOLD || time_reftime == 0)
- time_reftime = time_second;
- mtemp = time_second - time_reftime;
- L_LINT(ftemp, time_monitor);
- L_RSHIFT(ftemp, (SHIFT_PLL + 2 + time_constant) << 1);
- L_MPY(ftemp, mtemp);
- L_ADD(time_freq, ftemp);
- time_status &= ~STA_MODE;
- if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp >
- MAXSEC)) {
- L_LINT(ftemp, (time_monitor << 4) / mtemp);
- L_RSHIFT(ftemp, SHIFT_FLL + 4);
- L_ADD(time_freq, ftemp);
- time_status |= STA_MODE;
- }
- time_reftime = time_second;
- if (L_GINT(time_freq) > MAXFREQ)
- L_LINT(time_freq, MAXFREQ);
- else if (L_GINT(time_freq) < -MAXFREQ)
- L_LINT(time_freq, -MAXFREQ);
-}
-
-#ifdef PPS_SYNC
-/*
- * hardpps() - discipline CPU clock oscillator to external PPS signal
- *
- * This routine is called at each PPS interrupt in order to discipline
- * the CPU clock oscillator to the PPS signal. There are two independent
- * first-order feedback loops, one for the phase, the other for the
- * frequency. The phase loop measures and grooms the PPS phase offset
- * and leaves it in a handy spot for the seconds overflow routine. The
- * frequency loop averages successive PPS phase differences and
- * calculates the PPS frequency offset, which is also processed by the
- * seconds overflow routine. The code requires the caller to capture the
- * time and architecture-dependent hardware counter values in
- * nanoseconds at the on-time PPS signal transition.
- *
- * Note that, on some Unix systems this routine runs at an interrupt
- * priority level higher than the timer interrupt routine hardclock().
- * Therefore, the variables used are distinct from the hardclock()
- * variables, except for the actual time and frequency variables, which
- * are determined by this routine and updated atomically.
- */
-void
-hardpps(tsp, nsec)
- struct timespec *tsp; /* time at PPS */
- long nsec; /* hardware counter at PPS */
-{
- long u_sec, u_nsec, v_nsec; /* temps */
- l_fp ftemp;
-
- /*
- * The signal is first processed by a range gate and frequency
- * discriminator. The range gate rejects noise spikes outside
- * the range +-500 us. The frequency discriminator rejects input
- * signals with apparent frequency outside the range 1 +-500
- * PPM. If two hits occur in the same second, we ignore the
- * later hit; if not and a hit occurs outside the range gate,
- * keep the later hit for later comparison, but do not process
- * it.
- */
- time_status |= STA_PPSSIGNAL | STA_PPSJITTER;
- time_status &= ~(STA_PPSWANDER | STA_PPSERROR);
- pps_valid = PPS_VALID;
- u_sec = tsp->tv_sec;
- u_nsec = tsp->tv_nsec;
- if (u_nsec >= (NANOSECOND >> 1)) {
- u_nsec -= NANOSECOND;
- u_sec++;
- }
- v_nsec = u_nsec - pps_tf[0].tv_nsec;
- if (u_sec == pps_tf[0].tv_sec && v_nsec < NANOSECOND -
- MAXFREQ)
- return;
- pps_tf[2] = pps_tf[1];
- pps_tf[1] = pps_tf[0];
- pps_tf[0].tv_sec = u_sec;
- pps_tf[0].tv_nsec = u_nsec;
-
- /*
- * Compute the difference between the current and previous
- * counter values. If the difference exceeds 0.5 s, assume it
- * has wrapped around, so correct 1.0 s. If the result exceeds
- * the tick interval, the sample point has crossed a tick
- * boundary during the last second, so correct the tick. Very
- * intricate.
- */
- u_nsec = nsec;
- if (u_nsec > (NANOSECOND >> 1))
- u_nsec -= NANOSECOND;
- else if (u_nsec < -(NANOSECOND >> 1))
- u_nsec += NANOSECOND;
- pps_fcount += u_nsec;
- if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ)
- return;
- time_status &= ~STA_PPSJITTER;
-
- /*
- * A three-stage median filter is used to help denoise the PPS
- * time. The median sample becomes the time offset estimate; the
- * difference between the other two samples becomes the time
- * dispersion (jitter) estimate.
- */
- if (pps_tf[0].tv_nsec > pps_tf[1].tv_nsec) {
- if (pps_tf[1].tv_nsec > pps_tf[2].tv_nsec) {
- v_nsec = pps_tf[1].tv_nsec; /* 0 1 2 */
- u_nsec = pps_tf[0].tv_nsec - pps_tf[2].tv_nsec;
- } else if (pps_tf[2].tv_nsec > pps_tf[0].tv_nsec) {
- v_nsec = pps_tf[0].tv_nsec; /* 2 0 1 */
- u_nsec = pps_tf[2].tv_nsec - pps_tf[1].tv_nsec;
- } else {
- v_nsec = pps_tf[2].tv_nsec; /* 0 2 1 */
- u_nsec = pps_tf[0].tv_nsec - pps_tf[1].tv_nsec;
- }
- } else {
- if (pps_tf[1].tv_nsec < pps_tf[2].tv_nsec) {
- v_nsec = pps_tf[1].tv_nsec; /* 2 1 0 */
- u_nsec = pps_tf[2].tv_nsec - pps_tf[0].tv_nsec;
- } else if (pps_tf[2].tv_nsec < pps_tf[0].tv_nsec) {
- v_nsec = pps_tf[0].tv_nsec; /* 1 0 2 */
- u_nsec = pps_tf[1].tv_nsec - pps_tf[2].tv_nsec;
- } else {
- v_nsec = pps_tf[2].tv_nsec; /* 1 2 0 */
- u_nsec = pps_tf[1].tv_nsec - pps_tf[0].tv_nsec;
- }
- }
-
- /*
- * Nominal jitter is due to PPS signal noise and interrupt
- * latency. If it exceeds the popcorn threshold, the sample is
- * discarded. otherwise, if so enabled, the time offset is
- * updated. We can tolerate a modest loss of data here without
- * much degrading time accuracy.
- */
- if (u_nsec > (pps_jitter << PPS_POPCORN)) {
- time_status |= STA_PPSJITTER;
- pps_jitcnt++;
- } else if (time_status & STA_PPSTIME) {
- time_monitor = -v_nsec;
- L_LINT(time_offset, time_monitor);
- }
- pps_jitter += (u_nsec - pps_jitter) >> PPS_FAVG;
- u_sec = pps_tf[0].tv_sec - pps_lastsec;
- if (u_sec < (1 << pps_shift))
- return;
-
- /*
- * At the end of the calibration interval the difference between
- * the first and last counter values becomes the scaled
- * frequency. It will later be divided by the length of the
- * interval to determine the frequency update. If the frequency
- * exceeds a sanity threshold, or if the actual calibration
- * interval is not equal to the expected length, the data are
- * discarded. We can tolerate a modest loss of data here without
- * much degrading frequency accuracy.
- */
- pps_calcnt++;
- v_nsec = -pps_fcount;
- pps_lastsec = pps_tf[0].tv_sec;
- pps_fcount = 0;
- u_nsec = MAXFREQ << pps_shift;
- if (v_nsec > u_nsec || v_nsec < -u_nsec || u_sec != (1 <<
- pps_shift)) {
- time_status |= STA_PPSERROR;
- pps_errcnt++;
- return;
- }
-
- /*
- * Here the raw frequency offset and wander (stability) is
- * calculated. If the wander is less than the wander threshold
- * for four consecutive averaging intervals, the interval is
- * doubled; if it is greater than the threshold for four
- * consecutive intervals, the interval is halved. The scaled
- * frequency offset is converted to frequency offset. The
- * stability metric is calculated as the average of recent
- * frequency changes, but is used only for performance
- * monitoring.
- */
- L_LINT(ftemp, v_nsec);
- L_RSHIFT(ftemp, pps_shift);
- L_SUB(ftemp, pps_freq);
- u_nsec = L_GINT(ftemp);
- if (u_nsec > PPS_MAXWANDER) {
- L_LINT(ftemp, PPS_MAXWANDER);
- pps_intcnt--;
- time_status |= STA_PPSWANDER;
- pps_stbcnt++;
- } else if (u_nsec < -PPS_MAXWANDER) {
- L_LINT(ftemp, -PPS_MAXWANDER);
- pps_intcnt--;
- time_status |= STA_PPSWANDER;
- pps_stbcnt++;
- } else {
- pps_intcnt++;
- }
- if (pps_intcnt >= 4) {
- pps_intcnt = 4;
- if (pps_shift < pps_shiftmax) {
- pps_shift++;
- pps_intcnt = 0;
- }
- } else if (pps_intcnt <= -4 || pps_shift > pps_shiftmax) {
- pps_intcnt = -4;
- if (pps_shift > PPS_FAVG) {
- pps_shift--;
- pps_intcnt = 0;
- }
- }
- if (u_nsec < 0)
- u_nsec = -u_nsec;
- pps_stabil += (u_nsec * SCALE_PPM - pps_stabil) >> PPS_FAVG;
-
- /*
- * The PPS frequency is recalculated and clamped to the maximum
- * MAXFREQ. If enabled, the system clock frequency is updated as
- * well.
- */
- L_ADD(pps_freq, ftemp);
- u_nsec = L_GINT(pps_freq);
- if (u_nsec > MAXFREQ)
- L_LINT(pps_freq, MAXFREQ);
- else if (u_nsec < -MAXFREQ)
- L_LINT(pps_freq, -MAXFREQ);
- if (time_status & STA_PPSFREQ)
- time_freq = pps_freq;
-}
-#endif /* PPS_SYNC */
-
-#ifndef _SYS_SYSPROTO_H_
-struct adjtime_args {
- struct timeval *delta;
- struct timeval *olddelta;
-};
-#endif
-/* ARGSUSED */
-int
-adjtime(struct thread *td, struct adjtime_args *uap)
-{
- struct timeval delta, olddelta, *deltap;
- int error;
-
- if (uap->delta) {
- error = copyin(uap->delta, &delta, sizeof(delta));
- if (error)
- return (error);
- deltap = &delta;
- } else
- deltap = NULL;
- error = kern_adjtime(td, deltap, &olddelta);
- if (uap->olddelta && error == 0)
- error = copyout(&olddelta, uap->olddelta, sizeof(olddelta));
- return (error);
-}
-
-int
-kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta)
-{
- struct timeval atv;
- int error;
-
- mtx_lock(&Giant);
- if (olddelta) {
- atv.tv_sec = time_adjtime / 1000000;
- atv.tv_usec = time_adjtime % 1000000;
- if (atv.tv_usec < 0) {
- atv.tv_usec += 1000000;
- atv.tv_sec--;
- }
- *olddelta = atv;
- }
- if (delta) {
- if ((error = priv_check(td, PRIV_ADJTIME))) {
- mtx_unlock(&Giant);
- return (error);
- }
- time_adjtime = (int64_t)delta->tv_sec * 1000000 +
- delta->tv_usec;
- }
- mtx_unlock(&Giant);
- return (0);
-}
-
-static struct callout resettodr_callout;
-static int resettodr_period = 1800;
-
-static void
-periodic_resettodr(void *arg __unused)
-{
-
- if (!ntp_is_time_error()) {
- mtx_lock(&Giant);
- resettodr();
- mtx_unlock(&Giant);
- }
- if (resettodr_period > 0)
- callout_schedule(&resettodr_callout, resettodr_period * hz);
-}
-
-static void
-shutdown_resettodr(void *arg __unused, int howto __unused)
-{
-
- callout_drain(&resettodr_callout);
- if (resettodr_period > 0 && !ntp_is_time_error()) {
- mtx_lock(&Giant);
- resettodr();
- mtx_unlock(&Giant);
- }
-}
-
-static int
-sysctl_resettodr_period(SYSCTL_HANDLER_ARGS)
-{
- int error;
-
- error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
- if (error || !req->newptr)
- return (error);
- if (resettodr_period == 0)
- callout_stop(&resettodr_callout);
- else
- callout_reset(&resettodr_callout, resettodr_period * hz,
- periodic_resettodr, NULL);
- return (0);
-}
-
-SYSCTL_PROC(_machdep, OID_AUTO, rtc_save_period, CTLTYPE_INT|CTLFLAG_RW,
- &resettodr_period, 1800, sysctl_resettodr_period, "I",
- "Save system time to RTC with this period (in seconds)");
-TUNABLE_INT("machdep.rtc_save_period", &resettodr_period);
-
-static void
-start_periodic_resettodr(void *arg __unused)
-{
-
- EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_resettodr, NULL,
- SHUTDOWN_PRI_FIRST);
- callout_init(&resettodr_callout, 1);
- if (resettodr_period == 0)
- return;
- callout_reset(&resettodr_callout, resettodr_period * hz,
- periodic_resettodr, NULL);
-}
-
-SYSINIT(periodic_resettodr, SI_SUB_RUN_SCHEDULER, SI_ORDER_MIDDLE,
- start_periodic_resettodr, NULL);
-#endif /* __rtems__ */
diff --git a/freebsd/sys/kern/kern_tc.c b/freebsd/sys/kern/kern_tc.c
deleted file mode 100644
index effbe4c5..00000000
--- a/freebsd/sys/kern/kern_tc.c
+++ /dev/null
@@ -1,968 +0,0 @@
-#include <machine/rtems-bsd-config.h>
-
-/*-
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
- * can do whatever you want with this stuff. If we meet some day, and you think
- * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
- * ----------------------------------------------------------------------------
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <rtems/bsd/local/opt_ntp.h>
-
-#include <rtems/bsd/sys/param.h>
-#include <sys/kernel.h>
-#include <sys/sysctl.h>
-#include <sys/syslog.h>
-#include <sys/systm.h>
-#include <sys/timepps.h>
-#include <sys/timetc.h>
-#include <sys/timex.h>
-
-/*
- * A large step happens on boot. This constant detects such steps.
- * It is relatively small so that ntp_update_second gets called enough
- * in the typical 'missed a couple of seconds' case, but doesn't loop
- * forever when the time step is large.
- */
-#define LARGE_STEP 200
-
-/*
- * Implement a dummy timecounter which we can use until we get a real one
- * in the air. This allows the console and other early stuff to use
- * time services.
- */
-
-static u_int
-dummy_get_timecount(struct timecounter *tc)
-{
- static u_int now;
-
- return (++now);
-}
-
-static struct timecounter dummy_timecounter = {
- dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000
-};
-
-struct timehands {
- /* These fields must be initialized by the driver. */
- struct timecounter *th_counter;
- int64_t th_adjustment;
- u_int64_t th_scale;
- u_int th_offset_count;
- struct bintime th_offset;
- struct timeval th_microtime;
- struct timespec th_nanotime;
- /* Fields not to be copied in tc_windup start with th_generation. */
- volatile u_int th_generation;
- struct timehands *th_next;
-};
-
-static struct timehands th0;
-static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0};
-static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9};
-static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th8};
-static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th7};
-static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th6};
-static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5};
-static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4};
-static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3};
-static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2};
-static struct timehands th0 = {
- &dummy_timecounter,
- 0,
- (uint64_t)-1 / 1000000,
- 0,
- {1, 0},
- {0, 0},
- {0, 0},
- 1,
- &th1
-};
-
-static struct timehands *volatile timehands = &th0;
-struct timecounter *timecounter = &dummy_timecounter;
-static struct timecounter *timecounters = &dummy_timecounter;
-
-time_t time_second = 1;
-time_t time_uptime = 1;
-
-static struct bintime boottimebin;
-struct timeval boottime;
-static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS);
-SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD,
- NULL, 0, sysctl_kern_boottime, "S,timeval", "System boottime");
-
-SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
-SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc, CTLFLAG_RW, 0, "");
-
-static int timestepwarnings;
-SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RW,
- &timestepwarnings, 0, "Log time steps");
-
-static void tc_windup(void);
-static void cpu_tick_calibrate(int);
-
-static int
-sysctl_kern_boottime(SYSCTL_HANDLER_ARGS)
-{
-#ifdef SCTL_MASK32
- int tv[2];
-
- if (req->flags & SCTL_MASK32) {
- tv[0] = boottime.tv_sec;
- tv[1] = boottime.tv_usec;
- return SYSCTL_OUT(req, tv, sizeof(tv));
- } else
-#endif
- return SYSCTL_OUT(req, &boottime, sizeof(boottime));
-}
-
-static int
-sysctl_kern_timecounter_get(SYSCTL_HANDLER_ARGS)
-{
- u_int ncount;
- struct timecounter *tc = arg1;
-
- ncount = tc->tc_get_timecount(tc);
- return sysctl_handle_int(oidp, &ncount, 0, req);
-}
-
-static int
-sysctl_kern_timecounter_freq(SYSCTL_HANDLER_ARGS)
-{
- u_int64_t freq;
- struct timecounter *tc = arg1;
-
- freq = tc->tc_frequency;
- return sysctl_handle_quad(oidp, &freq, 0, req);
-}
-
-/*
- * Return the difference between the timehands' counter value now and what
- * was when we copied it to the timehands' offset_count.
- */
-static __inline u_int
-tc_delta(struct timehands *th)
-{
- struct timecounter *tc;
-
- tc = th->th_counter;
- return ((tc->tc_get_timecount(tc) - th->th_offset_count) &
- tc->tc_counter_mask);
-}
-
-/*
- * Functions for reading the time. We have to loop until we are sure that
- * the timehands that we operated on was not updated under our feet. See
- * the comment in <sys/time.h> for a description of these 12 functions.
- */
-
-void
-binuptime(struct bintime *bt)
-{
- struct timehands *th;
- u_int gen;
-
- do {
- th = timehands;
- gen = th->th_generation;
- *bt = th->th_offset;
- bintime_addx(bt, th->th_scale * tc_delta(th));
- } while (gen == 0 || gen != th->th_generation);
-}
-
-void
-nanouptime(struct timespec *tsp)
-{
- struct bintime bt;
-
- binuptime(&bt);
- bintime2timespec(&bt, tsp);
-}
-
-void
-microuptime(struct timeval *tvp)
-{
- struct bintime bt;
-
- binuptime(&bt);
- bintime2timeval(&bt, tvp);
-}
-
-void
-bintime(struct bintime *bt)
-{
-
- binuptime(bt);
- bintime_add(bt, &boottimebin);
-}
-
-void
-nanotime(struct timespec *tsp)
-{
- struct bintime bt;
-
- bintime(&bt);
- bintime2timespec(&bt, tsp);
-}
-
-void
-microtime(struct timeval *tvp)
-{
- struct bintime bt;
-
- bintime(&bt);
- bintime2timeval(&bt, tvp);
-}
-
-void
-getbinuptime(struct bintime *bt)
-{
- struct timehands *th;
- u_int gen;
-
- do {
- th = timehands;
- gen = th->th_generation;
- *bt = th->th_offset;
- } while (gen == 0 || gen != th->th_generation);
-}
-
-void
-getnanouptime(struct timespec *tsp)
-{
- struct timehands *th;
- u_int gen;
-
- do {
- th = timehands;
- gen = th->th_generation;
- bintime2timespec(&th->th_offset, tsp);
- } while (gen == 0 || gen != th->th_generation);
-}
-
-void
-getmicrouptime(struct timeval *tvp)
-{
- struct timehands *th;
- u_int gen;
-
- do {
- th = timehands;
- gen = th->th_generation;
- bintime2timeval(&th->th_offset, tvp);
- } while (gen == 0 || gen != th->th_generation);
-}
-
-void
-getbintime(struct bintime *bt)
-{
- struct timehands *th;
- u_int gen;
-
- do {
- th = timehands;
- gen = th->th_generation;
- *bt = th->th_offset;
- } while (gen == 0 || gen != th->th_generation);
- bintime_add(bt, &boottimebin);
-}
-
-void
-getnanotime(struct timespec *tsp)
-{
- struct timehands *th;
- u_int gen;
-
- do {
- th = timehands;
- gen = th->th_generation;
- *tsp = th->th_nanotime;
- } while (gen == 0 || gen != th->th_generation);
-}
-
-void
-getmicrotime(struct timeval *tvp)
-{
- struct timehands *th;
- u_int gen;
-
- do {
- th = timehands;
- gen = th->th_generation;
- *tvp = th->th_microtime;
- } while (gen == 0 || gen != th->th_generation);
-}
-
-/*
- * Initialize a new timecounter and possibly use it.
- */
-void
-tc_init(struct timecounter *tc)
-{
- u_int u;
- struct sysctl_oid *tc_root;
-
- u = tc->tc_frequency / tc->tc_counter_mask;
- /* XXX: We need some margin here, 10% is a guess */
- u *= 11;
- u /= 10;
- if (u > hz && tc->tc_quality >= 0) {
- tc->tc_quality = -2000;
- if (bootverbose) {
- printf("Timecounter \"%s\" frequency %ju Hz",
- tc->tc_name, (uintmax_t)tc->tc_frequency);
- printf(" -- Insufficient hz, needs at least %u\n", u);
- }
- } else if (tc->tc_quality >= 0 || bootverbose) {
- printf("Timecounter \"%s\" frequency %ju Hz quality %d\n",
- tc->tc_name, (uintmax_t)tc->tc_frequency,
- tc->tc_quality);
- }
-
- tc->tc_next = timecounters;
- timecounters = tc;
- /*
- * Set up sysctl tree for this counter.
- */
- tc_root = SYSCTL_ADD_NODE(NULL,
- SYSCTL_STATIC_CHILDREN(_kern_timecounter_tc), OID_AUTO, tc->tc_name,
- CTLFLAG_RW, 0, "timecounter description");
- SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "mask", CTLFLAG_RD, &(tc->tc_counter_mask), 0,
- "mask for implemented bits");
- SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "counter", CTLTYPE_UINT | CTLFLAG_RD, tc, sizeof(*tc),
- sysctl_kern_timecounter_get, "IU", "current timecounter value");
- SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "frequency", CTLTYPE_QUAD | CTLFLAG_RD, tc, sizeof(*tc),
- sysctl_kern_timecounter_freq, "QU", "timecounter frequency");
- SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO,
- "quality", CTLFLAG_RD, &(tc->tc_quality), 0,
- "goodness of time counter");
- /*
- * Never automatically use a timecounter with negative quality.
- * Even though we run on the dummy counter, switching here may be
- * worse since this timecounter may not be monotonous.
- */
- if (tc->tc_quality < 0)
- return;
- if (tc->tc_quality < timecounter->tc_quality)
- return;
- if (tc->tc_quality == timecounter->tc_quality &&
- tc->tc_frequency < timecounter->tc_frequency)
- return;
- (void)tc->tc_get_timecount(tc);
- (void)tc->tc_get_timecount(tc);
- timecounter = tc;
-}
-
-/* Report the frequency of the current timecounter. */
-u_int64_t
-tc_getfrequency(void)
-{
-
- return (timehands->th_counter->tc_frequency);
-}
-
-/*
- * Step our concept of UTC. This is done by modifying our estimate of
- * when we booted.
- * XXX: not locked.
- */
-void
-tc_setclock(struct timespec *ts)
-{
- struct timespec tbef, taft;
- struct bintime bt, bt2;
-
- cpu_tick_calibrate(1);
- nanotime(&tbef);
- timespec2bintime(ts, &bt);
- binuptime(&bt2);
- bintime_sub(&bt, &bt2);
- bintime_add(&bt2, &boottimebin);
- boottimebin = bt;
- bintime2timeval(&bt, &boottime);
-
- /* XXX fiddle all the little crinkly bits around the fiords... */
- tc_windup();
- nanotime(&taft);
- if (timestepwarnings) {
- log(LOG_INFO,
- "Time stepped from %jd.%09ld to %jd.%09ld (%jd.%09ld)\n",
- (intmax_t)tbef.tv_sec, tbef.tv_nsec,
- (intmax_t)taft.tv_sec, taft.tv_nsec,
- (intmax_t)ts->tv_sec, ts->tv_nsec);
- }
- cpu_tick_calibrate(1);
-}
-
-/*
- * Initialize the next struct timehands in the ring and make
- * it the active timehands. Along the way we might switch to a different
- * timecounter and/or do seconds processing in NTP. Slightly magic.
- */
-static void
-tc_windup(void)
-{
- struct bintime bt;
- struct timehands *th, *tho;
- u_int64_t scale;
- u_int delta, ncount, ogen;
- int i;
- time_t t;
-
- /*
- * Make the next timehands a copy of the current one, but do not
- * overwrite the generation or next pointer. While we update
- * the contents, the generation must be zero.
- */
- tho = timehands;
- th = tho->th_next;
- ogen = th->th_generation;
- th->th_generation = 0;
- bcopy(tho, th, offsetof(struct timehands, th_generation));
-
- /*
- * Capture a timecounter delta on the current timecounter and if
- * changing timecounters, a counter value from the new timecounter.
- * Update the offset fields accordingly.
- */
- delta = tc_delta(th);
- if (th->th_counter != timecounter)
- ncount = timecounter->tc_get_timecount(timecounter);
- else
- ncount = 0;
- th->th_offset_count += delta;
- th->th_offset_count &= th->th_counter->tc_counter_mask;
- while (delta > th->th_counter->tc_frequency) {
- /* Eat complete unadjusted seconds. */
- delta -= th->th_counter->tc_frequency;
- th->th_offset.sec++;
- }
- if ((delta > th->th_counter->tc_frequency / 2) &&
- (th->th_scale * delta < ((uint64_t)1 << 63))) {
- /* The product th_scale * delta just barely overflows. */
- th->th_offset.sec++;
- }
- bintime_addx(&th->th_offset, th->th_scale * delta);
-
- /*
- * Hardware latching timecounters may not generate interrupts on
- * PPS events, so instead we poll them. There is a finite risk that
- * the hardware might capture a count which is later than the one we
- * got above, and therefore possibly in the next NTP second which might
- * have a different rate than the current NTP second. It doesn't
- * matter in practice.
- */
- if (tho->th_counter->tc_poll_pps)
- tho->th_counter->tc_poll_pps(tho->th_counter);
-
- /*
- * Deal with NTP second processing. The for loop normally
- * iterates at most once, but in extreme situations it might
- * keep NTP sane if timeouts are not run for several seconds.
- * At boot, the time step can be large when the TOD hardware
- * has been read, so on really large steps, we call
- * ntp_update_second only twice. We need to call it twice in
- * case we missed a leap second.
- */
- bt = th->th_offset;
- bintime_add(&bt, &boottimebin);
- i = bt.sec - tho->th_microtime.tv_sec;
- if (i > LARGE_STEP)
- i = 2;
- for (; i > 0; i--) {
- t = bt.sec;
- ntp_update_second(&th->th_adjustment, &bt.sec);
- if (bt.sec != t)
- boottimebin.sec += bt.sec - t;
- }
- /* Update the UTC timestamps used by the get*() functions. */
- /* XXX shouldn't do this here. Should force non-`get' versions. */
- bintime2timeval(&bt, &th->th_microtime);
- bintime2timespec(&bt, &th->th_nanotime);
-
- /* Now is a good time to change timecounters. */
- if (th->th_counter != timecounter) {
- th->th_counter = timecounter;
- th->th_offset_count = ncount;
- }
-
- /*-
- * Recalculate the scaling factor. We want the number of 1/2^64
- * fractions of a second per period of the hardware counter, taking
- * into account the th_adjustment factor which the NTP PLL/adjtime(2)
- * processing provides us with.
- *
- * The th_adjustment is nanoseconds per second with 32 bit binary
- * fraction and we want 64 bit binary fraction of second:
- *
- * x = a * 2^32 / 10^9 = a * 4.294967296
- *
- * The range of th_adjustment is +/- 5000PPM so inside a 64bit int
- * we can only multiply by about 850 without overflowing, that
- * leaves no suitably precise fractions for multiply before divide.
- *
- * Divide before multiply with a fraction of 2199/512 results in a
- * systematic undercompensation of 10PPM of th_adjustment. On a
- * 5000PPM adjustment this is a 0.05PPM error. This is acceptable.
- *
- * We happily sacrifice the lowest of the 64 bits of our result
- * to the goddess of code clarity.
- *
- */
- scale = (u_int64_t)1 << 63;
- scale += (th->th_adjustment / 1024) * 2199;
- scale /= th->th_counter->tc_frequency;
- th->th_scale = scale * 2;
-
- /*
- * Now that the struct timehands is again consistent, set the new
- * generation number, making sure to not make it zero.
- */
- if (++ogen == 0)
- ogen = 1;
- th->th_generation = ogen;
-
- /* Go live with the new struct timehands. */
- time_second = th->th_microtime.tv_sec;
- time_uptime = th->th_offset.sec;
- timehands = th;
-}
-
-/* Report or change the active timecounter hardware. */
-static int
-sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS)
-{
- char newname[32];
- struct timecounter *newtc, *tc;
- int error;
-
- tc = timecounter;
- strlcpy(newname, tc->tc_name, sizeof(newname));
-
- error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req);
- if (error != 0 || req->newptr == NULL ||
- strcmp(newname, tc->tc_name) == 0)
- return (error);
- for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) {
- if (strcmp(newname, newtc->tc_name) != 0)
- continue;
-
- /* Warm up new timecounter. */
- (void)newtc->tc_get_timecount(newtc);
- (void)newtc->tc_get_timecount(newtc);
-
- timecounter = newtc;
- return (0);
- }
- return (EINVAL);
-}
-
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW,
- 0, 0, sysctl_kern_timecounter_hardware, "A",
- "Timecounter hardware selected");
-
-
-/* Report or change the active timecounter hardware. */
-static int
-sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS)
-{
- char buf[32], *spc;
- struct timecounter *tc;
- int error;
-
- spc = "";
- error = 0;
- for (tc = timecounters; error == 0 && tc != NULL; tc = tc->tc_next) {
- sprintf(buf, "%s%s(%d)",
- spc, tc->tc_name, tc->tc_quality);
- error = SYSCTL_OUT(req, buf, strlen(buf));
- spc = " ";
- }
- return (error);
-}
-
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
- 0, 0, sysctl_kern_timecounter_choice, "A", "Timecounter hardware detected");
-
-/*
- * RFC 2783 PPS-API implementation.
- */
-
-int
-pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
-{
- pps_params_t *app;
- struct pps_fetch_args *fapi;
-#ifdef PPS_SYNC
- struct pps_kcbind_args *kapi;
-#endif
-
- KASSERT(pps != NULL, ("NULL pps pointer in pps_ioctl"));
- switch (cmd) {
- case PPS_IOC_CREATE:
- return (0);
- case PPS_IOC_DESTROY:
- return (0);
- case PPS_IOC_SETPARAMS:
- app = (pps_params_t *)data;
- if (app->mode & ~pps->ppscap)
- return (EINVAL);
- pps->ppsparam = *app;
- return (0);
- case PPS_IOC_GETPARAMS:
- app = (pps_params_t *)data;
- *app = pps->ppsparam;
- app->api_version = PPS_API_VERS_1;
- return (0);
- case PPS_IOC_GETCAP:
- *(int*)data = pps->ppscap;
- return (0);
- case PPS_IOC_FETCH:
- fapi = (struct pps_fetch_args *)data;
- if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC)
- return (EINVAL);
- if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec)
- return (EOPNOTSUPP);
- pps->ppsinfo.current_mode = pps->ppsparam.mode;
- fapi->pps_info_buf = pps->ppsinfo;
- return (0);
- case PPS_IOC_KCBIND:
-#ifdef PPS_SYNC
- kapi = (struct pps_kcbind_args *)data;
- /* XXX Only root should be able to do this */
- if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC)
- return (EINVAL);
- if (kapi->kernel_consumer != PPS_KC_HARDPPS)
- return (EINVAL);
- if (kapi->edge & ~pps->ppscap)
- return (EINVAL);
- pps->kcmode = kapi->edge;
- return (0);
-#else
- return (EOPNOTSUPP);
-#endif
- default:
- return (ENOIOCTL);
- }
-}
-
-void
-pps_init(struct pps_state *pps)
-{
- pps->ppscap |= PPS_TSFMT_TSPEC;
- if (pps->ppscap & PPS_CAPTUREASSERT)
- pps->ppscap |= PPS_OFFSETASSERT;
- if (pps->ppscap & PPS_CAPTURECLEAR)
- pps->ppscap |= PPS_OFFSETCLEAR;
-}
-
-void
-pps_capture(struct pps_state *pps)
-{
- struct timehands *th;
-
- KASSERT(pps != NULL, ("NULL pps pointer in pps_capture"));
- th = timehands;
- pps->capgen = th->th_generation;
- pps->capth = th;
- pps->capcount = th->th_counter->tc_get_timecount(th->th_counter);
- if (pps->capgen != th->th_generation)
- pps->capgen = 0;
-}
-
-void
-pps_event(struct pps_state *pps, int event)
-{
- struct bintime bt;
- struct timespec ts, *tsp, *osp;
- u_int tcount, *pcount;
- int foff, fhard;
- pps_seq_t *pseq;
-
- KASSERT(pps != NULL, ("NULL pps pointer in pps_event"));
- /* If the timecounter was wound up underneath us, bail out. */
- if (pps->capgen == 0 || pps->capgen != pps->capth->th_generation)
- return;
-
- /* Things would be easier with arrays. */
- if (event == PPS_CAPTUREASSERT) {
- tsp = &pps->ppsinfo.assert_timestamp;
- osp = &pps->ppsparam.assert_offset;
- foff = pps->ppsparam.mode & PPS_OFFSETASSERT;
- fhard = pps->kcmode & PPS_CAPTUREASSERT;
- pcount = &pps->ppscount[0];
- pseq = &pps->ppsinfo.assert_sequence;
- } else {
- tsp = &pps->ppsinfo.clear_timestamp;
- osp = &pps->ppsparam.clear_offset;
- foff = pps->ppsparam.mode & PPS_OFFSETCLEAR;
- fhard = pps->kcmode & PPS_CAPTURECLEAR;
- pcount = &pps->ppscount[1];
- pseq = &pps->ppsinfo.clear_sequence;
- }
-
- /*
- * If the timecounter changed, we cannot compare the count values, so
- * we have to drop the rest of the PPS-stuff until the next event.
- */
- if (pps->ppstc != pps->capth->th_counter) {
- pps->ppstc = pps->capth->th_counter;
- *pcount = pps->capcount;
- pps->ppscount[2] = pps->capcount;
- return;
- }
-
- /* Convert the count to a timespec. */
- tcount = pps->capcount - pps->capth->th_offset_count;
- tcount &= pps->capth->th_counter->tc_counter_mask;
- bt = pps->capth->th_offset;
- bintime_addx(&bt, pps->capth->th_scale * tcount);
- bintime_add(&bt, &boottimebin);
- bintime2timespec(&bt, &ts);
-
- /* If the timecounter was wound up underneath us, bail out. */
- if (pps->capgen != pps->capth->th_generation)
- return;
-
- *pcount = pps->capcount;
- (*pseq)++;
- *tsp = ts;
-
- if (foff) {
- timespecadd(tsp, osp);
- if (tsp->tv_nsec < 0) {
- tsp->tv_nsec += 1000000000;
- tsp->tv_sec -= 1;
- }
- }
-#ifdef PPS_SYNC
- if (fhard) {
- u_int64_t scale;
-
- /*
- * Feed the NTP PLL/FLL.
- * The FLL wants to know how many (hardware) nanoseconds
- * elapsed since the previous event.
- */
- tcount = pps->capcount - pps->ppscount[2];
- pps->ppscount[2] = pps->capcount;
- tcount &= pps->capth->th_counter->tc_counter_mask;
- scale = (u_int64_t)1 << 63;
- scale /= pps->capth->th_counter->tc_frequency;
- scale *= 2;
- bt.sec = 0;
- bt.frac = 0;
- bintime_addx(&bt, scale * tcount);
- bintime2timespec(&bt, &ts);
- hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
- }
-#endif
-}
-
-/*
- * Timecounters need to be updated every so often to prevent the hardware
- * counter from overflowing. Updating also recalculates the cached values
- * used by the get*() family of functions, so their precision depends on
- * the update frequency.
- */
-
-static int tc_tick;
-SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0,
- "Approximate number of hardclock ticks in a millisecond");
-
-void
-tc_ticktock(void)
-{
- static int count;
- static time_t last_calib;
-
- if (++count < tc_tick)
- return;
- count = 0;
- tc_windup();
- if (time_uptime != last_calib && !(time_uptime & 0xf)) {
- cpu_tick_calibrate(0);
- last_calib = time_uptime;
- }
-}
-
-static void
-inittimecounter(void *dummy)
-{
- u_int p;
-
- /*
- * Set the initial timeout to
- * max(1, <approx. number of hardclock ticks in a millisecond>).
- * People should probably not use the sysctl to set the timeout
- * to smaller than its inital value, since that value is the
- * smallest reasonable one. If they want better timestamps they
- * should use the non-"get"* functions.
- */
- if (hz > 1000)
- tc_tick = (hz + 500) / 1000;
- else
- tc_tick = 1;
- p = (tc_tick * 1000000) / hz;
- printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000);
-
- /* warm up new timecounter (again) and get rolling. */
- (void)timecounter->tc_get_timecount(timecounter);
- (void)timecounter->tc_get_timecount(timecounter);
-}
-
-SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL);
-
-/* Cpu tick handling -------------------------------------------------*/
-
-static int cpu_tick_variable;
-static uint64_t cpu_tick_frequency;
-
-static uint64_t
-tc_cpu_ticks(void)
-{
- static uint64_t base;
- static unsigned last;
- unsigned u;
- struct timecounter *tc;
-
- tc = timehands->th_counter;
- u = tc->tc_get_timecount(tc) & tc->tc_counter_mask;
- if (u < last)
- base += (uint64_t)tc->tc_counter_mask + 1;
- last = u;
- return (u + base);
-}
-
-/*
- * This function gets called every 16 seconds on only one designated
- * CPU in the system from hardclock() via tc_ticktock().
- *
- * Whenever the real time clock is stepped we get called with reset=1
- * to make sure we handle suspend/resume and similar events correctly.
- */
-
-static void
-cpu_tick_calibrate(int reset)
-{
- static uint64_t c_last;
- uint64_t c_this, c_delta;
- static struct bintime t_last;
- struct bintime t_this, t_delta;
- uint32_t divi;
-
- if (reset) {
- /* The clock was stepped, abort & reset */
- t_last.sec = 0;
- return;
- }
-
- /* we don't calibrate fixed rate cputicks */
- if (!cpu_tick_variable)
- return;
-
- getbinuptime(&t_this);
- c_this = cpu_ticks();
- if (t_last.sec != 0) {
- c_delta = c_this - c_last;
- t_delta = t_this;
- bintime_sub(&t_delta, &t_last);
- /*
- * Validate that 16 +/- 1/256 seconds passed.
- * After division by 16 this gives us a precision of
- * roughly 250PPM which is sufficient
- */
- if (t_delta.sec > 16 || (
- t_delta.sec == 16 && t_delta.frac >= (0x01LL << 56))) {
- /* too long */
- if (bootverbose)
- printf("t_delta %ju.%016jx too long\n",
- (uintmax_t)t_delta.sec,
- (uintmax_t)t_delta.frac);
- } else if (t_delta.sec < 15 ||
- (t_delta.sec == 15 && t_delta.frac <= (0xffLL << 56))) {
- /* too short */
- if (bootverbose)
- printf("t_delta %ju.%016jx too short\n",
- (uintmax_t)t_delta.sec,
- (uintmax_t)t_delta.frac);
- } else {
- /* just right */
- /*
- * Headroom:
- * 2^(64-20) / 16[s] =
- * 2^(44) / 16[s] =
- * 17.592.186.044.416 / 16 =
- * 1.099.511.627.776 [Hz]
- */
- divi = t_delta.sec << 20;
- divi |= t_delta.frac >> (64 - 20);
- c_delta <<= 20;
- c_delta /= divi;
- if (c_delta > cpu_tick_frequency) {
- if (0 && bootverbose)
- printf("cpu_tick increased to %ju Hz\n",
- c_delta);
- cpu_tick_frequency = c_delta;
- }
- }
- }
- c_last = c_this;
- t_last = t_this;
-}
-
-void
-set_cputicker(cpu_tick_f *func, uint64_t freq, unsigned var)
-{
-
- if (func == NULL) {
- cpu_ticks = tc_cpu_ticks;
- } else {
- cpu_tick_frequency = freq;
- cpu_tick_variable = var;
- cpu_ticks = func;
- }
-}
-
-uint64_t
-cpu_tickrate(void)
-{
-
- if (cpu_ticks == tc_cpu_ticks)
- return (tc_getfrequency());
- return (cpu_tick_frequency);
-}
-
-/*
- * We need to be slightly careful converting cputicks to microseconds.
- * There is plenty of margin in 64 bits of microseconds (half a million
- * years) and in 64 bits at 4 GHz (146 years), but if we do a multiply
- * before divide conversion (to retain precision) we find that the
- * margin shrinks to 1.5 hours (one millionth of 146y).
- * With a three prong approach we never lose significant bits, no
- * matter what the cputick rate and length of timeinterval is.
- */
-
-uint64_t
-cputick2usec(uint64_t tick)
-{
-
- if (tick > 18446744073709551LL) /* floor(2^64 / 1000) */
- return (tick / (cpu_tickrate() / 1000000LL));
- else if (tick > 18446744073709LL) /* floor(2^64 / 1000000) */
- return ((tick * 1000LL) / (cpu_tickrate() / 1000LL));
- else
- return ((tick * 1000000LL) / cpu_tickrate());
-}
-
-cpu_tick_f *cpu_ticks = tc_cpu_ticks;