<commit_before>FFclock core

Core set of changes to support a feed-forward clock within the kernel.

---
 conf/NOTES     |   10 ++
 conf/options   |    1 
 kern/kern_tc.c |  250 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/time.h     |   46 ++++++++++
 4 files changed, 307 insertions(+)

Index: sys/kern/kern_tc.c
===================================================================
--- sys.orig/kern/kern_tc.c	2010-12-19 03:50:04.000000000 +1100
+++ sys/kern/kern_tc.c	2010-12-19 08:58:07.000000000 +1100
@@ -5,6 +5,12 @@
  * 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.   <NAME>
  * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010 The University of Melbourne
+ * All rights reserved.
+ *
+ * Portions of this software were developed by the University of Melbourne
+ * under sponsorship from the FreeBSD Foundation.
  */
 
 #include <sys/cdefs.h>
@@ -21,6 +27,12 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_tc
 #include <sys/timetc.h>
 #include <sys/timex.h>
 
+#ifdef FFCLOCK
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#endif	/* FFCLOCK */
+
 /*
  * A large step happens on boot.  This constant detects such steps.
  * It is relatively small so that ntp_update_second gets called enough
@@ -53,6 +65,9 @@ struct timehands {
 	int64_t			th_adjustment;
 	uint64_t		th_scale;
 	u_int	 		th_offset_count;
+#ifdef FFCLOCK
+	ffcounter_t		ffcounter_record;
+#endif
 	struct bintime		th_offset;
 	struct timeval		th_microtime;
 	struct timespec		th_nanotime;
@@ -61,6 +76,30 @@ struct timehands {
 	struct timehands	*th_next;
 };
 
+#ifdef FFCLOCK
+static struct timehands th0;
+static struct timehands th9 = { NULL, 0, 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}, 0, &th9};
+static struct timehands th7 = { NULL, 0, 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}, 0, &th7};
+static struct timehands th5 = { NULL, 0, 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}, 0, &th5};
+static struct timehands th3 = { NULL, 0, 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}, 0, &th3};
+static struct timehands th1 = { NULL, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2};
+static struct timehands th0 = {
+	&dummy_timecounter,
+	0,
+	(uint64_t)-1 / 1000000,
+	0,
+	0,
+	{1, 0},
+	{0, 0},
+	{0, 0},
+	1,
+	&th1
+};
+#else
 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};
@@ -82,6 +121,7 @@ static struct timehands th0 = {
 	1,
 	&th1
 };
+#endif	/* FFCLOCK */
 
 static struct timehands *volatile timehands = &th0;
 struct timecounter *timecounter = &dummy_timecounter;
@@ -300,6 +340,200 @@ getmicrotime(struct timeval *tvp)
 	} while (gen == 0 || gen != th->th_generation);
 }
 
