diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h --- a/sys/compat/freebsd32/freebsd32.h +++ b/sys/compat/freebsd32/freebsd32.h @@ -67,14 +67,14 @@ struct ffclock_estimate32 { struct bintime32 update_time; ffcounter update_ffcount; - ffcounter leapsec_next; + ffcounter leapsec_expected; uint64_t period; uint32_t errb_abs; uint32_t errb_rate; uint32_t status; - int16_t leapsec_total; - int8_t leapsec; - int8_t _pad; + int16_t secs_to_nextupdate; + int8_t leapsec_total; + int8_t leapsec_next; } #if defined(__amd64__) __attribute__((packed)) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -4103,16 +4103,17 @@ sizeof(struct ffclock_estimate32))) != 0) return (error); - CP(cest.update_time, cest32.update_time, sec); + CP(cest32.update_time, cest.update_time, sec); memcpy(&cest.update_time.frac, &cest32.update_time.frac, sizeof(uint64_t)); - CP(cest, cest32, update_ffcount); - CP(cest, cest32, leapsec_next); - CP(cest, cest32, period); - CP(cest, cest32, errb_abs); - CP(cest, cest32, errb_rate); - CP(cest, cest32, status); - CP(cest, cest32, leapsec_total); - CP(cest, cest32, leapsec); + CP(cest32, cest, update_ffcount); + CP(cest32, cest, leapsec_expected); + CP(cest32, cest, period); + CP(cest32, cest, errb_abs); + CP(cest32, cest, errb_rate); + CP(cest32, cest, status); + CP(cest32, cest, secs_to_nextupdate); + CP(cest32, cest, leapsec_total); + CP(cest32, cest, leapsec_next); mtx_lock(&ffclock_mtx); memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); @@ -4133,16 +4134,17 @@ memcpy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); mtx_unlock(&ffclock_mtx); - CP(cest32.update_time, cest.update_time, sec); + CP(cest.update_time, cest32.update_time, sec); memcpy(&cest32.update_time.frac, &cest.update_time.frac, sizeof(uint64_t)); - CP(cest32, cest, update_ffcount); - CP(cest32, cest, leapsec_next); - CP(cest32, cest, period); - CP(cest32, cest, errb_abs); - CP(cest32, cest, errb_rate); - CP(cest32, cest, status); - CP(cest32, cest, leapsec_total); - CP(cest32, cest, leapsec); + CP(cest, cest32, update_ffcount); + CP(cest, cest32, leapsec_expected); + CP(cest, cest32, period); + CP(cest, cest32, errb_abs); + CP(cest, cest32, errb_rate); + CP(cest, cest32, status); + CP(cest, cest32, secs_to_nextupdate); + CP(cest, cest32, leapsec_total); + CP(cest, cest32, leapsec_next); error = copyout(&cest32, uap->cest, sizeof(struct ffclock_estimate32)); return (error); diff --git a/sys/kern/kern_ffclock.c b/sys/kern/kern_ffclock.c --- a/sys/kern/kern_ffclock.c +++ b/sys/kern/kern_ffclock.c @@ -91,14 +91,14 @@ } while (update_ffcount != ffclock_estimate.update_ffcount); /* - * Leap second adjustment. Total as seen by synchronisation algorithm - * since it started. cest.leapsec_next is the ffcounter prediction of - * when the next leapsecond occurs. + * Leap second adjustment. Total as seen by the FFclock daemon since it + * started. cest.leapsec_expected is the ffcounter prediction of when + * the next leapsecond occurs. */ if ((flags & FFCLOCK_LEAPSEC) == FFCLOCK_LEAPSEC) { - bt->sec -= cest.leapsec_total; - if (ffc > cest.leapsec_next) - bt->sec -= cest.leapsec; + bt->sec -= cest.leapsec_total; // subtracting = including leaps + if (cest.leapsec_expected != 0 && ffc > cest.leapsec_expected) + bt->sec -= cest.leapsec_next; } /* Boot time adjustment, for uptime/monotonic clocks. */ @@ -159,9 +159,9 @@ #define MAX_SYSCLOCK_NAME_LEN 16 #define NUM_SYSCLOCKS nitems(sysclocks) -static int ffclock_version = 2; +static int ffclock_version = 3; SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, version, CTLFLAG_RD, - &ffclock_version, 0, "Feedforward clock kernel version"); + &ffclock_version, 0, "FFclock kernel version"); /* List available sysclocks. */ static int @@ -375,7 +375,7 @@ /* * System call allowing userland applications to retrieve the current value of - * the feedforward clock counter. + * the FFclock counter. */ #ifndef _SYS_SYSPROTO_H_ struct ffclock_getcounter_args { diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -579,13 +579,14 @@ timespec2bintime(ts, &ffclock_boottime); timespec2bintime(ts, &(cest.update_time)); ffclock_read_counter(&cest.update_ffcount); - cest.leapsec_next = 0; + cest.secs_to_nextupdate = 0; cest.period = ((1ULL << 63) / tc->tc_frequency) << 1; cest.errb_abs = 0; cest.errb_rate = 0; cest.status = FFCLOCK_STA_UNSYNC; + cest.leapsec_expected = 0; cest.leapsec_total = 0; - cest.leapsec = 0; + cest.leapsec_next = 0; mtx_lock(&ffclock_mtx); memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); @@ -647,7 +648,6 @@ struct bintime bt, gap; ffcounter ffdelta; uint64_t frac; - unsigned int polling; uint8_t forward_jump, ogen; /* Prepare next fftimehand where tick state will be updated. */ @@ -683,18 +683,20 @@ bintime_add(&ffth->tick_time_mono, &bt); /* Check if the clock status should be set to unsynchronized. - * Assessment based on age of last/current update. If the + * Assessment based on age of last/current update, and the + * daemon's estimate of the wait to the next update. If the * daemon's UNSYNC status is too stale, it is over-ridden. */ if (ffclock_updated == 0) { - ffdelta = ffth->tick_ffcount - cest->update_ffcount; - ffclock_convert_delta(ffdelta, cest->period, &bt); - if (bt.sec > 2 * FFCLOCK_SKM_SCALE) + bt = ffth->tick_time; + bintime_sub(&bt, &cest->update_time); + if (bt.sec > 3 * FFCLOCK_SKM_SCALE && + bt.sec > 3 * cest->secs_to_nextupdate) ffclock_status |= FFCLOCK_STA_UNSYNC; } } - + /* * An update in FFclock parameters is available in this tick. Generate * the new tick state based on this, projected from the update time. @@ -733,7 +735,7 @@ bintime_add(&ffth->tick_time_mono, &bt); } - /* Record direction of jump between monoFFC and natFFC */ + /* Record direction of jump between monoFFC and natFFC. */ if (bintime_cmp(&ffth->tick_time, &ffth->tick_time_mono, >)) forward_jump = 1; else @@ -789,21 +791,20 @@ ffth->period_mono = cest->period; // re-initialize /* Keep default if no visible gap or no daemon updates yet. */ - if (bintime_isset(&gap)) { - - /* Estimate #seconds to next update. */ - ffdelta = cest->update_ffcount; - ffdelta -= fftimehands->cest.update_ffcount; - ffclock_convert_delta(ffdelta, cest->period, &bt); - polling = bt.sec; + if (bintime_isset(&gap) && cest->secs_to_nextupdate > 0) { /* Calculate cap */ bt.sec = 0; bt.frac = 5000000 * NS_AS_BINFRAC; - bintime_mul(&bt, polling); + bintime_mul(&bt, cest->secs_to_nextupdate); if (bintime_cmp(&gap, &bt, >)) gap = bt; // gap = min(gap, bt) + /* Convert secs_to_nextupdate to counter units. */ + frac = 0; + frac -= 1; // approximate 2^64 with (2^64)-1 for ease + ffdelta = (frac/cest->period) * cest->secs_to_nextupdate; + /* Store the portion of gap per cycle in frac. */ frac = 0; if (gap.sec > 0) { @@ -877,10 +878,14 @@ memcpy(cest, &(fftimehands->cest), sizeof(struct ffclock_estimate)); cest->update_ffcount = ffth->tick_ffcount; + cest->secs_to_nextupdate = 0; cest->period = ((1ULL << 63) / tc->tc_frequency ) << 1; cest->errb_abs = 0; cest->errb_rate = 0; cest->status |= FFCLOCK_STA_UNSYNC; + cest->leapsec_expected = 0; + cest->leapsec_total = 0; + cest->leapsec_next = 0; ffth->tick_time = fftimehands->tick_time; ffth->tick_error = fftimehands->tick_error; @@ -1206,10 +1211,14 @@ if (!fast) clock_snap->ffcount += delta; - /* Record feedforward clock leap second adjustment. */ + /* + * Pre-calculate total leap adjustment appropriate to this ffcount. That + * is, total leaps so far and impending leap ffcount may have surpassed. + */ ffi->leapsec_adjustment = cest.leapsec_total; - if (clock_snap->ffcount > cest.leapsec_next) - ffi->leapsec_adjustment -= cest.leapsec; + if (cest.leapsec_expected != 0 && clock_snap->ffcount > + cest.leapsec_expected) + ffi->leapsec_adjustment += cest.leapsec_next; /* Record feedforward clock status and error. */ ffi->status = cest.status; diff --git a/sys/sys/timeffc.h b/sys/sys/timeffc.h --- a/sys/sys/timeffc.h +++ b/sys/sys/timeffc.h @@ -34,6 +34,10 @@ #include + +#if __BSD_VISIBLE +#ifdef _KERNEL + /* * Feedforward clock estimate * Holds time mark as a ffcounter and conversion to bintime based on current @@ -41,20 +45,18 @@ * Provides time of last daemon update, clock status and bound on error. */ struct ffclock_estimate { - struct bintime update_time; /* Time of last estimates update. */ - ffcounter update_ffcount; /* Counter value at last update. */ - ffcounter leapsec_next; /* Counter value of next leap second. */ - uint64_t period; /* Estimate of counter period. */ - uint32_t errb_abs; /* Bound on absolute clock error [ns]. */ - uint32_t errb_rate; /* Bound on counter rate error [ps/s]. */ - uint32_t status; /* Clock status. */ - int16_t leapsec_total; /* All leap seconds seen so far. */ - int8_t leapsec; /* Next leap second (in {-1,0,1}). */ + struct bintime update_time; /* FFclock time of last update. */ + ffcounter update_ffcount; /* Counter value at last update. */ + ffcounter leapsec_expected; /* Approx counter value of next leap. */ + uint64_t period; /* Counter period estimate [2^-64 s]. */ + uint32_t errb_abs; /* Bound on absolute clock error [ns]. */ + uint32_t errb_rate; /* Bound on rel. counter period err [ps/s]*/ + uint32_t status; /* Clock status. */ + uint16_t secs_to_nextupdate;/* Estimated wait til next update [s]. */ + int8_t leapsec_total; /* Sum of leap secs since clock start. */ + int8_t leapsec_next; /* Next leap second (in {-1,0,1}). */ }; -#if __BSD_VISIBLE -#ifdef _KERNEL - /* Constants to hold errors and error rates in 64bit binary fraction fields. */ #define MS_AS_BINFRAC (uint64_t)18446744073709551ULL // floor(2^64/1e3) #define MUS_AS_BINFRAC (uint64_t)18446744073709ULL // floor(2^64/1e6)