Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Extend kernel PPS api with pps_ref_event().
details: https://anonhg.NetBSD.org/src/rev/bc59d9d35809
branches: trunk
changeset: 786975:bc59d9d35809
user: kardel <kardel%NetBSD.org@localhost>
date: Sun May 26 18:07:42 2013 +0000
description:
Extend kernel PPS api with pps_ref_event().
pps_ref_event() allows capturing PPS time stamps
that are not generated at precisely 1Hz (e. g.
by reading a precision clock via callout()).
This extension allows clock drivers to supply PPS
time-stamps and drive the kernel NTP PLL
without the overhead of interrupt-handling and
-processing.
diffstat:
sys/conf/files | 4 +-
sys/kern/kern_tc.c | 295 +++++++++++++++++++++++++++++++++++++++++++++++-----
sys/sys/timepps.h | 13 ++-
3 files changed, 280 insertions(+), 32 deletions(-)
diffs (truncated from 464 to 300 lines):
diff -r 01aab8d68b63 -r bc59d9d35809 sys/conf/files
--- a/sys/conf/files Sun May 26 17:25:53 2013 +0000
+++ b/sys/conf/files Sun May 26 18:07:42 2013 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1070 2013/04/28 03:11:32 christos Exp $
+# $NetBSD: files,v 1.1071 2013/05/26 18:07:42 kardel Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20100430
@@ -64,7 +64,7 @@
defflag opt_sysv.h SYSVMSG SYSVSEM SYSVSHM
defparam opt_sysvparam.h SHMMAXPGS SEMMNI SEMMNS SEMUME SEMMNU
-defflag opt_ntp.h PPS_SYNC NTP
+defflag opt_ntp.h PPS_SYNC PPS_DEBUG NTP
defflag opt_ptm.h NO_DEV_PTM COMPAT_BSDPTY
diff -r 01aab8d68b63 -r bc59d9d35809 sys/kern/kern_tc.c
--- a/sys/kern/kern_tc.c Sun May 26 17:25:53 2013 +0000
+++ b/sys/kern/kern_tc.c Sun May 26 18:07:42 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_tc.c,v 1.44 2012/11/13 20:10:02 pooka Exp $ */
+/* $NetBSD: kern_tc.c,v 1.45 2013/05/26 18:07:42 kardel Exp $ */
/*-
* Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -40,7 +40,7 @@
#include <sys/cdefs.h>
/* __FBSDID("$FreeBSD: src/sys/kern/kern_tc.c,v 1.166 2005/09/19 22:16:31 andre Exp $"); */
-__KERNEL_RCSID(0, "$NetBSD: kern_tc.c,v 1.44 2012/11/13 20:10:02 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_tc.c,v 1.45 2013/05/26 18:07:42 kardel Exp $");
#ifdef _KERNEL_OPT
#include "opt_ntp.h"
@@ -688,7 +688,8 @@
if (timestepwarnings) {
bintime2timespec(&bt2, &ts2);
- log(LOG_INFO, "Time stepped from %lld.%09ld to %lld.%09ld\n",
+ log(LOG_INFO,
+ "Time stepped from %lld.%09ld to %lld.%09ld\n",
(long long)ts2.tv_sec, ts2.tv_nsec,
(long long)ts->tv_sec, ts->tv_nsec);
}
@@ -859,7 +860,8 @@
KASSERT(mutex_owned(&timecounter_lock));
- KASSERT(pps != NULL); /* XXX ("NULL pps pointer in pps_ioctl") */
+ KASSERT(pps != NULL);
+
switch (cmd) {
case PPS_IOC_CREATE:
return (0);
@@ -913,6 +915,9 @@
pps->ppscap |= PPS_OFFSETCLEAR;
}
+/*
+ * capture a timetamp in the pps structure
+ */
void
pps_capture(struct pps_state *pps)
{
@@ -929,72 +934,223 @@
pps->capgen = 0;
}
+#ifdef PPS_DEBUG
+int ppsdebug = 0;
+#endif
+
+/*
+ * process a pps_capture()ed event
+ */
void
pps_event(struct pps_state *pps, int event)
{
- struct bintime bt;
+ pps_ref_event(pps, event, NULL, PPS_REFEVNT_PPS|PPS_REFEVNT_CAPTURE);
+}
+
+/*
+ * extended pps api / kernel pll/fll entry point
+ *
+ * feed reference time stamps to PPS engine
+ *
+ * will simulate a PPS event and feed
+ * the NTP PLL/FLL if requested.
+ *
+ * the ref time stamps should be roughly once
+ * a second but do not need to be exactly in phase
+ * with the UTC second but should be close to it.
+ * this relaxation of requirements allows callout
+ * driven timestamping mechanisms to feed to pps
+ * capture/kernel pll logic.
+ *
+ * calling pattern is:
+ * pps_capture() (for PPS_REFEVNT_{CAPTURE|CAPCUR})
+ * read timestamp from reference source
+ * pps_ref_event()
+ *
+ * supported refmodes:
+ * PPS_REFEVNT_CAPTURE
+ * use system timestamp of pps_capture()
+ * PPS_REFEVNT_CURRENT
+ * use system timestamp of this call
+ * PPS_REFEVNT_CAPCUR
+ * use average of read capture and current system time stamp
+ * PPS_REFEVNT_PPS
+ * assume timestamp on second mark - ref_ts is ignored
+ *
+ */
+
+void
+pps_ref_event(struct pps_state *pps,
+ int event,
+ struct bintime *ref_ts,
+ int refmode
+ )
+{
+ struct bintime bt; /* current time */
+ struct bintime btd; /* time difference */
+ struct bintime bt_ref; /* reference time */
struct timespec ts, *tsp, *osp;
- u_int64_t tcount, *pcount;
- int foff;
-#ifdef PPS_SYNC
- int fhard;
-#endif
+ struct timehands *th;
+ u_int64_t tcount, acount, dcount, *pcount;
+ int foff, fhard, gen;
pps_seq_t *pseq;
KASSERT(mutex_owned(&timecounter_lock));
- KASSERT(pps != NULL); /* XXX ("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;
+ KASSERT(pps != NULL);
+
+ /* pick up current time stamp if needed */
+ if (refmode & (PPS_REFEVNT_CURRENT|PPS_REFEVNT_CAPCUR)) {
+ /* pick up current time stamp */
+ th = timehands;
+ gen = th->th_generation;
+ tcount = (u_int64_t)tc_delta(th) + th->th_offset_count;
+ if (gen != th->th_generation)
+ gen = 0;
- /* Things would be easier with arrays. */
+ /* If the timecounter was wound up underneath us, bail out. */
+ if (pps->capgen == 0 ||
+ pps->capgen != pps->capth->th_generation ||
+ gen == 0 ||
+ gen != pps->capgen) {
+#ifdef PPS_DEBUG
+ if (ppsdebug & 0x1) {
+ log(LOG_DEBUG,
+ "pps_ref_event(pps=%p, event=%d, ...): DROP (wind-up)\n",
+ pps, event);
+ }
+#endif
+ return;
+ }
+ } else {
+ tcount = 0; /* keep GCC happy */
+ }
+
+#ifdef PPS_DEBUG
+ if (ppsdebug & 0x1) {
+ struct timespec tmsp;
+
+ if (ref_ts == NULL) {
+ tmsp.tv_sec = 0;
+ tmsp.tv_nsec = 0;
+ } else {
+ bintime2timespec(ref_ts, &tmsp);
+ }
+
+ log(LOG_DEBUG,
+ "pps_ref_event(pps=%p, event=%d, ref_ts=%"PRIi64
+ ".%09"PRIi32", refmode=0x%1x)\n",
+ pps, event, tmsp.tv_sec, (int32_t)tmsp.tv_nsec, refmode);
+ }
+#endif
+
+ /* setup correct event references */
if (event == PPS_CAPTUREASSERT) {
tsp = &pps->ppsinfo.assert_timestamp;
osp = &pps->ppsparam.assert_offset;
foff = pps->ppsparam.mode & PPS_OFFSETASSERT;
-#ifdef PPS_SYNC
fhard = pps->kcmode & PPS_CAPTUREASSERT;
-#endif
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;
-#ifdef PPS_SYNC
fhard = pps->kcmode & PPS_CAPTURECLEAR;
-#endif
pcount = &pps->ppscount[1];
pseq = &pps->ppsinfo.clear_sequence;
}
+ /* determine system time stamp according to refmode */
+ dcount = 0; /* keep GCC happy */
+ switch (refmode & PPS_REFEVNT_RMASK) {
+ case PPS_REFEVNT_CAPTURE:
+ acount = pps->capcount; /* use capture timestamp */
+ break;
+
+ case PPS_REFEVNT_CURRENT:
+ acount = tcount; /* use current timestamp */
+ break;
+
+ case PPS_REFEVNT_CAPCUR:
+ /*
+ * calculate counter value between pps_capture() and
+ * pps_ref_event()
+ */
+ dcount = tcount - pps->capcount;
+ acount = (dcount / 2) + pps->capcount;
+ break;
+
+ default: /* ignore call error silently */
+ return;
+ }
+
/*
* 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;
+ pps->capcount = acount;
+ *pcount = acount;
+ pps->ppscount[2] = acount;
+#ifdef PPS_DEBUG
+ if (ppsdebug & 0x1) {
+ log(LOG_DEBUG,
+ "pps_ref_event(pps=%p, event=%d, ...): DROP (time-counter change)\n",
+ pps, event);
+ }
+#endif
return;
}
- /* Convert the count to a timespec. */
- tcount = pps->capcount - pps->capth->th_offset_count;
+ pps->capcount = acount;
+
+ /* Convert the count to a bintime. */
bt = pps->capth->th_offset;
- bintime_addx(&bt, pps->capth->th_scale * tcount);
+ bintime_addx(&bt, pps->capth->th_scale * (acount - pps->capth->th_offset_count));
bintime_add(&bt, &timebasebin);
+
+ if ((refmode & PPS_REFEVNT_PPS) == 0) {
+ /* determine difference to reference time stamp */
+ bt_ref = *ref_ts;
+
+ btd = bt;
+ bintime_sub(&btd, &bt_ref);
+
+ /*
+ * simulate a PPS timestamp by dropping the fraction
+ * and applying the offset
+ */
+ if (bt.frac >= (uint64_t)1<<63) /* skip to nearest second */
+ bt.sec++;
+ bt.frac = 0;
+ bintime_add(&bt, &btd);
+ } else {
+ /*
+ * create ref_ts from current time -
+ * we are supposed to be called on
+ * the second mark
+ */
+ bt_ref = bt;
+ if (bt_ref.frac >= (uint64_t)1<<63) /* skip to nearest second */
+ bt_ref.sec++;
+ bt_ref.frac = 0;
+ }
+
+ /* convert bintime to timestamp */
bintime2timespec(&bt, &ts);
/* If the timecounter was wound up underneath us, bail out. */
if (pps->capgen != pps->capth->th_generation)
return;
Home |
Main Index |
Thread Index |
Old Index