+
+#ifdef FFCLOCK
+
+/* Global data structure containing clock estimates */
+static struct feedforward_clock ffclock;
+
+
+MALLOC_DECLARE(M_FFCLOCK);
+MALLOC_DEFINE(M_FFCLOCK, "FFCLOCK", "Feed-Forward Clock estimates");
+
+
+static void
+init_ffclock(struct feedforward_clock *ffclock)
+{
+	unsigned long sz;
+	sz = sizeof(struct ffclock_estimate);
+
+	ffclock->updated = 0;
+	ffclock->cest	= (struct ffclock_estimate *) malloc(sz, M_FFCLOCK, M_WAITOK | M_ZERO);
+	ffclock->ocest	= (struct ffclock_estimate *) malloc(sz, M_FFCLOCK, M_WAITOK | M_ZERO);
+	ffclock->ucest	= (struct ffclock_estimate *) malloc(sz, M_FFCLOCK, M_WAITOK | M_ZERO);
+}
+
+
+/*
+ * We need to have a boot time from the RTC clock or the like to get
+ * kickstarted. init_ffclock is called before inittodr(), so cannot put the code
+ * there. Need to be called from tc_setclock(), once only.
+ */
+static void
+reset_ffclock(struct feedforward_clock *ffclock, struct timehands *th)
+{
+	struct timecounter *tc;
+	struct ffclock_estimate *cest;
+	struct ffclock_data *cdata;
+	struct timespec ts;
+
+	cest = ffclock->ucest;
+	cdata = &(cest->cdata);
+
+	/*
+	 * If called with a timehand, the timecounter is being changed and we
+	 * restart fresh. If not, the clock is being set from tc_setclock (note that
+	 * this may occur several times during boot).
+	 */
+	if (th) {
+		th->ffcounter_record = 0;
+		cdata->ffcounter = 0;
+		tc = th->th_counter;
+	}
+	else {
+		/*
+		 * Strictly speaking, we should record the ffcounter when the RTC clock is
+		 * read from initoddr(), but not worse the trouble (is RTC trustworthy
+		 * anyway?). Let's keep it simple
+		 */
+		cdata->ffcounter = read_ffcounter();
+		tc = timehands->th_counter;
+	}
+
+	/* Need to hold enough seconds until 2038. Assume 32 bits container */
+	cdata->time.sec = boottimebin.sec;
+	cdata->time.frac = boottimebin.frac;
+
+	cdata->period = ((1LLU << 63) / tc->tc_frequency ) << 1;
+
+	cdata->status = 0;
+	cdata->error_bound_avg = 0;
+
+	if (++cest->gen == 0)
+		cest->gen = 1;
+
+	ffclock->ucest = ffclock->cest;
+	ffclock->cest = cest;
+
+	cdata = &(ffclock->cest->cdata);
+
+	bintime2timespec(&(cdata->time), &ts);
+	printf("reset_ffclock: %s - period = %llu (%llu Hz), time = %lu.%lu",
+			tc->tc_name,
+			(long long unsigned) cdata->period,
+			(long long unsigned) tc->tc_frequency,
+			(long unsigned) ts.tv_sec,
+			(long unsigned) ts.tv_nsec);
+}
+
+
+/*
+ * Update to prevent overflow. This is no adjustment of the clock parameters.
+ * Assumption: timehands is the current one
+ */
+static void
+update_ffclock(struct feedforward_clock *ffclock)
+{
+	struct ffclock_estimate *tmp;
+	struct ffclock_data *cdata;
+	struct timehands *th;
+	ffcounter_t ffdelta;
+	struct bintime delta;
+
+	/*
+	 * If the clock has been updated by the synchronisation daemon, this new
+	 * data is the more up to date one.
+	 */
+	if ( ffclock->updated )
+	{
+		ffclock->ucest->gen = ffclock->cest->gen;
+		if (++ffclock->ucest->gen == 0)
+			ffclock->ucest->gen = 1;
+
+		tmp = ffclock->cest;
+		ffclock->cest = ffclock->ucest;
+		ffclock->ucest = tmp;
+		ffclock->updated = 0;
+		return;
+	}
+
+	/* If we just changed the timecounter, we have nothing to do in here */
+	cdata = &(ffclock->cest->cdata);
+	th = timehands;
+	if ( cdata->ffcounter > th->ffcounter_record )
+		return;
+
+	/* Update time mark */
+	*(ffclock->ocest) = *(ffclock->cest);
+	cdata = &(ffclock->ocest->cdata);
+
+	ffdelta = th->ffcounter_record - cdata->ffcounter;
+
+	delta.sec = 0;
+	delta.frac = cdata->period;
+	bintime_mul(&delta, ffdelta);
+	bintime_add(&(cdata->time), &delta);
+
+	cdata->ffcounter = th->ffcounter_record;
+
+	if (++ffclock->ocest->gen == 0)
+		ffclock->ocest->gen = 1;
+
+	tmp = ffclock->cest;
+	ffclock->cest = ffclock->ocest;
+	ffclock->ocest = tmp;
+}
+
+
+
+void
+ffcounter2bintime(ffcounter_t *ffcounter, struct bintime *bt)
+{
+	struct ffclock_data *cdata;
+	ffcounter_t ffdelta;
+	struct bintime delta;
+	uint8_t gen;
+
+	/*
+	 * No locking to prevent clock data to be updated. Check that the generation
+	 * has not changed instead.
+	 */
+	do {
+		gen = ffclock.cest->gen;
+		cdata = &(ffclock.cest->cdata);
+
+		ffdelta = *ffcounter - cdata->ffcounter;
+		delta.sec = 0;
+		delta.frac = cdata->period;
+		bintime_mul(&delta, ffdelta);
+		bt->sec = cdata->time.sec;
+		bt->frac = cdata->time.frac;
+		bintime_add(bt, &delta);
+
+	} while (gen == 0 || gen != ffclock.cest->gen);
+}
+
+
+
+ffcounter_t
+read_ffcounter(void)
+{
+	struct timehands *th;
+	u_int gen, delta;
+	ffcounter_t ffcounter;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		delta = tc_delta(th);
+		ffcounter = th->ffcounter_record;
+	} while ( gen == 0 || gen != th->th_generation);
+
+	return(ffcounter + delta);
+}
+#endif	/* FFCLOCK */
+
+
 /*
  * Initialize a new timecounter and possibly use it.
  */
