Index: sys/sys/timeffc.h =================================================================== --- sys/sys/timeffc.h (revision 228435) +++ sys/sys/timeffc.h (working copy) @@ -81,20 +81,70 @@ #define FFCLOCK_STA_WARMUP 2 /* - * Clock flags to select how the feed-forward counter is converted to absolute - * time by ffclock_convert_abs(). - * FAST: do not read the hardware counter, return feed-forward clock time - * at last tick. The time returned has the resolution of the kernel - * tick (1/hz [s]). - * LERP: linear interpolation of ffclock time to guarantee monotonic time. - * LEAPSEC: include leap seconds. - * UPTIME: removes time of boot. + * Flags for use predominantly by sysclock_getsnapshot() to control how the + * timecounter hardware is read and how the hardware snapshot is converted into + * absolute time. + * {FB|FF}CLOCK_WANTSNAP: Provide a time stamp from this system clock in the + * returned sysclock_snap struct. + * {FB|FF}CLOCK_FAST: Do not read the hardware counter, instead using the + * value at last tick. The time returned has a resolution + * of the kernel tick timer (1/hz [s]). + * FFCLOCK_LERP: Linear interpolation of ffclock time to guarantee + * monotonic time. + * FFCLOCK_LEAPSEC: Include leap seconds. + * {FB|FF}CLOCK_UPTIME: Time stamp should be relative to system boot, not epoch. */ -#define FFCLOCK_FAST 1 -#define FFCLOCK_LERP 2 -#define FFCLOCK_LEAPSEC 4 -#define FFCLOCK_UPTIME 8 +#define FFCLOCK_WANTSNAP 0x00000001 +#define FFCLOCK_FAST 0x00000002 +#define FFCLOCK_LERP 0x00000004 +#define FFCLOCK_LEAPSEC 0x00000008 +#define FFCLOCK_UPTIME 0x00000010 +#define FFCLOCK_MASK 0x0000ffff +#define FBCLOCK_WANTSNAP 0x00010000 +#define FBCLOCK_FAST 0x00020000 +#define FBCLOCK_UPTIME 0x00040000 +#define FBCLOCK_MASK 0xffff0000 + +/* + * Feedback clock specific info structure. The feedback clock's estimation of + * clock error is an absolute figure determined by the NTP algorithm. The status + * is determined by the userland daemon. + */ +struct fbclock_info { + struct bintime error; + int status; +}; + +/* + * Feed-forward clock specific info structure. The feed-forward clock's + * estimation of clock error is an upper bound, which although potentially + * looser than the feedback clock equivalent, is much more reliable. The status + * is determined by the userland daemon. + */ +struct ffclock_info { + struct bintime error; + int status; +}; + +/* + * Snapshot of system clocks and related information. Holds time read from each + * clock based on a single read of the active hardware timecounter, as well as + * respective clock information such as error estimates and the ffcounter value + * at the time of the read. + */ +struct sysclock_snap { + struct bintime fbclock_bt; + struct bintime ffclock_bt; + struct fbclock_info fb_info; + struct ffclock_info ff_info; + ffcounter ffcount; + int sysclock_active; +}; + +/* Take a snapshot of the system clock(s) and related information. */ +void sysclock_getsnapshot(struct sysclock_snap *clock_snap, uint32_t flags); + /* Resets feed-forward clock from RTC */ void ffclock_reset_clock(struct timespec *ts); Index: sys/kern/kern_ntptime.c =================================================================== --- sys/kern/kern_ntptime.c (revision 228435) +++ sys/kern/kern_ntptime.c (working copy) @@ -148,13 +148,13 @@ #define SHIFT_FLL 2 /* FLL loop gain (shift) */ static int time_state = TIME_OK; /* clock state */ -static int time_status = STA_UNSYNC; /* clock status bits */ +int time_status = STA_UNSYNC; /* clock status bits */ static long time_tai; /* TAI offset (s) */ static long time_monitor; /* last time offset scaled (ns) */ static long time_constant; /* poll interval (shift) (s) */ static long time_precision = 1; /* clock precision (ns) */ static long time_maxerror = MAXPHASE / 1000; /* maximum error (us) */ -static long time_esterror = MAXPHASE / 1000; /* estimated error (us) */ +long time_esterror = MAXPHASE / 1000; /* estimated error (us) */ static long time_reftime; /* time at last adjustment (s) */ static l_fp time_offset; /* time offset (ns) */ static l_fp time_freq; /* frequency offset (ns/s) */ Index: sys/kern/kern_tc.c =================================================================== --- sys/kern/kern_tc.c (revision 228435) +++ sys/kern/kern_tc.c (working copy) @@ -956,6 +956,98 @@ getmicrouptime_fromclock(tvp, sysclock_active); } + +/* Internal NTP status and error estimates. */ +extern int time_status; +extern long time_esterror; + +void +sysclock_getsnapshot(struct sysclock_snap *clock_snap, uint32_t flags) +{ + struct fftimehands *ffth; + struct timehands *th; + struct ffclock_estimate cest; + struct bintime bt, bt2; + ffcounter ffcount; + uint64_t period, th_scale; + unsigned int delta, fast, gen; + + delta = fast = 0; + if (flags & (FBCLOCK_FAST | FFCLOCK_FAST)) + fast = 1; + + do { + th = timehands; + gen = th->th_generation; + ffth = fftimehands; + th_scale = th->th_scale; + bt = th->th_offset; + if (flags & FFCLOCK_LERP) { + bt2 = ffth->tick_time_lerp; + period = ffth->period_lerp; + } else { + bt2 = ffth->tick_time; + period = ffth->cest.period; + } + ffcount = ffth->tick_ffcount; + cest = ffth->cest; + if (!fast) + delta = tc_delta(th); + } while (gen == 0 || gen != th->th_generation); + + if (!fast) + ffcount += delta; + + clock_snap->ffcount = ffcount; + clock_snap->sysclock_active = sysclock_active; + + if (flags & FBCLOCK_WANTSNAP) { + /* Add feedback clock info and time stamp to snapshot. */ + if (!fast) + bintime_addx(&bt, th_scale * delta); + + if ((flags & FBCLOCK_UPTIME) == 0) + bintime_add(&bt, &boottimebin); + + clock_snap->fbclock_bt = bt; + clock_snap->fb_info.status = time_status; + /* XXX: Very crude estimate of feedback clock error. */ + bt.sec = time_esterror / 1000000; + bt.frac = ((time_esterror - bt.sec) * 1000000) * + (uint64_t)18446744073709ULL; + clock_snap->fb_info.error = bt; + } + + if (flags & FFCLOCK_WANTSNAP) { + /* Add feed-forward clock info and time stamp to snapshot. */ + if (!fast) { + ffclock_convert_delta(delta, period, &bt); + bintime_add(&bt2, &bt); + } + + /* Leap second adjustment. */ + if (flags & FFCLOCK_LEAPSEC) { + bt2.sec -= cest.leapsec_total; + if (ffcount > cest.leapsec_next) + bt2.sec -= cest.leapsec; + } + + /* Boot time adjustment, for uptime/monotonic clocks. */ + if (flags & FFCLOCK_UPTIME) + bintime_sub(&bt2, &ffclock_boottime); + + clock_snap->ffclock_bt = bt2; + clock_snap->ff_info.status = cest.status; + ffcount = clock_snap->ffcount - cest.update_ffcount; + ffclock_convert_delta(ffcount, period, &bt); + /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s]. */ + bintime_mul(&bt, cest.errb_rate * (uint64_t)18446744073709ULL); + /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns]. */ + bintime_addx(&bt, cest.errb_abs * (uint64_t)18446744073ULL); + clock_snap->ff_info.error = bt; + } +} + #endif /* FFCLOCK */ /*