Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:26

0001 /**
0002  * @file
0003  *
0004  * @ingroup RTEMSScoreTimecounter
0005  *
0006  * @brief This source file contains the implementation of ntp_gettime(),
0007  *   ntp_adjtime(), adjtime(), and _Timecounter_NTP_update_second().
0008  */
0009 
0010 /*-
0011  ***********************************************************************
0012  *                                     *
0013  * Copyright (c) David L. Mills 1993-2001                  *
0014  *                                     *
0015  * Permission to use, copy, modify, and distribute this software and   *
0016  * its documentation for any purpose and without fee is hereby         *
0017  * granted, provided that the above copyright notice appears in all    *
0018  * copies and that both the copyright notice and this permission       *
0019  * notice appear in supporting documentation, and that the name        *
0020  * University of Delaware not be used in advertising or publicity      *
0021  * pertaining to distribution of the software without specific,        *
0022  * written prior permission. The University of Delaware makes no       *
0023  * representations about the suitability this software for any         *
0024  * purpose. It is provided "as is" without express or implied          *
0025  * warranty.                                   *
0026  *                                     *
0027  **********************************************************************/
0028 
0029 /*
0030  * Adapted from the original sources for FreeBSD and timecounters by:
0031  * Poul-Henning Kamp <phk@FreeBSD.org>.
0032  *
0033  * The 32bit version of the "LP" macros seems a bit past its "sell by" 
0034  * date so I have retained only the 64bit version and included it directly
0035  * in this file.
0036  *
0037  * Only minor changes done to interface with the timecounters over in
0038  * sys/kern/kern_clock.c.   Some of the comments below may be (even more)
0039  * confusing and/or plain wrong in that context.
0040  */
0041 
0042 #include <sys/cdefs.h>
0043 #include "opt_ntp.h"
0044 
0045 #include <sys/param.h>
0046 #ifndef __rtems__
0047 #include <sys/systm.h>
0048 #include <sys/sysproto.h>
0049 #include <sys/eventhandler.h>
0050 #include <sys/kernel.h>
0051 #include <sys/priv.h>
0052 #include <sys/proc.h>
0053 #include <sys/lock.h>
0054 #include <sys/mutex.h>
0055 #endif /* __rtems__ */
0056 #include <sys/time.h>
0057 #include <sys/timex.h>
0058 #include <sys/timetc.h>
0059 #ifdef __rtems__
0060 #define _KERNEL
0061 #endif /* __rtems__ */
0062 #include <sys/timepps.h>
0063 #ifndef __rtems__
0064 #include <sys/syscallsubr.h>
0065 #include <sys/sysctl.h>
0066 #else /* __rtems__ */
0067 #include <rtems/sysinit.h>
0068 #include <rtems/score/timecounter.h>
0069 #include <errno.h>
0070 #include <string.h>
0071 #define nanotime(_tsp) _Timecounter_Nanotime(_tsp)
0072 #define ntp_update_second _Timecounter_NTP_update_second
0073 #define time_uptime _Timecounter_Time_uptime
0074 struct thread;
0075 
0076 static inline long
0077 lmax(long a, long b)
0078 {
0079 
0080     if (a > b)
0081         return (a);
0082     return (b);
0083 }
0084 
0085 static inline quad_t
0086 qmin(quad_t a, quad_t b)
0087 {
0088 
0089     if (a < b)
0090            return (a);
0091     return (b);
0092 }
0093 #endif /* __rtems__ */
0094 
0095 #ifndef __rtems__
0096 #ifdef PPS_SYNC
0097 FEATURE(pps_sync, "Support usage of external PPS signal by kernel PLL");
0098 #endif
0099 #endif /* __rtems__ */
0100 
0101 /*
0102  * Single-precision macros for 64-bit machines
0103  */
0104 typedef int64_t l_fp;
0105 #define L_ADD(v, u) ((v) += (u))
0106 #define L_SUB(v, u) ((v) -= (u))
0107 #define L_ADDHI(v, a)   ((v) += (int64_t)(a) << 32)
0108 #define L_NEG(v)    ((v) = -(v))
0109 #define L_RSHIFT(v, n) \
0110     do { \
0111         if ((v) < 0) \
0112             (v) = -(-(v) >> (n)); \
0113         else \
0114             (v) = (v) >> (n); \
0115     } while (0)
0116 #define L_MPY(v, a) ((v) *= (a))
0117 #define L_CLR(v)    ((v) = 0)
0118 #define L_ISNEG(v)  ((v) < 0)
0119 #define L_LINT(v, a) \
0120     do { \
0121         if ((a) < 0) \
0122             ((v) = -((int64_t)(-(a)) << 32)); \
0123         else \
0124             ((v) = (int64_t)(a) << 32); \
0125     } while (0)
0126 #define L_GINT(v)   ((v) < 0 ? -(-(v) >> 32) : (v) >> 32)
0127 
0128 /*
0129  * Generic NTP kernel interface
0130  *
0131  * These routines constitute the Network Time Protocol (NTP) interfaces
0132  * for user and daemon application programs. The ntp_gettime() routine
0133  * provides the time, maximum error (synch distance) and estimated error
0134  * (dispersion) to client user application programs. The ntp_adjtime()
0135  * routine is used by the NTP daemon to adjust the system clock to an
0136  * externally derived time. The time offset and related variables set by
0137  * this routine are used by other routines in this module to adjust the
0138  * phase and frequency of the clock discipline loop which controls the
0139  * system clock.
0140  *
0141  * When the kernel time is reckoned directly in nanoseconds (NTP_NANO
0142  * defined), the time at each tick interrupt is derived directly from
0143  * the kernel time variable. When the kernel time is reckoned in
0144  * microseconds, (NTP_NANO undefined), the time is derived from the
0145  * kernel time variable together with a variable representing the
0146  * leftover nanoseconds at the last tick interrupt. In either case, the
0147  * current nanosecond time is reckoned from these values plus an
0148  * interpolated value derived by the clock routines in another
0149  * architecture-specific module. The interpolation can use either a
0150  * dedicated counter or a processor cycle counter (PCC) implemented in
0151  * some architectures.
0152  *
0153  * Note that all routines must run at priority splclock or higher.
0154  */
0155 /*
0156  * Phase/frequency-lock loop (PLL/FLL) definitions
0157  *
0158  * The nanosecond clock discipline uses two variable types, time
0159  * variables and frequency variables. Both types are represented as 64-
0160  * bit fixed-point quantities with the decimal point between two 32-bit
0161  * halves. On a 32-bit machine, each half is represented as a single
0162  * word and mathematical operations are done using multiple-precision
0163  * arithmetic. On a 64-bit machine, ordinary computer arithmetic is
0164  * used.
0165  *
0166  * A time variable is a signed 64-bit fixed-point number in ns and
0167  * fraction. It represents the remaining time offset to be amortized
0168  * over succeeding tick interrupts. The maximum time offset is about
0169  * 0.5 s and the resolution is about 2.3e-10 ns.
0170  *
0171  *          1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0172  *  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
0173  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0174  * |s s s|           ns                |
0175  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0176  * |                fraction                   |
0177  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0178  *
0179  * A frequency variable is a signed 64-bit fixed-point number in ns/s
0180  * and fraction. It represents the ns and fraction to be added to the
0181  * kernel time variable at each second. The maximum frequency offset is
0182  * about +-500000 ns/s and the resolution is about 2.3e-10 ns/s.
0183  *
0184  *          1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0185  *  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
0186  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0187  * |s s s s s s s s s s s s s|            ns/s             |
0188  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0189  * |                fraction                   |
0190  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0191  */
0192 /*
0193  * The following variables establish the state of the PLL/FLL and the
0194  * residual time and frequency offset of the local clock.
0195  */
0196 #define SHIFT_PLL   4       /* PLL loop gain (shift) */
0197 #define SHIFT_FLL   2       /* FLL loop gain (shift) */
0198 
0199 static int time_state = TIME_OK;    /* clock state */
0200 #ifdef __rtems__
0201 static
0202 #endif /* __rtems__ */
0203 int time_status = STA_UNSYNC;   /* clock status bits */
0204 static long time_tai;           /* TAI offset (s) */
0205 static long time_monitor;       /* last time offset scaled (ns) */
0206 static long time_constant;      /* poll interval (shift) (s) */
0207 static long time_precision = 1;     /* clock precision (ns) */
0208 static long time_maxerror = MAXPHASE / 1000; /* maximum error (us) */
0209 #ifdef __rtems__
0210 static
0211 #endif /* __rtems__ */
0212 long time_esterror = MAXPHASE / 1000; /* estimated error (us) */
0213 static long time_reftime;       /* uptime at last adjustment (s) */
0214 static l_fp time_offset;        /* time offset (ns) */
0215 static l_fp time_freq;          /* frequency offset (ns/s) */
0216 static l_fp time_adj;           /* tick adjust (ns/s) */
0217 
0218 static int64_t time_adjtime;        /* correction from adjtime(2) (usec) */
0219 
0220 #ifndef __rtems__
0221 static struct mtx ntp_lock;
0222 MTX_SYSINIT(ntp, &ntp_lock, "ntp", MTX_SPIN);
0223 
0224 #define NTP_LOCK()      mtx_lock_spin(&ntp_lock)
0225 #define NTP_UNLOCK()        mtx_unlock_spin(&ntp_lock)
0226 #define NTP_ASSERT_LOCKED() mtx_assert(&ntp_lock, MA_OWNED)
0227 #else /* __rtems__ */
0228 #define NTP_LOCK()                  \
0229     do {                        \
0230         ISR_lock_Context lock_context;          \
0231         _Timecounter_Acquire(&lock_context);
0232 #define NTP_UNLOCK()                    \
0233         _Timecounter_Release(&lock_context);        \
0234     } while (0)
0235 #define NTP_ASSERT_LOCKED()             \
0236     _Assert(_ISR_lock_Is_owner(&_Timecounter_Lock))
0237 #endif /* __rtems__ */
0238 
0239 #ifdef PPS_SYNC
0240 /*
0241  * The following variables are used when a pulse-per-second (PPS) signal
0242  * is available and connected via a modem control lead. They establish
0243  * the engineering parameters of the clock discipline loop when
0244  * controlled by the PPS signal.
0245  */
0246 #define PPS_FAVG    2       /* min freq avg interval (s) (shift) */
0247 #define PPS_FAVGDEF 8       /* default freq avg int (s) (shift) */
0248 #define PPS_FAVGMAX 15      /* max freq avg interval (s) (shift) */
0249 #define PPS_PAVG    4       /* phase avg interval (s) (shift) */
0250 #define PPS_VALID   120     /* PPS signal watchdog max (s) */
0251 #define PPS_MAXWANDER   100000      /* max PPS wander (ns/s) */
0252 #define PPS_POPCORN 2       /* popcorn spike threshold (shift) */
0253 
0254 static struct timespec pps_tf[3];   /* phase median filter */
0255 static l_fp pps_freq;           /* scaled frequency offset (ns/s) */
0256 static long pps_fcount;         /* frequency accumulator */
0257 static long pps_jitter;         /* nominal jitter (ns) */
0258 static long pps_stabil;         /* nominal stability (scaled ns/s) */
0259 static time_t pps_lastsec;      /* time at last calibration (s) */
0260 
0261 static int pps_valid;           /* signal watchdog counter */
0262 static int pps_shift = PPS_FAVG;    /* interval duration (s) (shift) */
0263 static int pps_shiftmax = PPS_FAVGDEF;  /* max interval duration (s) (shift) */
0264 static int pps_intcnt;          /* wander counter */
0265 
0266 /*
0267  * PPS signal quality monitors
0268  */
0269 static long pps_calcnt;         /* calibration intervals */
0270 static long pps_jitcnt;         /* jitter limit exceeded */
0271 static long pps_stbcnt;         /* stability limit exceeded */
0272 static long pps_errcnt;         /* calibration errors */
0273 #endif /* PPS_SYNC */
0274 /*
0275  * End of phase/frequency-lock loop (PLL/FLL) definitions
0276  */
0277 
0278 static void hardupdate(long offset);
0279 static void ntp_gettime1(struct ntptimeval *ntvp);
0280 static bool ntp_is_time_error(int tsl);
0281 
0282 static bool
0283 ntp_is_time_error(int tsl)
0284 {
0285 
0286     /*
0287      * Status word error decode. If any of these conditions occur,
0288      * an error is returned, instead of the status word. Most
0289      * applications will care only about the fact the system clock
0290      * may not be trusted, not about the details.
0291      *
0292      * Hardware or software error
0293      */
0294     if ((tsl & (STA_UNSYNC | STA_CLOCKERR)) ||
0295 
0296     /*
0297      * PPS signal lost when either time or frequency synchronization
0298      * requested
0299      */
0300         (tsl & (STA_PPSFREQ | STA_PPSTIME) &&
0301         !(tsl & STA_PPSSIGNAL)) ||
0302 
0303     /*
0304      * PPS jitter exceeded when time synchronization requested
0305      */
0306         (tsl & STA_PPSTIME && tsl & STA_PPSJITTER) ||
0307 
0308     /*
0309      * PPS wander exceeded or calibration error when frequency
0310      * synchronization requested
0311      */
0312         (tsl & STA_PPSFREQ &&
0313         tsl & (STA_PPSWANDER | STA_PPSERROR)))
0314         return (true);
0315 
0316     return (false);
0317 }
0318 
0319 static void
0320 ntp_gettime1(struct ntptimeval *ntvp)
0321 {
0322     struct timespec atv;    /* nanosecond time */
0323 
0324     NTP_ASSERT_LOCKED();
0325 
0326     nanotime(&atv);
0327     ntvp->time.tv_sec = atv.tv_sec;
0328     ntvp->time.tv_nsec = atv.tv_nsec;
0329     ntvp->maxerror = time_maxerror;
0330     ntvp->esterror = time_esterror;
0331     ntvp->tai = time_tai;
0332     ntvp->time_state = time_state;
0333 
0334     if (ntp_is_time_error(time_status))
0335         ntvp->time_state = TIME_ERROR;
0336 }
0337 
0338 /*
0339  * ntp_gettime() - NTP user application interface
0340  *
0341  * See the timex.h header file for synopsis and API description.  Note that
0342  * the TAI offset is returned in the ntvtimeval.tai structure member.
0343  */
0344 #ifndef __rtems__
0345 #ifndef _SYS_SYSPROTO_H_
0346 struct ntp_gettime_args {
0347     struct ntptimeval *ntvp;
0348 };
0349 #endif
0350 /* ARGSUSED */
0351 int
0352 sys_ntp_gettime(struct thread *td, struct ntp_gettime_args *uap)
0353 {   
0354     struct ntptimeval ntv;
0355 
0356     memset(&ntv, 0, sizeof(ntv));
0357 
0358     NTP_LOCK();
0359     ntp_gettime1(&ntv);
0360     NTP_UNLOCK();
0361 
0362     td->td_retval[0] = ntv.time_state;
0363     return (copyout(&ntv, uap->ntvp, sizeof(ntv)));
0364 }
0365 #else /* __rtems__ */
0366 int
0367 ntp_gettime(struct ntptimeval *ntv)
0368 {
0369 
0370     if (ntv == NULL) {
0371         errno = EFAULT;
0372         return (-1);
0373     }
0374 
0375     ntv = memset(ntv, 0, sizeof(*ntv));
0376 
0377     NTP_LOCK();
0378     ntp_gettime1(ntv);
0379     NTP_UNLOCK();
0380 
0381     return (ntv->time_state);
0382 }
0383 #endif /* __rtems__ */
0384 
0385 #ifndef __rtems__
0386 static int
0387 ntp_sysctl(SYSCTL_HANDLER_ARGS)
0388 {
0389     struct ntptimeval ntv;  /* temporary structure */
0390 
0391     memset(&ntv, 0, sizeof(ntv));
0392 
0393     NTP_LOCK();
0394     ntp_gettime1(&ntv);
0395     NTP_UNLOCK();
0396 
0397     return (sysctl_handle_opaque(oidp, &ntv, sizeof(ntv), req));
0398 }
0399 
0400 SYSCTL_NODE(_kern, OID_AUTO, ntp_pll, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
0401     "");
0402 SYSCTL_PROC(_kern_ntp_pll, OID_AUTO, gettime, CTLTYPE_OPAQUE | CTLFLAG_RD |
0403     CTLFLAG_MPSAFE, 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval",
0404     "");
0405 
0406 #ifdef PPS_SYNC
0407 SYSCTL_INT(_kern_ntp_pll, OID_AUTO, pps_shiftmax, CTLFLAG_RW,
0408     &pps_shiftmax, 0, "Max interval duration (sec) (shift)");
0409 SYSCTL_INT(_kern_ntp_pll, OID_AUTO, pps_shift, CTLFLAG_RW,
0410     &pps_shift, 0, "Interval duration (sec) (shift)");
0411 SYSCTL_LONG(_kern_ntp_pll, OID_AUTO, time_monitor, CTLFLAG_RD,
0412     &time_monitor, 0, "Last time offset scaled (ns)");
0413 
0414 SYSCTL_S64(_kern_ntp_pll, OID_AUTO, pps_freq, CTLFLAG_RD | CTLFLAG_MPSAFE,
0415     &pps_freq, 0,
0416     "Scaled frequency offset (ns/sec)");
0417 SYSCTL_S64(_kern_ntp_pll, OID_AUTO, time_freq, CTLFLAG_RD | CTLFLAG_MPSAFE,
0418     &time_freq, 0,
0419     "Frequency offset (ns/sec)");
0420 #endif
0421 #endif /* __rtems__ */
0422 
0423 /*
0424  * ntp_adjtime() - NTP daemon application interface
0425  *
0426  * See the timex.h header file for synopsis and API description.  Note that
0427  * the timex.constant structure member has a dual purpose to set the time
0428  * constant and to set the TAI offset.
0429  */
0430 #ifdef __rtems__
0431 static
0432 #endif /* __rtems__ */
0433 int
0434 kern_ntp_adjtime(struct thread *td, struct timex *ntv, int *retvalp)
0435 {
0436     long freq;      /* frequency ns/s) */
0437     int modes;      /* mode bits from structure */
0438 #ifndef __rtems__
0439     int error, retval;
0440 #else /* __rtems__ */
0441     int retval;
0442 #endif /* __rtems__ */
0443 
0444     /*
0445      * Update selected clock variables - only the superuser can
0446      * change anything. Note that there is no error checking here on
0447      * the assumption the superuser should know what it is doing.
0448      * Note that either the time constant or TAI offset are loaded
0449      * from the ntv.constant member, depending on the mode bits. If
0450      * the STA_PLL bit in the status word is cleared, the state and
0451      * status words are reset to the initial values at boot.
0452      */
0453     modes = ntv->modes;
0454 #ifndef __rtems__
0455     error = 0;
0456     if (modes)
0457         error = priv_check(td, PRIV_NTP_ADJTIME);
0458     if (error != 0)
0459         return (error);
0460 #endif /* __rtems__ */
0461     NTP_LOCK();
0462     if (modes & MOD_MAXERROR)
0463         time_maxerror = ntv->maxerror;
0464     if (modes & MOD_ESTERROR)
0465         time_esterror = ntv->esterror;
0466     if (modes & MOD_STATUS) {
0467         if (time_status & STA_PLL && !(ntv->status & STA_PLL)) {
0468             time_state = TIME_OK;
0469             time_status = STA_UNSYNC;
0470 #ifdef PPS_SYNC
0471             pps_shift = PPS_FAVG;
0472 #endif /* PPS_SYNC */
0473         }
0474         time_status &= STA_RONLY;
0475         time_status |= ntv->status & ~STA_RONLY;
0476     }
0477     if (modes & MOD_TIMECONST) {
0478         if (ntv->constant < 0)
0479             time_constant = 0;
0480         else if (ntv->constant > MAXTC)
0481             time_constant = MAXTC;
0482         else
0483             time_constant = ntv->constant;
0484     }
0485     if (modes & MOD_TAI) {
0486         if (ntv->constant > 0) /* XXX zero & negative numbers ? */
0487             time_tai = ntv->constant;
0488     }
0489 #ifdef PPS_SYNC
0490     if (modes & MOD_PPSMAX) {
0491         if (ntv->shift < PPS_FAVG)
0492             pps_shiftmax = PPS_FAVG;
0493         else if (ntv->shift > PPS_FAVGMAX)
0494             pps_shiftmax = PPS_FAVGMAX;
0495         else
0496             pps_shiftmax = ntv->shift;
0497     }
0498 #endif /* PPS_SYNC */
0499     if (modes & MOD_NANO)
0500         time_status |= STA_NANO;
0501     if (modes & MOD_MICRO)
0502         time_status &= ~STA_NANO;
0503     if (modes & MOD_CLKB)
0504         time_status |= STA_CLK;
0505     if (modes & MOD_CLKA)
0506         time_status &= ~STA_CLK;
0507     if (modes & MOD_FREQUENCY) {
0508         freq = (ntv->freq * 1000LL) >> 16;
0509         if (freq > MAXFREQ)
0510             L_LINT(time_freq, MAXFREQ);
0511         else if (freq < -MAXFREQ)
0512             L_LINT(time_freq, -MAXFREQ);
0513         else {
0514             /*
0515              * ntv->freq is [PPM * 2^16] = [us/s * 2^16]
0516              * time_freq is [ns/s * 2^32]
0517              */
0518             time_freq = ntv->freq * 1000LL * 65536LL;
0519         }
0520 #ifdef PPS_SYNC
0521         pps_freq = time_freq;
0522 #endif /* PPS_SYNC */
0523     }
0524     if (modes & MOD_OFFSET) {
0525         if (time_status & STA_NANO)
0526             hardupdate(ntv->offset);
0527         else
0528             hardupdate(ntv->offset * 1000);
0529     }
0530 
0531     /*
0532      * Retrieve all clock variables. Note that the TAI offset is
0533      * returned only by ntp_gettime();
0534      */
0535     if (time_status & STA_NANO)
0536         ntv->offset = L_GINT(time_offset);
0537     else
0538         ntv->offset = L_GINT(time_offset) / 1000; /* XXX rounding ? */
0539     ntv->freq = L_GINT((time_freq / 1000LL) << 16);
0540     ntv->maxerror = time_maxerror;
0541     ntv->esterror = time_esterror;
0542     ntv->status = time_status;
0543     ntv->constant = time_constant;
0544     if (time_status & STA_NANO)
0545         ntv->precision = time_precision;
0546     else
0547         ntv->precision = time_precision / 1000;
0548     ntv->tolerance = MAXFREQ * SCALE_PPM;
0549 #ifdef PPS_SYNC
0550     ntv->shift = pps_shift;
0551     ntv->ppsfreq = L_GINT((pps_freq / 1000LL) << 16);
0552     if (time_status & STA_NANO)
0553         ntv->jitter = pps_jitter;
0554     else
0555         ntv->jitter = pps_jitter / 1000;
0556     ntv->stabil = pps_stabil;
0557     ntv->calcnt = pps_calcnt;
0558     ntv->errcnt = pps_errcnt;
0559     ntv->jitcnt = pps_jitcnt;
0560     ntv->stbcnt = pps_stbcnt;
0561 #endif /* PPS_SYNC */
0562     retval = ntp_is_time_error(time_status) ? TIME_ERROR : time_state;
0563     NTP_UNLOCK();
0564 
0565     *retvalp = retval;
0566     return (0);
0567 }
0568 
0569 #ifndef _SYS_SYSPROTO_H_
0570 struct ntp_adjtime_args {
0571     struct timex *tp;
0572 };
0573 #endif
0574 
0575 #ifndef __rtems__
0576 int
0577 sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
0578 {
0579     struct timex ntv;
0580     int error, retval;
0581 
0582     error = copyin(uap->tp, &ntv, sizeof(ntv));
0583     if (error == 0) {
0584         error = kern_ntp_adjtime(td, &ntv, &retval);
0585         if (error == 0) {
0586             error = copyout(&ntv, uap->tp, sizeof(ntv));
0587             if (error == 0)
0588                 td->td_retval[0] = retval;
0589         }
0590     }
0591     return (error);
0592 }
0593 #else /* __rtems__ */
0594 int
0595 ntp_adjtime(struct timex *ntv)
0596 {
0597     int error;
0598     int retval;
0599 
0600     if (ntv == NULL) {
0601         errno = EFAULT;
0602         return (-1);
0603     }
0604 
0605     error = kern_ntp_adjtime(NULL, ntv, &retval);
0606     _Assert_Unused_variable_equals(error, 0);
0607     return (retval);
0608 }
0609 #endif /* __rtems__ */
0610 
0611 /*
0612  * second_overflow() - called after ntp_tick_adjust()
0613  *
0614  * This routine is ordinarily called immediately following the above
0615  * routine ntp_tick_adjust(). While these two routines are normally
0616  * combined, they are separated here only for the purposes of
0617  * simulation.
0618  */
0619 void
0620 ntp_update_second(int64_t *adjustment, time_t *newsec)
0621 {
0622     int tickrate;
0623     l_fp ftemp;     /* 32/64-bit temporary */
0624 
0625 #ifndef __rtems__
0626     NTP_LOCK();
0627 #else /* __rtems__ */
0628     NTP_ASSERT_LOCKED();
0629 #endif /* __rtems__ */
0630 
0631     /*
0632      * On rollover of the second both the nanosecond and microsecond
0633      * clocks are updated and the state machine cranked as
0634      * necessary. The phase adjustment to be used for the next
0635      * second is calculated and the maximum error is increased by
0636      * the tolerance.
0637      */
0638     time_maxerror += MAXFREQ / 1000;
0639 
0640     /*
0641      * Leap second processing. If in leap-insert state at
0642      * the end of the day, the system clock is set back one
0643      * second; if in leap-delete state, the system clock is
0644      * set ahead one second. The nano_time() routine or
0645      * external clock driver will insure that reported time
0646      * is always monotonic.
0647      */
0648     switch (time_state) {
0649         /*
0650          * No warning.
0651          */
0652         case TIME_OK:
0653         if (time_status & STA_INS)
0654             time_state = TIME_INS;
0655         else if (time_status & STA_DEL)
0656             time_state = TIME_DEL;
0657         break;
0658 
0659         /*
0660          * Insert second 23:59:60 following second
0661          * 23:59:59.
0662          */
0663         case TIME_INS:
0664         if (!(time_status & STA_INS))
0665             time_state = TIME_OK;
0666         else if ((*newsec) % 86400 == 0) {
0667             (*newsec)--;
0668             time_state = TIME_OOP;
0669             time_tai++;
0670         }
0671         break;
0672 
0673         /*
0674          * Delete second 23:59:59.
0675          */
0676         case TIME_DEL:
0677         if (!(time_status & STA_DEL))
0678             time_state = TIME_OK;
0679         else if (((*newsec) + 1) % 86400 == 0) {
0680             (*newsec)++;
0681             time_tai--;
0682             time_state = TIME_WAIT;
0683         }
0684         break;
0685 
0686         /*
0687          * Insert second in progress.
0688          */
0689         case TIME_OOP:
0690             time_state = TIME_WAIT;
0691         break;
0692 
0693         /*
0694          * Wait for status bits to clear.
0695          */
0696         case TIME_WAIT:
0697         if (!(time_status & (STA_INS | STA_DEL)))
0698             time_state = TIME_OK;
0699     }
0700 
0701     /*
0702      * Compute the total time adjustment for the next second
0703      * in ns. The offset is reduced by a factor depending on
0704      * whether the PPS signal is operating. Note that the
0705      * value is in effect scaled by the clock frequency,
0706      * since the adjustment is added at each tick interrupt.
0707      */
0708     ftemp = time_offset;
0709 #ifdef PPS_SYNC
0710     /* XXX even if PPS signal dies we should finish adjustment ? */
0711     if (time_status & STA_PPSTIME && time_status &
0712         STA_PPSSIGNAL)
0713         L_RSHIFT(ftemp, pps_shift);
0714     else
0715         L_RSHIFT(ftemp, SHIFT_PLL + time_constant);
0716 #else
0717         L_RSHIFT(ftemp, SHIFT_PLL + time_constant);
0718 #endif /* PPS_SYNC */
0719     time_adj = ftemp;
0720     L_SUB(time_offset, ftemp);
0721     L_ADD(time_adj, time_freq);
0722 
0723     /*
0724      * Apply any correction from adjtime(2).  If more than one second
0725      * off we slew at a rate of 5ms/s (5000 PPM) else 500us/s (500 PPM)
0726      * until the last second is slewed the final < 500 usecs.
0727      */
0728     if (time_adjtime != 0) {
0729         if (time_adjtime > 1000000)
0730             tickrate = 5000;
0731         else if (time_adjtime < -1000000)
0732             tickrate = -5000;
0733         else if (time_adjtime > 500)
0734             tickrate = 500;
0735         else if (time_adjtime < -500)
0736             tickrate = -500;
0737         else
0738             tickrate = time_adjtime;
0739         time_adjtime -= tickrate;
0740         L_LINT(ftemp, tickrate * 1000);
0741         L_ADD(time_adj, ftemp);
0742     }
0743     *adjustment = time_adj;
0744         
0745 #ifdef PPS_SYNC
0746     if (pps_valid > 0)
0747         pps_valid--;
0748     else
0749         time_status &= ~STA_PPSSIGNAL;
0750 #endif /* PPS_SYNC */
0751 
0752 #ifndef __rtems__
0753     NTP_UNLOCK();
0754 #endif /* __rtems__ */
0755 }
0756 #ifdef __rtems__
0757 static void
0758 _NTP_Initialize(void)
0759 {
0760 
0761     _Timecounter_Set_NTP_update_second(ntp_update_second);
0762 }
0763 
0764 RTEMS_SYSINIT_ITEM(_NTP_Initialize, RTEMS_SYSINIT_DEVICE_DRIVERS,
0765     RTEMS_SYSINIT_ORDER_FOURTH);
0766 #endif /* __rtems__ */
0767 
0768 /*
0769  * hardupdate() - local clock update
0770  *
0771  * This routine is called by ntp_adjtime() to update the local clock
0772  * phase and frequency. The implementation is of an adaptive-parameter,
0773  * hybrid phase/frequency-lock loop (PLL/FLL). The routine computes new
0774  * time and frequency offset estimates for each call. If the kernel PPS
0775  * discipline code is configured (PPS_SYNC), the PPS signal itself
0776  * determines the new time offset, instead of the calling argument.
0777  * Presumably, calls to ntp_adjtime() occur only when the caller
0778  * believes the local clock is valid within some bound (+-128 ms with
0779  * NTP). If the caller's time is far different than the PPS time, an
0780  * argument will ensue, and it's not clear who will lose.
0781  *
0782  * For uncompensated quartz crystal oscillators and nominal update
0783  * intervals less than 256 s, operation should be in phase-lock mode,
0784  * where the loop is disciplined to phase. For update intervals greater
0785  * than 1024 s, operation should be in frequency-lock mode, where the
0786  * loop is disciplined to frequency. Between 256 s and 1024 s, the mode
0787  * is selected by the STA_MODE status bit.
0788  */
0789 static void
0790 hardupdate(long offset /* clock offset (ns) */)
0791 {
0792     long mtemp;
0793     l_fp ftemp;
0794 
0795     NTP_ASSERT_LOCKED();
0796 
0797     /*
0798      * Select how the phase is to be controlled and from which
0799      * source. If the PPS signal is present and enabled to
0800      * discipline the time, the PPS offset is used; otherwise, the
0801      * argument offset is used.
0802      */
0803     if (!(time_status & STA_PLL))
0804         return;
0805     if (!(time_status & STA_PPSTIME && time_status &
0806         STA_PPSSIGNAL)) {
0807         if (offset > MAXPHASE)
0808             time_monitor = MAXPHASE;
0809         else if (offset < -MAXPHASE)
0810             time_monitor = -MAXPHASE;
0811         else
0812             time_monitor = offset;
0813         L_LINT(time_offset, time_monitor);
0814     }
0815 
0816     /*
0817      * Select how the frequency is to be controlled and in which
0818      * mode (PLL or FLL). If the PPS signal is present and enabled
0819      * to discipline the frequency, the PPS frequency is used;
0820      * otherwise, the argument offset is used to compute it.
0821      */
0822     if (time_status & STA_PPSFREQ && time_status & STA_PPSSIGNAL) {
0823         time_reftime = time_uptime;
0824         return;
0825     }
0826     if (time_status & STA_FREQHOLD || time_reftime == 0)
0827         time_reftime = time_uptime;
0828     mtemp = time_uptime - time_reftime;
0829     L_LINT(ftemp, time_monitor);
0830     L_RSHIFT(ftemp, (SHIFT_PLL + 2 + time_constant) << 1);
0831     L_MPY(ftemp, mtemp);
0832     L_ADD(time_freq, ftemp);
0833     time_status &= ~STA_MODE;
0834     if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp >
0835         MAXSEC)) {
0836         L_LINT(ftemp, (time_monitor << 4) / mtemp);
0837         L_RSHIFT(ftemp, SHIFT_FLL + 4);
0838         L_ADD(time_freq, ftemp);
0839         time_status |= STA_MODE;
0840     }
0841     time_reftime = time_uptime;
0842     if (L_GINT(time_freq) > MAXFREQ)
0843         L_LINT(time_freq, MAXFREQ);
0844     else if (L_GINT(time_freq) < -MAXFREQ)
0845         L_LINT(time_freq, -MAXFREQ);
0846 }
0847 
0848 #ifdef PPS_SYNC
0849 /*
0850  * hardpps() - discipline CPU clock oscillator to external PPS signal
0851  *
0852  * This routine is called at each PPS interrupt in order to discipline
0853  * the CPU clock oscillator to the PPS signal. There are two independent
0854  * first-order feedback loops, one for the phase, the other for the
0855  * frequency. The phase loop measures and grooms the PPS phase offset
0856  * and leaves it in a handy spot for the seconds overflow routine. The
0857  * frequency loop averages successive PPS phase differences and
0858  * calculates the PPS frequency offset, which is also processed by the
0859  * seconds overflow routine. The code requires the caller to capture the
0860  * time and architecture-dependent hardware counter values in
0861  * nanoseconds at the on-time PPS signal transition.
0862  *
0863  * Note that, on some Unix systems this routine runs at an interrupt
0864  * priority level higher than the timer interrupt routine hardclock().
0865  * Therefore, the variables used are distinct from the hardclock()
0866  * variables, except for the actual time and frequency variables, which
0867  * are determined by this routine and updated atomically.
0868  *
0869  * tsp  - time at current PPS event
0870  * delta_nsec - time elapsed between the previous and current PPS event
0871  */
0872 void
0873 hardpps(struct timespec *tsp, long delta_nsec)
0874 {
0875     long u_nsec, v_nsec; /* temps */
0876     time_t u_sec;
0877     l_fp ftemp;
0878 
0879     NTP_LOCK();
0880 
0881     /*
0882      * The signal is first processed by a range gate and frequency
0883      * discriminator. The range gate rejects noise spikes outside
0884      * the range +-500 us. The frequency discriminator rejects input
0885      * signals with apparent frequency outside the range 1 +-500
0886      * PPM. If two hits occur in the same second, we ignore the
0887      * later hit; if not and a hit occurs outside the range gate,
0888      * keep the later hit for later comparison, but do not process
0889      * it.
0890      */
0891     time_status |= STA_PPSSIGNAL | STA_PPSJITTER;
0892     time_status &= ~(STA_PPSWANDER | STA_PPSERROR);
0893     pps_valid = PPS_VALID;
0894     u_sec = tsp->tv_sec;
0895     u_nsec = tsp->tv_nsec;
0896     if (u_nsec >= (NANOSECOND >> 1)) {
0897         u_nsec -= NANOSECOND;
0898         u_sec++;
0899     }
0900     v_nsec = u_nsec - pps_tf[0].tv_nsec;
0901     if (u_sec == pps_tf[0].tv_sec && v_nsec < NANOSECOND - MAXFREQ)
0902         goto out;
0903     pps_tf[2] = pps_tf[1];
0904     pps_tf[1] = pps_tf[0];
0905     pps_tf[0].tv_sec = u_sec;
0906     pps_tf[0].tv_nsec = u_nsec;
0907 
0908     /*
0909      * Update the frequency accumulator using the difference between the
0910      * current and previous PPS event measured directly by the timecounter.
0911      */
0912     pps_fcount += delta_nsec - NANOSECOND;
0913     if (v_nsec > MAXFREQ || v_nsec < -MAXFREQ)
0914         goto out;
0915     time_status &= ~STA_PPSJITTER;
0916 
0917     /*
0918      * A three-stage median filter is used to help denoise the PPS
0919      * time. The median sample becomes the time offset estimate; the
0920      * difference between the other two samples becomes the time
0921      * dispersion (jitter) estimate.
0922      */
0923     if (pps_tf[0].tv_nsec > pps_tf[1].tv_nsec) {
0924         if (pps_tf[1].tv_nsec > pps_tf[2].tv_nsec) {
0925             v_nsec = pps_tf[1].tv_nsec; /* 0 1 2 */
0926             u_nsec = pps_tf[0].tv_nsec - pps_tf[2].tv_nsec;
0927         } else if (pps_tf[2].tv_nsec > pps_tf[0].tv_nsec) {
0928             v_nsec = pps_tf[0].tv_nsec; /* 2 0 1 */
0929             u_nsec = pps_tf[2].tv_nsec - pps_tf[1].tv_nsec;
0930         } else {
0931             v_nsec = pps_tf[2].tv_nsec; /* 0 2 1 */
0932             u_nsec = pps_tf[0].tv_nsec - pps_tf[1].tv_nsec;
0933         }
0934     } else {
0935         if (pps_tf[1].tv_nsec < pps_tf[2].tv_nsec) {
0936             v_nsec = pps_tf[1].tv_nsec; /* 2 1 0 */
0937             u_nsec = pps_tf[2].tv_nsec - pps_tf[0].tv_nsec;
0938         } else if (pps_tf[2].tv_nsec < pps_tf[0].tv_nsec) {
0939             v_nsec = pps_tf[0].tv_nsec; /* 1 0 2 */
0940             u_nsec = pps_tf[1].tv_nsec - pps_tf[2].tv_nsec;
0941         } else {
0942             v_nsec = pps_tf[2].tv_nsec; /* 1 2 0 */
0943             u_nsec = pps_tf[1].tv_nsec - pps_tf[0].tv_nsec;
0944         }
0945     }
0946 
0947     /*
0948      * Nominal jitter is due to PPS signal noise and interrupt
0949      * latency. If it exceeds the popcorn threshold, the sample is
0950      * discarded. otherwise, if so enabled, the time offset is
0951      * updated. We can tolerate a modest loss of data here without
0952      * much degrading time accuracy.
0953      *
0954      * The measurements being checked here were made with the system
0955      * timecounter, so the popcorn threshold is not allowed to fall below
0956      * the number of nanoseconds in two ticks of the timecounter.  For a
0957      * timecounter running faster than 1 GHz the lower bound is 2ns, just
0958      * to avoid a nonsensical threshold of zero.
0959     */
0960     if (u_nsec > lmax(pps_jitter << PPS_POPCORN,
0961         2 * (NANOSECOND / (long)qmin(NANOSECOND, tc_getfrequency())))) {
0962         time_status |= STA_PPSJITTER;
0963         pps_jitcnt++;
0964     } else if (time_status & STA_PPSTIME) {
0965         time_monitor = -v_nsec;
0966         L_LINT(time_offset, time_monitor);
0967     }
0968     pps_jitter += (u_nsec - pps_jitter) >> PPS_FAVG;
0969     u_sec = pps_tf[0].tv_sec - pps_lastsec;
0970     if (u_sec < (1 << pps_shift))
0971         goto out;
0972 
0973     /*
0974      * At the end of the calibration interval the difference between
0975      * the first and last counter values becomes the scaled
0976      * frequency. It will later be divided by the length of the
0977      * interval to determine the frequency update. If the frequency
0978      * exceeds a sanity threshold, or if the actual calibration
0979      * interval is not equal to the expected length, the data are
0980      * discarded. We can tolerate a modest loss of data here without
0981      * much degrading frequency accuracy.
0982      */
0983     pps_calcnt++;
0984     v_nsec = -pps_fcount;
0985     pps_lastsec = pps_tf[0].tv_sec;
0986     pps_fcount = 0;
0987     u_nsec = MAXFREQ << pps_shift;
0988     if (v_nsec > u_nsec || v_nsec < -u_nsec || u_sec != (1 << pps_shift)) {
0989         time_status |= STA_PPSERROR;
0990         pps_errcnt++;
0991         goto out;
0992     }
0993 
0994     /*
0995      * Here the raw frequency offset and wander (stability) is
0996      * calculated. If the wander is less than the wander threshold
0997      * for four consecutive averaging intervals, the interval is
0998      * doubled; if it is greater than the threshold for four
0999      * consecutive intervals, the interval is halved. The scaled
1000      * frequency offset is converted to frequency offset. The
1001      * stability metric is calculated as the average of recent
1002      * frequency changes, but is used only for performance
1003      * monitoring.
1004      */
1005     L_LINT(ftemp, v_nsec);
1006     L_RSHIFT(ftemp, pps_shift);
1007     L_SUB(ftemp, pps_freq);
1008     u_nsec = L_GINT(ftemp);
1009     if (u_nsec > PPS_MAXWANDER) {
1010         L_LINT(ftemp, PPS_MAXWANDER);
1011         pps_intcnt--;
1012         time_status |= STA_PPSWANDER;
1013         pps_stbcnt++;
1014     } else if (u_nsec < -PPS_MAXWANDER) {
1015         L_LINT(ftemp, -PPS_MAXWANDER);
1016         pps_intcnt--;
1017         time_status |= STA_PPSWANDER;
1018         pps_stbcnt++;
1019     } else {
1020         pps_intcnt++;
1021     }
1022     if (pps_intcnt >= 4) {
1023         pps_intcnt = 4;
1024         if (pps_shift < pps_shiftmax) {
1025             pps_shift++;
1026             pps_intcnt = 0;
1027         }
1028     } else if (pps_intcnt <= -4 || pps_shift > pps_shiftmax) {
1029         pps_intcnt = -4;
1030         if (pps_shift > PPS_FAVG) {
1031             pps_shift--;
1032             pps_intcnt = 0;
1033         }
1034     }
1035     if (u_nsec < 0)
1036         u_nsec = -u_nsec;
1037     pps_stabil += (u_nsec * SCALE_PPM - pps_stabil) >> PPS_FAVG;
1038 
1039     /*
1040      * The PPS frequency is recalculated and clamped to the maximum
1041      * MAXFREQ. If enabled, the system clock frequency is updated as
1042      * well.
1043      */
1044     L_ADD(pps_freq, ftemp);
1045     u_nsec = L_GINT(pps_freq);
1046     if (u_nsec > MAXFREQ)
1047         L_LINT(pps_freq, MAXFREQ);
1048     else if (u_nsec < -MAXFREQ)
1049         L_LINT(pps_freq, -MAXFREQ);
1050     if (time_status & STA_PPSFREQ)
1051         time_freq = pps_freq;
1052 
1053 out:
1054     NTP_UNLOCK();
1055 }
1056 #endif /* PPS_SYNC */
1057 
1058 #ifndef __rtems__
1059 #ifndef _SYS_SYSPROTO_H_
1060 struct adjtime_args {
1061     struct timeval *delta;
1062     struct timeval *olddelta;
1063 };
1064 #endif
1065 /* ARGSUSED */
1066 int
1067 sys_adjtime(struct thread *td, struct adjtime_args *uap)
1068 {
1069     struct timeval delta, olddelta, *deltap;
1070     int error;
1071 
1072     if (uap->delta) {
1073         error = copyin(uap->delta, &delta, sizeof(delta));
1074         if (error)
1075             return (error);
1076         deltap = &delta;
1077     } else
1078         deltap = NULL;
1079     error = kern_adjtime(td, deltap, &olddelta);
1080     if (uap->olddelta && error == 0)
1081         error = copyout(&olddelta, uap->olddelta, sizeof(olddelta));
1082     return (error);
1083 }
1084 
1085 int
1086 kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta)
1087 #else /* __rtems__ */
1088 static int
1089 kern_adjtime(const struct timeval *delta, struct timeval *olddelta)
1090 #endif /* __rtems__ */
1091 {
1092     struct timeval atv;
1093     int64_t ltr, ltw;
1094 #ifndef __rtems__
1095     int error;
1096 #endif /* __rtems__ */
1097 
1098     if (delta != NULL) {
1099 #ifndef __rtems__
1100         error = priv_check(td, PRIV_ADJTIME);
1101         if (error != 0)
1102             return (error);
1103 #endif /* __rtems__ */
1104         ltw = (int64_t)delta->tv_sec * 1000000 + delta->tv_usec;
1105     }
1106     NTP_LOCK();
1107     ltr = time_adjtime;
1108     if (delta != NULL)
1109         time_adjtime = ltw;
1110     NTP_UNLOCK();
1111     if (olddelta != NULL) {
1112         atv.tv_sec = ltr / 1000000;
1113         atv.tv_usec = ltr % 1000000;
1114         if (atv.tv_usec < 0) {
1115             atv.tv_usec += 1000000;
1116             atv.tv_sec--;
1117         }
1118         *olddelta = atv;
1119     }
1120     return (0);
1121 }
1122 #ifdef __rtems__
1123 int
1124 adjtime(const struct timeval *delta, struct timeval *olddelta)
1125 {
1126     int error;
1127 
1128     error = kern_adjtime(delta, olddelta);
1129     _Assert_Unused_variable_equals(error, 0);
1130     return (0);
1131 }
1132 #endif /* __rtems__ */
1133 
1134 #ifndef __rtems__
1135 static struct callout resettodr_callout;
1136 static int resettodr_period = 1800;
1137 
1138 static void
1139 periodic_resettodr(void *arg __unused)
1140 {
1141 
1142     /*
1143      * Read of time_status is lock-less, which is fine since
1144      * ntp_is_time_error() operates on the consistent read value.
1145      */
1146     if (!ntp_is_time_error(time_status))
1147         resettodr();
1148     if (resettodr_period > 0)
1149         callout_schedule(&resettodr_callout, resettodr_period * hz);
1150 }
1151 
1152 static void
1153 shutdown_resettodr(void *arg __unused, int howto __unused)
1154 {
1155 
1156     callout_drain(&resettodr_callout);
1157     /* Another unlocked read of time_status */
1158     if (resettodr_period > 0 && !ntp_is_time_error(time_status))
1159         resettodr();
1160 }
1161 
1162 static int
1163 sysctl_resettodr_period(SYSCTL_HANDLER_ARGS)
1164 {
1165     int error;
1166 
1167     error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
1168     if (error || !req->newptr)
1169         return (error);
1170     if (cold)
1171         goto done;
1172     if (resettodr_period == 0)
1173         callout_stop(&resettodr_callout);
1174     else
1175         callout_reset(&resettodr_callout, resettodr_period * hz,
1176             periodic_resettodr, NULL);
1177 done:
1178     return (0);
1179 }
1180 
1181 SYSCTL_PROC(_machdep, OID_AUTO, rtc_save_period, CTLTYPE_INT | CTLFLAG_RWTUN |
1182     CTLFLAG_MPSAFE, &resettodr_period, 1800, sysctl_resettodr_period, "I",
1183     "Save system time to RTC with this period (in seconds)");
1184 
1185 static void
1186 start_periodic_resettodr(void *arg __unused)
1187 {
1188 
1189     EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_resettodr, NULL,
1190         SHUTDOWN_PRI_FIRST);
1191     callout_init(&resettodr_callout, 1);
1192     if (resettodr_period == 0)
1193         return;
1194     callout_reset(&resettodr_callout, resettodr_period * hz,
1195         periodic_resettodr, NULL);
1196 }
1197 
1198 SYSINIT(periodic_resettodr, SI_SUB_LAST, SI_ORDER_MIDDLE,
1199     start_periodic_resettodr, NULL);
1200 #endif /* __rtems__ */