@@ -391,6 +625,10 @@ tc_setclock(struct timespec *ts)
 	boottimebin = bt;
 	bintime2timeval(&bt, &boottime);
 
+#ifdef FFCLOCK
+	reset_ffclock(&ffclock, NULL);
+#endif	/* FFCLOCK */
+
 	/* XXX fiddle all the little crinkly bits around the fiords... */
 	tc_windup();
 	nanotime(&taft);
@@ -440,6 +678,9 @@ tc_windup(void)
 		ncount = timecounter->tc_get_timecount(timecounter);
 	else
 		ncount = 0;
+#ifdef FFCLOCK
+	th->ffcounter_record += delta;
+#endif
 	th->th_offset_count += delta;
 	th->th_offset_count &= th->th_counter->tc_counter_mask;
 	while (delta > th->th_counter->tc_frequency) {
@@ -496,6 +737,9 @@ tc_windup(void)
 		th->th_offset_count = ncount;
 		tc_min_ticktock_freq = max(1, timecounter->tc_frequency /
 		    (((uint64_t)timecounter->tc_counter_mask + 1) / 3));
+#ifdef FFCLOCK
+		reset_ffclock(&ffclock, th);
+#endif
 	}
 
 	/*-
@@ -792,6 +1036,9 @@ tc_ticktock(int cnt)
 		return;
 	count = 0;
 	tc_windup();
+#ifdef FFCLOCK
+	update_ffclock(&ffclock);
+#endif
 }
 
 static void
@@ -814,6 +1061,9 @@ inittimecounter(void *dummy)
 	p = (tc_tick * 1000000) / hz;
 	printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000);
 
+#ifdef FFCLOCK
+	init_ffclock(&ffclock);
+#endif
 	/* warm up new timecounter (again) and get rolling. */
 	(void)timecounter->tc_get_timecount(timecounter);
 	(void)timecounter->tc_get_timecount(timecounter);
Index: sys/sys/time.h
===================================================================
--- sys.orig/sys/time.h	2010-12-19 03:50:04.000000000 +1100
+++ sys/sys/time.h	2010-12-19 08:58:07.000000000 +1100
@@ -2,6 +2,12 @@
  * Copyright (C) 1982, 1986, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
+ * Copyright (C) 2010 The University of Melbourne
+ * All rights reserved.
+ *
+ * Portions of this software were developed by the University of Melbourne
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -324,6 +330,46 @@ void	getbintime(struct bintime *bt);
 void	getnanotime(struct timespec *tsp);
 void	getmicrotime(struct timeval *tvp);
 
+/* FFCLOCK specific */
+typedef uint64_t ffcounter_t;
+
+/* Feed-Forward Clock synchronisation structure */
+
+struct ffclock_data
+{
+    /* Time conversion of ffcounter below */
+    struct bintime time;
+    /* Last synchronization daemon update or update_ffclock() */
+    ffcounter_t ffcounter;
+    /* Timecounter period estimate (<< per_shift) */
+    uint64_t period;
+    /* Clock status word */
+    uint32_t status;
+    /* Average of clock error bound in [ns] */
+    uint32_t error_bound_avg;
+};
+
+struct ffclock_estimate
+{
+	volatile uint8_t gen;
+	struct ffclock_data cdata;
+};
+
+/* Current estimate and old one, no locking on the timestamping side */
+struct feedforward_clock
+{
+	volatile uint8_t updated;
+	struct ffclock_estimate *cest;
+	struct ffclock_estimate *ocest;
+	struct ffclock_estimate *ucest;
+};
+
+
+
+ffcounter_t read_ffcounter(void);
+void ffcounter2bintime(ffcounter_t *ffcounter, struct bintime *bt);
+/* FFCLOCK */
+
 /* Other functions */
 int	itimerdecr(struct itimerval *itp, int usec);
 int	itimerfix(struct timeval *tv);
