patch-1.3.28 linux/kernel/time.c
Next file: linux/mm/kmalloc.c
Previous file: linux/kernel/sys.c
Back to the patch index
Back to the overall index
- Lines: 239
- Date:
Fri Sep 15 10:59:45 1995
- Orig file:
v1.3.27/linux/kernel/time.c
- Orig date:
Sun Sep 3 12:27:04 1995
diff -u --recursive --new-file v1.3.27/linux/kernel/time.c linux/kernel/time.c
@@ -19,10 +19,8 @@
* 1995-03-26 Markus Kuhn
* fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
* precision CMOS clock update
- *
- * to do: adjtimex() has to be updated to recent (1994-12-13) revision
- * of David Mill's kernel clock model. For more information, check
- * <ftp://louie.udel.edu/pub/ntp/kernel.tar.Z>.
+ * 1995-08-13 Torsten Duwe
+ * kernel PLL updated to 1994-12-13 specs (rfc-1489)
*/
#include <linux/errno.h>
@@ -150,7 +148,7 @@
cli();
xtime.tv_sec = value;
xtime.tv_usec = 0;
- time_status = TIME_BAD;
+ time_state = TIME_BAD;
time_maxerror = 0x70000000;
time_esterror = 0x70000000;
sti();
@@ -330,7 +328,7 @@
}
xtime = new_tv;
- time_status = TIME_BAD;
+ time_state = TIME_BAD;
time_maxerror = 0x70000000;
time_esterror = 0x70000000;
sti();
@@ -338,6 +336,24 @@
return 0;
}
+long pps_offset = 0; /* pps time offset (us) */
+long pps_jitter = MAXTIME; /* time dispersion (jitter) (us) */
+
+long pps_freq = 0; /* frequency offset (scaled ppm) */
+long pps_stabil = MAXFREQ; /* frequency dispersion (scaled ppm) */
+
+long pps_valid = PPS_VALID; /* pps signal watchdog counter */
+
+int pps_shift = PPS_SHIFT; /* interval duration (s) (shift) */
+
+long pps_jitcnt = 0; /* jitter limit exceeded */
+long pps_calcnt = 0; /* calibration intervals */
+long pps_errcnt = 0; /* calibration errors */
+long pps_stbcnt = 0; /* stability limit exceeded */
+
+/* hook for a loadable hardpps kernel module */
+void (*hardpps_ptr)(struct timeval *) = (void (*)(struct timeval *))0;
+
/* adjtimex mainly allows reading (and writing, if superuser) of
* kernel time-keeping variables. used by xntpd.
*/
@@ -360,25 +376,19 @@
memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
/* In order to modify anything, you gotta be super-user! */
- if (txc.mode && !suser())
+ if (txc.modes && !suser())
return -EPERM;
/* Now we validate the data before disabling interrupts
*/
- if (txc.mode != ADJ_OFFSET_SINGLESHOT && (txc.mode & ADJ_OFFSET))
- /* Microsec field limited to -131000 .. 131000 usecs */
- if (txc.offset <= -(1 << (31 - SHIFT_UPDATE))
- || txc.offset >= (1 << (31 - SHIFT_UPDATE)))
- return -EINVAL;
-
- /* time_status must be in a fairly small range */
- if (txc.mode & ADJ_STATUS)
- if (txc.status < TIME_OK || txc.status > TIME_BAD)
+ if (txc.modes != ADJ_OFFSET_SINGLESHOT && (txc.modes & ADJ_OFFSET))
+ /* adjustment Offset limited to +- .512 seconds */
+ if (txc.offset <= - MAXPHASE || txc.offset >= MAXPHASE )
return -EINVAL;
/* if the quartz is off by more than 10% something is VERY wrong ! */
- if (txc.mode & ADJ_TICK)
+ if (txc.modes & ADJ_TICK)
if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
return -EINVAL;
@@ -388,72 +398,118 @@
save_adjust = time_adjust;
/* If there are input parameters, then process them */
- if (txc.mode)
+ if (txc.modes)
{
- if (time_status == TIME_BAD)
- time_status = TIME_OK;
+ if (time_state == TIME_BAD)
+ time_state = TIME_OK;
- if (txc.mode & ADJ_STATUS)
+ if (txc.modes & ADJ_STATUS)
time_status = txc.status;
- if (txc.mode & ADJ_FREQUENCY)
- time_freq = txc.frequency << (SHIFT_KF - 16);
+ if (txc.modes & ADJ_FREQUENCY)
+ time_freq = txc.freq;
- if (txc.mode & ADJ_MAXERROR)
+ if (txc.modes & ADJ_MAXERROR)
time_maxerror = txc.maxerror;
- if (txc.mode & ADJ_ESTERROR)
+ if (txc.modes & ADJ_ESTERROR)
time_esterror = txc.esterror;
- if (txc.mode & ADJ_TIMECONST)
- time_constant = txc.time_constant;
+ if (txc.modes & ADJ_TIMECONST)
+ time_constant = txc.constant;
- if (txc.mode & ADJ_OFFSET)
- if (txc.mode == ADJ_OFFSET_SINGLESHOT)
+ if (txc.modes & ADJ_OFFSET)
+ if ((txc.modes == ADJ_OFFSET_SINGLESHOT)
+ || !(time_status & STA_PLL))
{
time_adjust = txc.offset;
}
- else /* XXX should give an error if other bits set */
+ else if ((time_status & STA_PLL)||(time_status & STA_PPSTIME))
{
- time_offset = txc.offset << SHIFT_UPDATE;
- mtemp = xtime.tv_sec - time_reftime;
- time_reftime = xtime.tv_sec;
- if (mtemp > (MAXSEC+2) || mtemp < 0)
- mtemp = 0;
-
- if (txc.offset < 0)
- time_freq -= (-txc.offset * mtemp) >>
- (time_constant + time_constant);
+ ltemp = (time_status & STA_PPSTIME &&
+ time_status & STA_PPSSIGNAL) ?
+ pps_offset : txc.offset;
+
+ /*
+ * Scale the phase adjustment and
+ * clamp to the operating range.
+ */
+ if (ltemp > MAXPHASE)
+ time_offset = MAXPHASE << SHIFT_UPDATE;
+ else if (ltemp < -MAXPHASE)
+ time_offset = -(MAXPHASE << SHIFT_UPDATE);
else
- time_freq += (txc.offset * mtemp) >>
- (time_constant + time_constant);
+ time_offset = ltemp << SHIFT_UPDATE;
- ltemp = time_tolerance << SHIFT_KF;
+ /*
+ * Select whether the frequency is to be controlled and in which
+ * mode (PLL or FLL). Clamp to the operating range. Ugly
+ * multiply/divide should be replaced someday.
+ */
- if (time_freq > ltemp)
- time_freq = ltemp;
- else if (time_freq < -ltemp)
- time_freq = -ltemp;
+ if (time_status & STA_FREQHOLD || time_reftime == 0)
+ time_reftime = xtime.tv_sec;
+ mtemp = xtime.tv_sec - time_reftime;
+ time_reftime = xtime.tv_sec;
+ if (time_status & STA_FLL)
+ {
+ if (mtemp >= MINSEC)
+ {
+ ltemp = ((time_offset / mtemp) << (SHIFT_USEC -
+ SHIFT_UPDATE));
+ if (ltemp < 0)
+ time_freq -= -ltemp >> SHIFT_KH;
+ else
+ time_freq += ltemp >> SHIFT_KH;
+ }
+ }
+ else
+ {
+ if (mtemp < MAXSEC)
+ {
+ ltemp *= mtemp;
+ if (ltemp < 0)
+ time_freq -= -ltemp >> (time_constant +
+ time_constant + SHIFT_KF -
+ SHIFT_USEC);
+ else
+ time_freq += ltemp >> (time_constant +
+ time_constant + SHIFT_KF -
+ SHIFT_USEC);
+ }
+ }
+ if (time_freq > time_tolerance)
+ time_freq = time_tolerance;
+ else if (time_freq < -time_tolerance)
+ time_freq = -time_tolerance;
}
- if (txc.mode & ADJ_TICK)
+ if (txc.modes & ADJ_TICK)
tick = txc.tick;
}
txc.offset = save_adjust;
- txc.frequency = ((time_freq+1) >> (SHIFT_KF - 16));
+ txc.freq = time_freq;
txc.maxerror = time_maxerror;
txc.esterror = time_esterror;
txc.status = time_status;
- txc.time_constant = time_constant;
+ txc.constant = time_constant;
txc.precision = time_precision;
txc.tolerance = time_tolerance;
txc.time = xtime;
txc.tick = tick;
+ txc.ppsfreq = pps_freq;
+ txc.jitter = pps_jitter;
+ txc.shift = pps_shift;
+ txc.stabil = pps_stabil;
+ txc.jitcnt = pps_jitcnt;
+ txc.calcnt = pps_calcnt;
+ txc.errcnt = pps_errcnt;
+ txc.stbcnt = pps_stbcnt;
sti();
memcpy_tofs(txc_p, &txc, sizeof(struct timex));
- return time_status;
+ return time_state;
}
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this