1*f464c5ccSLawrence Stewart /*- 2*f464c5ccSLawrence Stewart * Copyright (c) 2011 The University of Melbourne 3*f464c5ccSLawrence Stewart * All rights reserved. 4*f464c5ccSLawrence Stewart * 5*f464c5ccSLawrence Stewart * This software was developed by Julien Ridoux at the University of Melbourne 6*f464c5ccSLawrence Stewart * under sponsorship from the FreeBSD Foundation. 7*f464c5ccSLawrence Stewart * 8*f464c5ccSLawrence Stewart * Redistribution and use in source and binary forms, with or without 9*f464c5ccSLawrence Stewart * modification, are permitted provided that the following conditions 10*f464c5ccSLawrence Stewart * are met: 11*f464c5ccSLawrence Stewart * 1. Redistributions of source code must retain the above copyright 12*f464c5ccSLawrence Stewart * notice, this list of conditions and the following disclaimer. 13*f464c5ccSLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright 14*f464c5ccSLawrence Stewart * notice, this list of conditions and the following disclaimer in the 15*f464c5ccSLawrence Stewart * documentation and/or other materials provided with the distribution. 16*f464c5ccSLawrence Stewart * 17*f464c5ccSLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*f464c5ccSLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*f464c5ccSLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*f464c5ccSLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*f464c5ccSLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*f464c5ccSLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*f464c5ccSLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*f464c5ccSLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*f464c5ccSLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*f464c5ccSLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*f464c5ccSLawrence Stewart * SUCH DAMAGE. 28*f464c5ccSLawrence Stewart */ 29*f464c5ccSLawrence Stewart 30*f464c5ccSLawrence Stewart #include <sys/cdefs.h> 31*f464c5ccSLawrence Stewart __FBSDID("$FreeBSD$"); 32*f464c5ccSLawrence Stewart 33*f464c5ccSLawrence Stewart #include <sys/param.h> 34*f464c5ccSLawrence Stewart #include <sys/systm.h> 35*f464c5ccSLawrence Stewart #include <sys/timeffc.h> 36*f464c5ccSLawrence Stewart 37*f464c5ccSLawrence Stewart extern struct ffclock_estimate ffclock_estimate; 38*f464c5ccSLawrence Stewart extern struct bintime ffclock_boottime; 39*f464c5ccSLawrence Stewart 40*f464c5ccSLawrence Stewart /* 41*f464c5ccSLawrence Stewart * Feed-forward clock absolute time. This should be the preferred way to read 42*f464c5ccSLawrence Stewart * the feed-forward clock for "wall-clock" type time. The flags allow to compose 43*f464c5ccSLawrence Stewart * various flavours of absolute time (e.g. with or without leap seconds taken 44*f464c5ccSLawrence Stewart * into account). If valid pointers are provided, the ffcounter value and an 45*f464c5ccSLawrence Stewart * upper bound on clock error associated with the bintime are provided. 46*f464c5ccSLawrence Stewart * NOTE: use ffclock_convert_abs() to differ the conversion of a ffcounter value 47*f464c5ccSLawrence Stewart * read earlier. 48*f464c5ccSLawrence Stewart */ 49*f464c5ccSLawrence Stewart void 50*f464c5ccSLawrence Stewart ffclock_abstime(ffcounter *ffcount, struct bintime *bt, 51*f464c5ccSLawrence Stewart struct bintime *error_bound, uint32_t flags) 52*f464c5ccSLawrence Stewart { 53*f464c5ccSLawrence Stewart struct ffclock_estimate cest; 54*f464c5ccSLawrence Stewart ffcounter ffc; 55*f464c5ccSLawrence Stewart ffcounter update_ffcount; 56*f464c5ccSLawrence Stewart ffcounter ffdelta_error; 57*f464c5ccSLawrence Stewart 58*f464c5ccSLawrence Stewart /* Get counter and corresponding time. */ 59*f464c5ccSLawrence Stewart if ((flags & FFCLOCK_FAST) == FFCLOCK_FAST) 60*f464c5ccSLawrence Stewart ffclock_last_tick(&ffc, bt, flags); 61*f464c5ccSLawrence Stewart else { 62*f464c5ccSLawrence Stewart ffclock_read_counter(&ffc); 63*f464c5ccSLawrence Stewart ffclock_convert_abs(ffc, bt, flags); 64*f464c5ccSLawrence Stewart } 65*f464c5ccSLawrence Stewart 66*f464c5ccSLawrence Stewart /* Current ffclock estimate, use update_ffcount as generation number. */ 67*f464c5ccSLawrence Stewart do { 68*f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 69*f464c5ccSLawrence Stewart bcopy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 70*f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 71*f464c5ccSLawrence Stewart 72*f464c5ccSLawrence Stewart /* 73*f464c5ccSLawrence Stewart * Leap second adjustment. Total as seen by synchronisation algorithm 74*f464c5ccSLawrence Stewart * since it started. cest.leapsec_next is the ffcounter prediction of 75*f464c5ccSLawrence Stewart * when the next leapsecond occurs. 76*f464c5ccSLawrence Stewart */ 77*f464c5ccSLawrence Stewart if ((flags & FFCLOCK_LEAPSEC) == FFCLOCK_LEAPSEC) { 78*f464c5ccSLawrence Stewart bt->sec -= cest.leapsec_total; 79*f464c5ccSLawrence Stewart if (ffc > cest.leapsec_next) 80*f464c5ccSLawrence Stewart bt->sec -= cest.leapsec; 81*f464c5ccSLawrence Stewart } 82*f464c5ccSLawrence Stewart 83*f464c5ccSLawrence Stewart /* Boot time adjustment, for uptime/monotonic clocks. */ 84*f464c5ccSLawrence Stewart if ((flags & FFCLOCK_UPTIME) == FFCLOCK_UPTIME) { 85*f464c5ccSLawrence Stewart bintime_sub(bt, &ffclock_boottime); 86*f464c5ccSLawrence Stewart } 87*f464c5ccSLawrence Stewart 88*f464c5ccSLawrence Stewart /* Compute error bound if a valid pointer has been passed. */ 89*f464c5ccSLawrence Stewart if (error_bound) { 90*f464c5ccSLawrence Stewart ffdelta_error = ffc - cest.update_ffcount; 91*f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta_error, error_bound); 92*f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 93*f464c5ccSLawrence Stewart bintime_mul(error_bound, cest.errb_rate * 94*f464c5ccSLawrence Stewart (uint64_t)18446744073709LL); 95*f464c5ccSLawrence Stewart /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns] */ 96*f464c5ccSLawrence Stewart bintime_addx(error_bound, cest.errb_abs * 97*f464c5ccSLawrence Stewart (uint64_t)18446744073LL); 98*f464c5ccSLawrence Stewart } 99*f464c5ccSLawrence Stewart 100*f464c5ccSLawrence Stewart if (ffcount) 101*f464c5ccSLawrence Stewart *ffcount = ffc; 102*f464c5ccSLawrence Stewart } 103*f464c5ccSLawrence Stewart 104*f464c5ccSLawrence Stewart /* 105*f464c5ccSLawrence Stewart * Feed-forward difference clock. This should be the preferred way to convert a 106*f464c5ccSLawrence Stewart * time interval in ffcounter values into a time interval in seconds. If a valid 107*f464c5ccSLawrence Stewart * pointer is passed, an upper bound on the error in computing the time interval 108*f464c5ccSLawrence Stewart * in seconds is provided. 109*f464c5ccSLawrence Stewart */ 110*f464c5ccSLawrence Stewart void 111*f464c5ccSLawrence Stewart ffclock_difftime(ffcounter ffdelta, struct bintime *bt, 112*f464c5ccSLawrence Stewart struct bintime *error_bound) 113*f464c5ccSLawrence Stewart { 114*f464c5ccSLawrence Stewart ffcounter update_ffcount; 115*f464c5ccSLawrence Stewart uint32_t err_rate; 116*f464c5ccSLawrence Stewart 117*f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, bt); 118*f464c5ccSLawrence Stewart 119*f464c5ccSLawrence Stewart if (error_bound) { 120*f464c5ccSLawrence Stewart do { 121*f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 122*f464c5ccSLawrence Stewart err_rate = ffclock_estimate.errb_rate; 123*f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 124*f464c5ccSLawrence Stewart 125*f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, error_bound); 126*f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 127*f464c5ccSLawrence Stewart bintime_mul(error_bound, err_rate * (uint64_t)18446744073709LL); 128*f464c5ccSLawrence Stewart } 129*f464c5ccSLawrence Stewart } 130