Index: sys/conf/NOTES
===================================================================
--- sys.orig/conf/NOTES	2010-12-19 03:50:04.000000000 +1100
+++ sys/conf/NOTES	2010-12-19 08:58:07.000000000 +1100
@@ -1178,6 +1178,16 @@ options 	HZ=100
 
 options 	PPS_SYNC
 
+# Enable support for generic Feed-Forward clocks in the kernel.
+# The feed-forward clock support is an alternative to the feedback oriented
+# ntpd/system clock approach, and is to be used with a feed-forward
+# synchronization algorithm such as the RADclock:
+# More info there: http://www.synclab.org/radclock
+#
+# Note: this is an experimental feature.
+
+options 	FFCLOCK
+
 
 #####################################################################
 # SCSI DEVICES
Index: sys/conf/options
===================================================================
--- sys.orig/conf/options	2010-12-19 03:50:04.000000000 +1100
+++ sys/conf/options	2010-12-19 08:58:07.000000000 +1100
@@ -75,6 +75,7 @@ COMPRESS_USER_CORES opt_core.h
 CY_PCI_FASTINTR
 DEADLKRES	opt_watchdog.h
 DIRECTIO
+FFCLOCK		opt_ffclock.h
 FULL_PREEMPTION	opt_sched.h
 IPI_PREEMPTION	opt_sched.h
 GEOM_AES	opt_geom.h
<commit_msg>Fix print out precision issue<commit_after>FFclock core

Core set of changes to support a feed-forward clock within the kernel.

---
 conf/NOTES     |   10 ++
 conf/options   |    1 
 kern/kern_tc.c |  250 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sys/time.h     |   46 ++++++++++
 4 files changed, 307 insertions(+)

Index: sys/kern/kern_tc.c
===================================================================
--- sys.orig/kern/kern_tc.c	2010-12-19 03:50:04.000000000 +1100
+++ sys/kern/kern_tc.c	2010-12-19 08:58:07.000000000 +1100
@@ -5,6 +5,12 @@
  * 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.   <NAME>
  * ----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2010 The University of Melbourne
+ * All rights reserved.
+ *
+ * Portions of this software were developed by the University of Melbourne
+ * under sponsorship from the FreeBSD Foundation.
  */
 
 #include <sys/cdefs.h>
@@ -21,6 +27,12 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_tc
 #include <sys/timetc.h>
 #include <sys/timex.h>
 
+#ifdef FFCLOCK
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+#endif	/* FFCLOCK */
+
 /*
  * A large step happens on boot.  This constant detects such steps.
  * It is relatively small so that ntp_update_second gets called enough
@@ -53,6 +65,9 @@ struct timehands {
 	int64_t			th_adjustment;
 	uint64_t		th_scale;
 	u_int	 		th_offset_count;
+#ifdef FFCLOCK
+	ffcounter_t		ffcounter_record;
+#endif
 	struct bintime		th_offset;
 	struct timeval		th_microtime;
 	struct timespec		th_nanotime;
@@ -61,6 +76,30 @@ struct timehands {
 	struct timehands	*th_next;
 };
 
+#ifdef FFCLOCK
+static struct timehands th0;
+static struct timehands th9 = { NULL, 0, 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}, 0, &th9};
+static struct timehands th7 = { NULL, 0, 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}, 0, &th7};
+static struct timehands th5 = { NULL, 0, 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}, 0, &th5};
+static struct timehands th3 = { NULL, 0, 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}, 0, &th3};
+static struct timehands th1 = { NULL, 0, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2};
+static struct timehands th0 = {
+	&dummy_timecounter,
+	0,
+	(uint64_t)-1 / 1000000,
+	0,
+	0,
+	{1, 0},
+	{0, 0},
+	{0, 0},
+	1,
+	&th1
+};
+#else
 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};
@@ -82,6 +121,7 @@ static struct timehands th0 = {
 	1,
 	&th1
 };
+#endif	/* FFCLOCK */
 
 static struct timehands *volatile timehands = &th0;
 struct timecounter *timecounter = &dummy_timecounter;
