summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_clock.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1999-03-11 15:09:51 +0000
committerphk <phk@FreeBSD.org>1999-03-11 15:09:51 +0000
commit1542a4a4974b31d78a2115e37a802c377265be93 (patch)
tree59c54f6ab6826395ea6c20a6d0d12cb2be4bc943 /sys/kern/kern_clock.c
parent9c47f49734c0ff3b3d666a5a7a2bb329444223f1 (diff)
downloadFreeBSD-src-1542a4a4974b31d78a2115e37a802c377265be93.zip
FreeBSD-src-1542a4a4974b31d78a2115e37a802c377265be93.tar.gz
Make even more of the PPSAPI implementations generic.
FLL support in hardpps() Various magic shuffles and improved comments Style fixes from Bruce.
Diffstat (limited to 'sys/kern/kern_clock.c')
-rw-r--r--sys/kern/kern_clock.c199
1 files changed, 147 insertions, 52 deletions
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index 1c536ee..da424e5 100644
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -37,9 +37,11 @@
* SUCH DAMAGE.
*
* @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
- * $Id: kern_clock.c,v 1.88 1999/02/19 19:34:49 luoqi Exp $
+ * $Id: kern_clock.c,v 1.89 1999/03/08 12:35:58 phk Exp $
*/
+#include "opt_ntp.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/dkstat.h>
@@ -50,6 +52,7 @@
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/timex.h>
+#include <sys/timepps.h>
#include <vm/vm.h>
#include <sys/lock.h>
#include <vm/pmap.h>
@@ -509,11 +512,14 @@ tco_delta(struct timecounter *tc)
}
/*
- * We have four functions for looking at the clock, two for microseconds
- * and two for nanoseconds. For each there is fast but less precise
- * version "get{nano|micro}time" which will return a time which is up
- * to 1/HZ previous to the call, whereas the raw version "{nano|micro}time"
- * will return a timestamp which is as precise as possible.
+ * We have eight functions for looking at the clock, four for
+ * microseconds and four for nanoseconds. For each there is fast
+ * but less precise version "get{nano|micro}[up]time" which will
+ * return a time which is up to 1/HZ previous to the call, whereas
+ * the raw version "{nano|micro}[up]time" will return a timestamp
+ * which is as precise as possible. The "up" variants return the
+ * time relative to system boot, these are well suited for time
+ * interval measurements.
*/
void
@@ -583,29 +589,6 @@ nanotime(struct timespec *ts)
}
void
-timecounter_timespec(unsigned count, struct timespec *ts)
-{
- u_int64_t delta;
- struct timecounter *tc;
-
- tc = (struct timecounter *)timecounter;
- ts->tv_sec = tc->tc_offset_sec;
- count -= tc->tc_offset_count;
- count &= tc->tc_counter_mask;
- delta = tc->tc_offset_nano;
- delta += ((u_int64_t)count * tc->tc_scale_nano_f);
- delta >>= 32;
- delta += ((u_int64_t)count * tc->tc_scale_nano_i);
- delta += boottime.tv_usec * 1000;
- ts->tv_sec += boottime.tv_sec;
- while (delta >= 1000000000) {
- delta -= 1000000000;
- ts->tv_sec++;
- }
- ts->tv_nsec = delta;
-}
-
-void
getmicrouptime(struct timeval *tvp)
{
struct timecounter *tc;
@@ -805,8 +788,6 @@ tco_forward(int force)
while (tc->tc_offset_nano >= 1000000000ULL << 32) {
tc->tc_offset_nano -= 1000000000ULL << 32;
tc->tc_offset_sec++;
- tc->tc_frequency = tc->tc_tweak->tc_frequency;
- tc->tc_adjustment = tc->tc_tweak->tc_adjustment;
ntp_update_second(tc); /* XXX only needed if xntpd runs */
tco_setscales(tc);
force++;
@@ -832,35 +813,149 @@ tco_forward(int force)
timecounter = tc;
}
-static int
-sysctl_kern_timecounter_frequency SYSCTL_HANDLER_ARGS
+SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
+
+SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 0,
+ "This variable determines the method used for updating timecounters. "
+ "If the default algorithm (0) fails with \"calcru negative...\" messages "
+ "try the alternate algorithm (1) which handles bad hardware better."
+
+);
+
+
+int
+pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps)
{
+ pps_params_t *app;
+ pps_info_t *api;
+
+ 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;
+ return (0);
+ case PPS_IOC_GETCAP:
+ *(int*)data = pps->ppscap;
+ return (0);
+ case PPS_IOC_FETCH:
+ api = (pps_info_t *)data;
+ pps->ppsinfo.current_mode = pps->ppsparam.mode;
+ *api = pps->ppsinfo;
+ return (0);
+ case PPS_IOC_WAIT:
+ return (EOPNOTSUPP);
+ default:
+ return (ENOTTY);
+ }
+}
- return (sysctl_handle_opaque(oidp,
- &timecounter->tc_tweak->tc_frequency,
- sizeof(timecounter->tc_tweak->tc_frequency), req));
+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;
+#ifdef PPS_SYNC
+ if (pps->ppscap & PPS_CAPTUREASSERT)
+ pps->ppscap |= PPS_HARDPPSONASSERT;
+ if (pps->ppscap & PPS_CAPTURECLEAR)
+ pps->ppscap |= PPS_HARDPPSONCLEAR;
+#endif
}
-static int
-sysctl_kern_timecounter_adjustment SYSCTL_HANDLER_ARGS
+void
+pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event)
{
+ struct timespec ts, *tsp, *osp;
+ u_int64_t delta;
+ unsigned tcount, *pcount;
+ int foff, fhard;
+ pps_seq_t *pseq;
+
+ /* 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->ppsparam.mode & PPS_HARDPPSONASSERT;
+ 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->ppsparam.mode & PPS_HARDPPSONCLEAR;
+ pcount = &pps->ppscount[1];
+ pseq = &pps->ppsinfo.clear_sequence;
+ }
- return (sysctl_handle_opaque(oidp,
- &timecounter->tc_tweak->tc_adjustment,
- sizeof(timecounter->tc_tweak->tc_adjustment), req));
-}
+ /* The timecounter changed: bail */
+ if (!pps->ppstc ||
+ pps->ppstc->tc_name != tc->tc_name ||
+ tc->tc_name != timecounter->tc_name) {
+ pps->ppstc = tc;
+ *pcount = count;
+ return;
+ }
-SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, "");
+ /* Now, make sure we have the right instance */
+ tc = timecounter;
-SYSCTL_INT(_kern_timecounter, KERN_ARGMAX, method, CTLFLAG_RW, &tco_method, 0,
- "This variable determines the method used for updating timecounters. "
- "If the default algorithm (0) fails with \"calcru negative...\" messages "
- "try the alternate algorithm (1) which handles bad hardware better."
+ /* Nothing really happened */
+ if (*pcount == count)
+ return;
-);
+ *pcount = count;
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, frequency, CTLTYPE_INT | CTLFLAG_RW,
- 0, sizeof(u_int), sysctl_kern_timecounter_frequency, "I", "");
+ /* Convert the count to timespec */
+ ts.tv_sec = tc->tc_offset_sec;
+ tcount = count - tc->tc_offset_count;
+ tcount &= tc->tc_counter_mask;
+ delta = tc->tc_offset_nano;
+ delta += ((u_int64_t)tcount * tc->tc_scale_nano_f);
+ delta >>= 32;
+ delta += ((u_int64_t)tcount * tc->tc_scale_nano_i);
+ delta += boottime.tv_usec * 1000;
+ ts.tv_sec += boottime.tv_sec;
+ while (delta >= 1000000000) {
+ delta -= 1000000000;
+ ts.tv_sec++;
+ }
+ ts.tv_nsec = delta;
+
+ (*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) {
+ /* magic, at its best... */
+ tcount = count - pps->ppscount[2];
+ pps->ppscount[2] = count;
+ tcount &= tc->tc_counter_mask;
+ delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f);
+ delta >>= 32;
+ delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i);
+ hardpps(tsp, delta);
+ }
+#endif
+}
-SYSCTL_PROC(_kern_timecounter, OID_AUTO, adjustment, CTLTYPE_INT | CTLFLAG_RW,
- 0, sizeof(int), sysctl_kern_timecounter_adjustment, "I", "");
OpenPOWER on IntegriCloud