@@ -300,6 +340,200 @@ getmicrotime(struct timeval *tvp)
 	} while (gen == 0 || gen != th->th_generation);
 }
 
+
+#ifdef FFCLOCK
+
+/* Global data structure containing clock estimates */
+static struct feedforward_clock ffclock;
+
+
+MALLOC_DECLARE(M_FFCLOCK);
+MALLOC_DEFINE(M_FFCLOCK, "FFCLOCK", "Feed-Forward Clock estimates");
+
+
+static void
+init_ffclock(struct feedforward_clock *ffclock)
+{
+	unsigned long sz;
+	sz = sizeof(struct ffclock_estimate);
+
+	ffclock->updated = 0;
+	ffclock->cest	= (struct ffclock_estimate *) malloc(sz, M_FFCLOCK, M_WAITOK | M_ZERO);
+	ffclock->ocest	= (struct ffclock_estimate *) malloc(sz, M_FFCLOCK, M_WAITOK | M_ZERO);
+	ffclock->ucest	= (struct ffclock_estimate *) malloc(sz, M_FFCLOCK, M_WAITOK | M_ZERO);
+}
+
+
+/*
+ * We need to have a boot time from the RTC clock or the like to get
+ * kickstarted. init_ffclock is called before inittodr(), so cannot put the code
+ * there. Need to be called from tc_setclock(), once only.
+ */
+static void
+reset_ffclock(struct feedforward_clock *ffclock, struct timehands *th)
+{
+	struct timecounter *tc;
+	struct ffclock_estimate *cest;
+	struct ffclock_data *cdata;
+	struct timespec ts;
+
+	cest = ffclock->ucest;
+	cdata = &(cest->cdata);
+
+	/*
+	 * If called with a timehand, the timecounter is being changed and we
+	 * restart fresh. If not, the clock is being set from tc_setclock (note that
+	 * this may occur several times during boot).
+	 */
+	if (th) {
+		th->ffcounter_record = 0;
+		cdata->ffcounter = 0;
+		tc = th->th_counter;
+	}
+	else {
+		/*
+		 * Strictly speaking, we should record the ffcounter when the RTC clock is
+		 * read from initoddr(), but not worse the trouble (is RTC trustworthy
+		 * anyway?). Let's keep it simple
+		 */
+		cdata->ffcounter = read_ffcounter();
+		tc = timehands->th_counter;
+	}
+
+	/* Need to hold enough seconds until 2038. Assume 32 bits container */
+	cdata->time.sec = boottimebin.sec;
+	cdata->time.frac = boottimebin.frac;
+
+	cdata->period = ((1LLU << 63) / tc->tc_frequency ) << 1;
+
+	cdata->status = 0;
+	cdata->error_bound_avg = 0;
+
+	if (++cest->gen == 0)
+		cest->gen = 1;
+
+	ffclock->ucest = ffclock->cest;
+	ffclock->cest = cest;
+
+	cdata = &(ffclock->cest->cdata);
+
+	bintime2timespec(&(cdata->time), &ts);
+	printf("reset_ffclock: %s - period = %llu (%llu Hz), time = %lu.%09lu",
+			tc->tc_name,
+			(long long unsigned) cdata->period,
+			(long long unsigned) tc->tc_frequency,
+			(long unsigned) ts.tv_sec,
+			(long unsigned) ts.tv_nsec);
+}
+
+
+/*
+ * Update to prevent overflow. This is no adjustment of the clock parameters.
+ * Assumption: timehands is the current one
+ */
+static void
+update_ffclock(struct feedforward_clock *ffclock)
+{
+	struct ffclock_estimate *tmp;
+	struct ffclock_data *cdata;
+	struct timehands *th;
+	ffcounter_t ffdelta;
+	struct bintime delta;
+
+	/*
+	 * If the clock has been updated by the synchronisation daemon, this new
+	 * data is the more up to date one.
+	 */
+	if ( ffclock->updated )
+	{
+		ffclock->ucest->gen = ffclock->cest->gen;
+		if (++ffclock->ucest->gen == 0)
+			ffclock->ucest->gen = 1;
+
+		tmp = ffclock->cest;
+		ffclock->cest = ffclock->ucest;
+		ffclock->ucest = tmp;
+		ffclock->updated = 0;
+		return;
+	}
+
+	/* If we just changed the timecounter, we have nothing to do in here */
+	cdata = &(ffclock->cest->cdata);
+	th = timehands;
+	if ( cdata->ffcounter > th->ffcounter_record )
+		return;
+
+	/* Update time mark */
+	*(ffclock->ocest) = *(ffclock->cest);
+	cdata = &(ffclock->ocest->cdata);
+
+	ffdelta = th->ffcounter_record - cdata->ffcounter;
+
+	delta.sec = 0;
+	delta.frac = cdata->period;
+	bintime_mul(&delta, ffdelta);
+	bintime_add(&(cdata->time), &delta);
+
+	cdata->ffcounter = th->ffcounter_record;
+
+	if (++ffclock->ocest->gen == 0)
+		ffclock->ocest->gen = 1;
+
+	tmp = ffclock->cest;
+	ffclock->cest = ffclock->ocest;
+	ffclock->ocest = tmp;
+}
+
+
+
+void
+ffcounter2bintime(ffcounter_t *ffcounter, struct bintime *bt)
+{
+	struct ffclock_data *cdata;
+	ffcounter_t ffdelta;
+	struct bintime delta;
+	uint8_t gen;
+
+	/*
+	 * No locking to prevent clock data to be updated. Check that the generation
+	 * has not changed instead.
+	 */
+	do {
+		gen = ffclock.cest->gen;
+		cdata = &(ffclock.cest->cdata);
+
+		ffdelta = *ffcounter - cdata->ffcounter;
+		delta.sec = 0;
+		delta.frac = cdata->period;
+		bintime_mul(&delta, ffdelta);
+		bt->sec = cdata->time.sec;
+		bt->frac = cdata->time.frac;
+		bintime_add(bt, &delta);
+
+	} while (gen == 0 || gen != ffclock.cest->gen);
+}
+
+
+
+ffcounter_t
+read_ffcounter(void)
+{
+	struct timehands *th;
+	u_int gen, delta;
+	ffcounter_t ffcounter;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		delta = tc_delta(th);
+		ffcounter = th->ffcounter_record;
+	} while ( gen == 0 || gen != th->th_generation);
+
+	return(ffcounter + delta);
+}
+#endif	/* FFCLOCK */
+
+
 /*
  * Initialize a new timecounter and possibly use it.
  */
@@ -391,6 +625,10 @@ tc_setclock(struct timespec *ts)
 	boottimebin = bt;
 	bintime2timeval(&bt, &boottime);
 
+#ifdef FFCLOCK
+	reset_ffclock(&ffclock, NULL);
+#endif	/* FFCLOCK */
+
 	/* XXX fiddle all the little crinkly bits around the fiords... */
 	tc_windup();
 	nanotime(&taft);
@@ -440,6 +678,9 @@ tc_windup(void)
 		ncount = timecounter->tc_get_timecount(timecounter);
 	else
 		ncount = 0;
+#ifdef FFCLOCK
+	th->ffcounter_record += delta;
+#endif
 	th->th_offset_count += delta;
 	th->th_offset_count &= th->th_counter->tc_counter_mask;
 	while (delta > th->th_counter->tc_frequency) {
@@ -496,6 +737,9 @@ tc_windup(void)
 		th->th_offset_count = ncount;
 		tc_min_ticktock_freq = max(1, timecounter->tc_frequency /
 		    (((uint64_t)timecounter->tc_counter_mask + 1) / 3));
+#ifdef FFCLOCK
+		reset_ffclock(&ffclock, th);
+#endif
 	}
 
 	/*-
@@ -792,6 +1036,9 @@ tc_ticktock(int cnt)
 		return;
 	count = 0;
 	tc_windup();
+#ifdef FFCLOCK
+	update_ffclock(&ffclock);
+#endif
 }
 
 static void
@@ -814,6 +1061,9 @@ inittimecounter(void *dummy)
 	p = (tc_tick * 1000000) / hz;
 	printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000);
 
+#ifdef FFCLOCK
+	init_ffclock(&ffclock);
+#endif
 	/* warm up new timecounter (again) and get rolling. */
 	(void)timecounter->tc_get_timecount(timecounter);
 	(void)timecounter->tc_get_timecount(timecounter);
Index: sys/sys/time.h
===================================================================
--- sys.orig/sys/time.h	2010-12-19 03:50:04.000000000 +1100
+++ sys/sys/time.h	2010-12-19 08:58:07.000000000 +1100
@@ -2,6 +2,12 @@
  * Copyright (C) 1982, 1986, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
+ * Copyright (C) 2010 The University of Melbourne
+ * All rights reserved.
+ *
+ * Portions of this software were developed by the University of Melbourne
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -324,6 +330,46 @@ void	getbintime(struct bintime *bt);
 void	getnanotime(struct timespec *tsp);
 void	getmicrotime(struct timeval *tvp);
 
+/* FFCLOCK specific */
+typedef uint64_t ffcounter_t;
+
+/* Feed-Forward Clock synchronisation structure */
+
+struct ffclock_data
+{
+    /* Time conversion of ffcounter below */
+    struct bintime time;
+    /* Last synchronization daemon update or update_ffclock() */
+    ffcounter_t ffcounter;
+    /* Timecounter period estimate (<< per_shift) */
+    uint64_t period;
+    /* Clock status word */
+    uint32_t status;
+    /* Average of clock error bound in [ns] */
+    uint32_t error_bound_avg;
+};
+
+struct ffclock_estimate
+{
+	volatile uint8_t gen;
+	struct ffclock_data cdata;
+};
+
+/* Current estimate and old one, no locking on the timestamping side */
+struct feedforward_clock
+{
+	volatile uint8_t updated;
+	struct ffclock_estimate *cest;
+	struct ffclock_estimate *ocest;
+	struct ffclock_estimate *ucest;
+};
+
+
+
+ffcounter_t read_ffcounter(void);
+void ffcounter2bintime(ffcounter_t *ffcounter, struct bintime *bt);
+/* FFCLOCK */
+
 /* Other functions */
 int	itimerdecr(struct itimerval *itp, int usec);
 int	itimerfix(struct timeval *tv);
Index: sys/conf/NOTES
===================================================================
--- sys.orig/conf/NOTES	2010-12-19 03:50:04.000000000 +1100
+++ sys/conf/NOTES	2010-12-19 08:58:07.000000000 +1100
@@ -1178,6 +1178,16 @@ options 	HZ=100
 
 options 	PPS_SYNC
 
+# Enable support for generic Feed-Forward clocks in the kernel.
+# The feed-forward clock support is an alternative to the feedback oriented
+# ntpd/system clock approach, and is to be used with a feed-forward
+# synchronization algorithm such as the RADclock:
+# More info there: http://www.synclab.org/radclock
+#
+# Note: this is an experimental feature.
+
+options 	FFCLOCK
+
 
 #####################################################################
 # SCSI DEVICES
Index: sys/conf/options
===================================================================
--- sys.orig/conf/options	2010-12-19 03:50:04.000000000 +1100
+++ sys/conf/options	2010-12-19 08:58:07.000000000 +1100
@@ -75,6 +75,7 @@ COMPRESS_USER_CORES opt_core.h
 CY_PCI_FASTINTR
 DEADLKRES	opt_watchdog.h
 DIRECTIO
+FFCLOCK		opt_ffclock.h
 FULL_PREEMPTION	opt_sched.h
 IPI_PREEMPTION	opt_sched.h
 GEOM_AES	opt_geom.h

{'fraction_non_alphanumeric': 0.19219050673508659, 'fraction_numerical': 0.04866901860166774, 'mean_word_length': 3.9425401228452546, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 201, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 16, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6266559', 'n_tokens_mistral': 10665, 'n_tokens_neox': 9433, 'n_words': 2544}