1f464c5ccSLawrence Stewart /*- 2f464c5ccSLawrence Stewart * Copyright (c) 2011 The University of Melbourne 3f464c5ccSLawrence Stewart * All rights reserved. 4f464c5ccSLawrence Stewart * 5f464c5ccSLawrence Stewart * This software was developed by Julien Ridoux at the University of Melbourne 6f464c5ccSLawrence Stewart * under sponsorship from the FreeBSD Foundation. 7f464c5ccSLawrence Stewart * 8f464c5ccSLawrence Stewart * Redistribution and use in source and binary forms, with or without 9f464c5ccSLawrence Stewart * modification, are permitted provided that the following conditions 10f464c5ccSLawrence Stewart * are met: 11f464c5ccSLawrence Stewart * 1. Redistributions of source code must retain the above copyright 12f464c5ccSLawrence Stewart * notice, this list of conditions and the following disclaimer. 13f464c5ccSLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright 14f464c5ccSLawrence Stewart * notice, this list of conditions and the following disclaimer in the 15f464c5ccSLawrence Stewart * documentation and/or other materials provided with the distribution. 16f464c5ccSLawrence Stewart * 17f464c5ccSLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18f464c5ccSLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19f464c5ccSLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20f464c5ccSLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21f464c5ccSLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22f464c5ccSLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23f464c5ccSLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24f464c5ccSLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25f464c5ccSLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26f464c5ccSLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27f464c5ccSLawrence Stewart * SUCH DAMAGE. 28f464c5ccSLawrence Stewart */ 29f464c5ccSLawrence Stewart 30f464c5ccSLawrence Stewart #include <sys/cdefs.h> 31f464c5ccSLawrence Stewart __FBSDID("$FreeBSD$"); 32f464c5ccSLawrence Stewart 33*cf13a585SLawrence Stewart #include "opt_ffclock.h" 34*cf13a585SLawrence Stewart 35f464c5ccSLawrence Stewart #include <sys/param.h> 36*cf13a585SLawrence Stewart #include <sys/bus.h> 37*cf13a585SLawrence Stewart #include <sys/kernel.h> 38*cf13a585SLawrence Stewart #include <sys/lock.h> 39*cf13a585SLawrence Stewart #include <sys/module.h> 40*cf13a585SLawrence Stewart #include <sys/mutex.h> 41*cf13a585SLawrence Stewart #include <sys/priv.h> 42*cf13a585SLawrence Stewart #include <sys/proc.h> 439bce0f05SLawrence Stewart #include <sys/sbuf.h> 44*cf13a585SLawrence Stewart #include <sys/sysent.h> 45*cf13a585SLawrence Stewart #include <sys/sysproto.h> 469bce0f05SLawrence Stewart #include <sys/sysctl.h> 47f464c5ccSLawrence Stewart #include <sys/systm.h> 48f464c5ccSLawrence Stewart #include <sys/timeffc.h> 49f464c5ccSLawrence Stewart 50*cf13a585SLawrence Stewart #ifdef FFCLOCK 51*cf13a585SLawrence Stewart 52f464c5ccSLawrence Stewart extern struct ffclock_estimate ffclock_estimate; 53f464c5ccSLawrence Stewart extern struct bintime ffclock_boottime; 54*cf13a585SLawrence Stewart extern int8_t ffclock_updated; 55*cf13a585SLawrence Stewart extern struct mtx ffclock_mtx; 56f464c5ccSLawrence Stewart 57f464c5ccSLawrence Stewart /* 58f464c5ccSLawrence Stewart * Feed-forward clock absolute time. This should be the preferred way to read 59f464c5ccSLawrence Stewart * the feed-forward clock for "wall-clock" type time. The flags allow to compose 60f464c5ccSLawrence Stewart * various flavours of absolute time (e.g. with or without leap seconds taken 61f464c5ccSLawrence Stewart * into account). If valid pointers are provided, the ffcounter value and an 62f464c5ccSLawrence Stewart * upper bound on clock error associated with the bintime are provided. 63f464c5ccSLawrence Stewart * NOTE: use ffclock_convert_abs() to differ the conversion of a ffcounter value 64f464c5ccSLawrence Stewart * read earlier. 65f464c5ccSLawrence Stewart */ 66f464c5ccSLawrence Stewart void 67f464c5ccSLawrence Stewart ffclock_abstime(ffcounter *ffcount, struct bintime *bt, 68f464c5ccSLawrence Stewart struct bintime *error_bound, uint32_t flags) 69f464c5ccSLawrence Stewart { 70f464c5ccSLawrence Stewart struct ffclock_estimate cest; 71f464c5ccSLawrence Stewart ffcounter ffc; 72f464c5ccSLawrence Stewart ffcounter update_ffcount; 73f464c5ccSLawrence Stewart ffcounter ffdelta_error; 74f464c5ccSLawrence Stewart 75f464c5ccSLawrence Stewart /* Get counter and corresponding time. */ 76f464c5ccSLawrence Stewart if ((flags & FFCLOCK_FAST) == FFCLOCK_FAST) 77f464c5ccSLawrence Stewart ffclock_last_tick(&ffc, bt, flags); 78f464c5ccSLawrence Stewart else { 79f464c5ccSLawrence Stewart ffclock_read_counter(&ffc); 80f464c5ccSLawrence Stewart ffclock_convert_abs(ffc, bt, flags); 81f464c5ccSLawrence Stewart } 82f464c5ccSLawrence Stewart 83f464c5ccSLawrence Stewart /* Current ffclock estimate, use update_ffcount as generation number. */ 84f464c5ccSLawrence Stewart do { 85f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 86f464c5ccSLawrence Stewart bcopy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 87f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 88f464c5ccSLawrence Stewart 89f464c5ccSLawrence Stewart /* 90f464c5ccSLawrence Stewart * Leap second adjustment. Total as seen by synchronisation algorithm 91f464c5ccSLawrence Stewart * since it started. cest.leapsec_next is the ffcounter prediction of 92f464c5ccSLawrence Stewart * when the next leapsecond occurs. 93f464c5ccSLawrence Stewart */ 94f464c5ccSLawrence Stewart if ((flags & FFCLOCK_LEAPSEC) == FFCLOCK_LEAPSEC) { 95f464c5ccSLawrence Stewart bt->sec -= cest.leapsec_total; 96f464c5ccSLawrence Stewart if (ffc > cest.leapsec_next) 97f464c5ccSLawrence Stewart bt->sec -= cest.leapsec; 98f464c5ccSLawrence Stewart } 99f464c5ccSLawrence Stewart 100f464c5ccSLawrence Stewart /* Boot time adjustment, for uptime/monotonic clocks. */ 101f464c5ccSLawrence Stewart if ((flags & FFCLOCK_UPTIME) == FFCLOCK_UPTIME) { 102f464c5ccSLawrence Stewart bintime_sub(bt, &ffclock_boottime); 103f464c5ccSLawrence Stewart } 104f464c5ccSLawrence Stewart 105f464c5ccSLawrence Stewart /* Compute error bound if a valid pointer has been passed. */ 106f464c5ccSLawrence Stewart if (error_bound) { 107f464c5ccSLawrence Stewart ffdelta_error = ffc - cest.update_ffcount; 108f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta_error, error_bound); 109f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 110f464c5ccSLawrence Stewart bintime_mul(error_bound, cest.errb_rate * 111f464c5ccSLawrence Stewart (uint64_t)18446744073709LL); 112f464c5ccSLawrence Stewart /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns] */ 113f464c5ccSLawrence Stewart bintime_addx(error_bound, cest.errb_abs * 114f464c5ccSLawrence Stewart (uint64_t)18446744073LL); 115f464c5ccSLawrence Stewart } 116f464c5ccSLawrence Stewart 117f464c5ccSLawrence Stewart if (ffcount) 118f464c5ccSLawrence Stewart *ffcount = ffc; 119f464c5ccSLawrence Stewart } 120f464c5ccSLawrence Stewart 121f464c5ccSLawrence Stewart /* 122f464c5ccSLawrence Stewart * Feed-forward difference clock. This should be the preferred way to convert a 123f464c5ccSLawrence Stewart * time interval in ffcounter values into a time interval in seconds. If a valid 124f464c5ccSLawrence Stewart * pointer is passed, an upper bound on the error in computing the time interval 125f464c5ccSLawrence Stewart * in seconds is provided. 126f464c5ccSLawrence Stewart */ 127f464c5ccSLawrence Stewart void 128f464c5ccSLawrence Stewart ffclock_difftime(ffcounter ffdelta, struct bintime *bt, 129f464c5ccSLawrence Stewart struct bintime *error_bound) 130f464c5ccSLawrence Stewart { 131f464c5ccSLawrence Stewart ffcounter update_ffcount; 132f464c5ccSLawrence Stewart uint32_t err_rate; 133f464c5ccSLawrence Stewart 134f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, bt); 135f464c5ccSLawrence Stewart 136f464c5ccSLawrence Stewart if (error_bound) { 137f464c5ccSLawrence Stewart do { 138f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 139f464c5ccSLawrence Stewart err_rate = ffclock_estimate.errb_rate; 140f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 141f464c5ccSLawrence Stewart 142f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, error_bound); 143f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 144f464c5ccSLawrence Stewart bintime_mul(error_bound, err_rate * (uint64_t)18446744073709LL); 145f464c5ccSLawrence Stewart } 146f464c5ccSLawrence Stewart } 1479bce0f05SLawrence Stewart 1489bce0f05SLawrence Stewart /* 1499bce0f05SLawrence Stewart * Sysctl for the Feed-Forward Clock. 1509bce0f05SLawrence Stewart */ 1519bce0f05SLawrence Stewart 1529bce0f05SLawrence Stewart static int ffclock_version = 2; 1539bce0f05SLawrence Stewart SYSCTL_NODE(_kern, OID_AUTO, ffclock, CTLFLAG_RW, 0, 1549bce0f05SLawrence Stewart "Feed-Forward Clock Support"); 1559bce0f05SLawrence Stewart SYSCTL_INT(_kern_ffclock, OID_AUTO, version, CTLFLAG_RD, &ffclock_version, 0, 1569bce0f05SLawrence Stewart "Version of Feed-Forward Clock Support"); 1579bce0f05SLawrence Stewart 1589bce0f05SLawrence Stewart /* 1599bce0f05SLawrence Stewart * Sysctl to select which clock is read when calling any of the 1609bce0f05SLawrence Stewart * [get]{bin,nano,micro}[up]time() functions. 1619bce0f05SLawrence Stewart */ 1629bce0f05SLawrence Stewart char *sysclocks[] = {"feedback", "feed-forward"}; 1639bce0f05SLawrence Stewart 1649bce0f05SLawrence Stewart #define NUM_SYSCLOCKS (sizeof(sysclocks) / sizeof(*sysclocks)) 1659bce0f05SLawrence Stewart 1669bce0f05SLawrence Stewart /* Report or change the active timecounter hardware. */ 1679bce0f05SLawrence Stewart static int 1689bce0f05SLawrence Stewart sysctl_kern_ffclock_choice(SYSCTL_HANDLER_ARGS) 1699bce0f05SLawrence Stewart { 1709bce0f05SLawrence Stewart struct sbuf *s; 1719bce0f05SLawrence Stewart int clk, error; 1729bce0f05SLawrence Stewart 1739bce0f05SLawrence Stewart s = sbuf_new_for_sysctl(NULL, NULL, 16 * NUM_SYSCLOCKS, req); 1749bce0f05SLawrence Stewart if (s == NULL) 1759bce0f05SLawrence Stewart return (ENOMEM); 1769bce0f05SLawrence Stewart 1779bce0f05SLawrence Stewart for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 1789bce0f05SLawrence Stewart sbuf_cat(s, sysclocks[clk]); 1799bce0f05SLawrence Stewart if (clk + 1 < NUM_SYSCLOCKS) 1809bce0f05SLawrence Stewart sbuf_cat(s, " "); 1819bce0f05SLawrence Stewart } 1829bce0f05SLawrence Stewart error = sbuf_finish(s); 1839bce0f05SLawrence Stewart sbuf_delete(s); 1849bce0f05SLawrence Stewart 1859bce0f05SLawrence Stewart return (error); 1869bce0f05SLawrence Stewart } 1879bce0f05SLawrence Stewart 1889bce0f05SLawrence Stewart SYSCTL_PROC(_kern_ffclock, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD, 1899bce0f05SLawrence Stewart 0, 0, sysctl_kern_ffclock_choice, "A", "Clock paradigms available"); 1909bce0f05SLawrence Stewart 1919bce0f05SLawrence Stewart extern int sysclock_active; 1929bce0f05SLawrence Stewart 1939bce0f05SLawrence Stewart static int 1949bce0f05SLawrence Stewart sysctl_kern_ffclock_active(SYSCTL_HANDLER_ARGS) 1959bce0f05SLawrence Stewart { 1969bce0f05SLawrence Stewart char newclock[32]; 1979bce0f05SLawrence Stewart int error; 1989bce0f05SLawrence Stewart 1999bce0f05SLawrence Stewart switch (sysclock_active) { 2009bce0f05SLawrence Stewart case SYSCLOCK_FBCK: 2019bce0f05SLawrence Stewart strlcpy(newclock, sysclocks[SYSCLOCK_FBCK], sizeof(newclock)); 2029bce0f05SLawrence Stewart break; 2039bce0f05SLawrence Stewart case SYSCLOCK_FFWD: 2049bce0f05SLawrence Stewart strlcpy(newclock, sysclocks[SYSCLOCK_FFWD], sizeof(newclock)); 2059bce0f05SLawrence Stewart break; 2069bce0f05SLawrence Stewart } 2079bce0f05SLawrence Stewart 2089bce0f05SLawrence Stewart error = sysctl_handle_string(oidp, &newclock[0], sizeof(newclock), req); 2099bce0f05SLawrence Stewart if (error != 0 || req->newptr == NULL) 2109bce0f05SLawrence Stewart return (error); 2119bce0f05SLawrence Stewart if (strncmp(newclock, sysclocks[SYSCLOCK_FBCK], 2129bce0f05SLawrence Stewart sizeof(sysclocks[SYSCLOCK_FBCK])) == 0) 2139bce0f05SLawrence Stewart sysclock_active = SYSCLOCK_FBCK; 2149bce0f05SLawrence Stewart else if (strncmp(newclock, sysclocks[SYSCLOCK_FFWD], 2159bce0f05SLawrence Stewart sizeof(sysclocks[SYSCLOCK_FFWD])) == 0) 2169bce0f05SLawrence Stewart sysclock_active = SYSCLOCK_FFWD; 2179bce0f05SLawrence Stewart else 2189bce0f05SLawrence Stewart return (EINVAL); 2199bce0f05SLawrence Stewart 2209bce0f05SLawrence Stewart return (error); 2219bce0f05SLawrence Stewart } 2229bce0f05SLawrence Stewart 2239bce0f05SLawrence Stewart SYSCTL_PROC(_kern_ffclock, OID_AUTO, active, CTLTYPE_STRING | CTLFLAG_RW, 2249bce0f05SLawrence Stewart 0, 0, sysctl_kern_ffclock_active, "A", "Kernel clock selected"); 2259bce0f05SLawrence Stewart 226*cf13a585SLawrence Stewart int sysctl_kern_ffclock_ffcounter_bypass = 0; 227*cf13a585SLawrence Stewart 228*cf13a585SLawrence Stewart SYSCTL_INT(_kern_ffclock, OID_AUTO, ffcounter_bypass, CTLFLAG_RW, 229*cf13a585SLawrence Stewart &sysctl_kern_ffclock_ffcounter_bypass, 0, 230*cf13a585SLawrence Stewart "Use reliable hardware timecounter as the Feed-Forward Counter"); 231*cf13a585SLawrence Stewart 2329bce0f05SLawrence Stewart /* 2339bce0f05SLawrence Stewart * High level functions to access the Feed-Forward Clock. 2349bce0f05SLawrence Stewart */ 2359bce0f05SLawrence Stewart void 2369bce0f05SLawrence Stewart ffclock_bintime(struct bintime *bt) 2379bce0f05SLawrence Stewart { 2389bce0f05SLawrence Stewart 2399bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2409bce0f05SLawrence Stewart } 2419bce0f05SLawrence Stewart 2429bce0f05SLawrence Stewart void 2439bce0f05SLawrence Stewart ffclock_nanotime(struct timespec *tsp) 2449bce0f05SLawrence Stewart { 2459bce0f05SLawrence Stewart struct bintime bt; 2469bce0f05SLawrence Stewart 2479bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2489bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 2499bce0f05SLawrence Stewart } 2509bce0f05SLawrence Stewart 2519bce0f05SLawrence Stewart void 2529bce0f05SLawrence Stewart ffclock_microtime(struct timeval *tvp) 2539bce0f05SLawrence Stewart { 2549bce0f05SLawrence Stewart struct bintime bt; 2559bce0f05SLawrence Stewart 2569bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2579bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2589bce0f05SLawrence Stewart } 2599bce0f05SLawrence Stewart 2609bce0f05SLawrence Stewart void 2619bce0f05SLawrence Stewart ffclock_getbintime(struct bintime *bt) 2629bce0f05SLawrence Stewart { 2639bce0f05SLawrence Stewart 2649bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 2659bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2669bce0f05SLawrence Stewart } 2679bce0f05SLawrence Stewart 2689bce0f05SLawrence Stewart void 2699bce0f05SLawrence Stewart ffclock_getnanotime(struct timespec *tsp) 2709bce0f05SLawrence Stewart { 2719bce0f05SLawrence Stewart struct bintime bt; 2729bce0f05SLawrence Stewart 2739bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 2749bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2759bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 2769bce0f05SLawrence Stewart } 2779bce0f05SLawrence Stewart 2789bce0f05SLawrence Stewart void 2799bce0f05SLawrence Stewart ffclock_getmicrotime(struct timeval *tvp) 2809bce0f05SLawrence Stewart { 2819bce0f05SLawrence Stewart struct bintime bt; 2829bce0f05SLawrence Stewart 2839bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 2849bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2859bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2869bce0f05SLawrence Stewart } 2879bce0f05SLawrence Stewart 2889bce0f05SLawrence Stewart void 2899bce0f05SLawrence Stewart ffclock_binuptime(struct bintime *bt) 2909bce0f05SLawrence Stewart { 2919bce0f05SLawrence Stewart 2929bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 2939bce0f05SLawrence Stewart } 2949bce0f05SLawrence Stewart 2959bce0f05SLawrence Stewart void 2969bce0f05SLawrence Stewart ffclock_nanouptime(struct timespec *tsp) 2979bce0f05SLawrence Stewart { 2989bce0f05SLawrence Stewart struct bintime bt; 2999bce0f05SLawrence Stewart 3009bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3019bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3029bce0f05SLawrence Stewart } 3039bce0f05SLawrence Stewart 3049bce0f05SLawrence Stewart void 3059bce0f05SLawrence Stewart ffclock_microuptime(struct timeval *tvp) 3069bce0f05SLawrence Stewart { 3079bce0f05SLawrence Stewart struct bintime bt; 3089bce0f05SLawrence Stewart 3099bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3109bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3119bce0f05SLawrence Stewart } 3129bce0f05SLawrence Stewart 3139bce0f05SLawrence Stewart void 3149bce0f05SLawrence Stewart ffclock_getbinuptime(struct bintime *bt) 3159bce0f05SLawrence Stewart { 3169bce0f05SLawrence Stewart 3179bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 3189bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3199bce0f05SLawrence Stewart } 3209bce0f05SLawrence Stewart 3219bce0f05SLawrence Stewart void 3229bce0f05SLawrence Stewart ffclock_getnanouptime(struct timespec *tsp) 3239bce0f05SLawrence Stewart { 3249bce0f05SLawrence Stewart struct bintime bt; 3259bce0f05SLawrence Stewart 3269bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 3279bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3289bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3299bce0f05SLawrence Stewart } 3309bce0f05SLawrence Stewart 3319bce0f05SLawrence Stewart void 3329bce0f05SLawrence Stewart ffclock_getmicrouptime(struct timeval *tvp) 3339bce0f05SLawrence Stewart { 3349bce0f05SLawrence Stewart struct bintime bt; 3359bce0f05SLawrence Stewart 3369bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 3379bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3389bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3399bce0f05SLawrence Stewart } 3409bce0f05SLawrence Stewart 3419bce0f05SLawrence Stewart void 3429bce0f05SLawrence Stewart ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt) 3439bce0f05SLawrence Stewart { 3449bce0f05SLawrence Stewart 3459bce0f05SLawrence Stewart ffclock_difftime(ffdelta, bt, NULL); 3469bce0f05SLawrence Stewart } 3479bce0f05SLawrence Stewart 3489bce0f05SLawrence Stewart void 3499bce0f05SLawrence Stewart ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp) 3509bce0f05SLawrence Stewart { 3519bce0f05SLawrence Stewart struct bintime bt; 3529bce0f05SLawrence Stewart 3539bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3549bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3559bce0f05SLawrence Stewart } 3569bce0f05SLawrence Stewart 3579bce0f05SLawrence Stewart void 3589bce0f05SLawrence Stewart ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp) 3599bce0f05SLawrence Stewart { 3609bce0f05SLawrence Stewart struct bintime bt; 3619bce0f05SLawrence Stewart 3629bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3639bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3649bce0f05SLawrence Stewart } 365*cf13a585SLawrence Stewart 366*cf13a585SLawrence Stewart /* 367*cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the current value of 368*cf13a585SLawrence Stewart * the Feed-Forward Clock counter. 369*cf13a585SLawrence Stewart */ 370*cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 371*cf13a585SLawrence Stewart struct ffclock_getcounter_args { 372*cf13a585SLawrence Stewart ffcounter *ffcount; 373*cf13a585SLawrence Stewart }; 374*cf13a585SLawrence Stewart #endif 375*cf13a585SLawrence Stewart /* ARGSUSED */ 376*cf13a585SLawrence Stewart int 377*cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 378*cf13a585SLawrence Stewart { 379*cf13a585SLawrence Stewart ffcounter ffcount; 380*cf13a585SLawrence Stewart int error; 381*cf13a585SLawrence Stewart 382*cf13a585SLawrence Stewart ffcount = 0; 383*cf13a585SLawrence Stewart ffclock_read_counter(&ffcount); 384*cf13a585SLawrence Stewart if (ffcount == 0) 385*cf13a585SLawrence Stewart return (EAGAIN); 386*cf13a585SLawrence Stewart error = copyout(&ffcount, uap->ffcount, sizeof(ffcounter)); 387*cf13a585SLawrence Stewart 388*cf13a585SLawrence Stewart return (error); 389*cf13a585SLawrence Stewart } 390*cf13a585SLawrence Stewart 391*cf13a585SLawrence Stewart /* 392*cf13a585SLawrence Stewart * System call allowing the synchronisation daemon to push new feed-foward clock 393*cf13a585SLawrence Stewart * estimates to the kernel. Acquire ffclock_mtx to prevent concurrent updates 394*cf13a585SLawrence Stewart * and ensure data consistency. 395*cf13a585SLawrence Stewart * NOTE: ffclock_updated signals the fftimehands that new estimates are 396*cf13a585SLawrence Stewart * available. The updated estimates are picked up by the fftimehands on next 397*cf13a585SLawrence Stewart * tick, which could take as long as 1/hz seconds (if ticks are not missed). 398*cf13a585SLawrence Stewart */ 399*cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 400*cf13a585SLawrence Stewart struct ffclock_setestimate_args { 401*cf13a585SLawrence Stewart struct ffclock_estimate *cest; 402*cf13a585SLawrence Stewart }; 403*cf13a585SLawrence Stewart #endif 404*cf13a585SLawrence Stewart /* ARGSUSED */ 405*cf13a585SLawrence Stewart int 406*cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 407*cf13a585SLawrence Stewart { 408*cf13a585SLawrence Stewart struct ffclock_estimate cest; 409*cf13a585SLawrence Stewart int error; 410*cf13a585SLawrence Stewart 411*cf13a585SLawrence Stewart /* Reuse of PRIV_CLOCK_SETTIME. */ 412*cf13a585SLawrence Stewart if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) 413*cf13a585SLawrence Stewart return (error); 414*cf13a585SLawrence Stewart 415*cf13a585SLawrence Stewart if ((error = copyin(uap->cest, &cest, sizeof(struct ffclock_estimate))) 416*cf13a585SLawrence Stewart != 0) 417*cf13a585SLawrence Stewart return (error); 418*cf13a585SLawrence Stewart 419*cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 420*cf13a585SLawrence Stewart memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 421*cf13a585SLawrence Stewart ffclock_updated++; 422*cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 423*cf13a585SLawrence Stewart return (error); 424*cf13a585SLawrence Stewart } 425*cf13a585SLawrence Stewart 426*cf13a585SLawrence Stewart /* 427*cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the clock estimates 428*cf13a585SLawrence Stewart * stored within the kernel. It is useful to kickstart the synchronisation 429*cf13a585SLawrence Stewart * daemon with the kernel's knowledge of hardware timecounter. 430*cf13a585SLawrence Stewart */ 431*cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 432*cf13a585SLawrence Stewart struct ffclock_getestimate_args { 433*cf13a585SLawrence Stewart struct ffclock_estimate *cest; 434*cf13a585SLawrence Stewart }; 435*cf13a585SLawrence Stewart #endif 436*cf13a585SLawrence Stewart /* ARGSUSED */ 437*cf13a585SLawrence Stewart int 438*cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 439*cf13a585SLawrence Stewart { 440*cf13a585SLawrence Stewart struct ffclock_estimate cest; 441*cf13a585SLawrence Stewart int error; 442*cf13a585SLawrence Stewart 443*cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 444*cf13a585SLawrence Stewart memcpy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); 445*cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 446*cf13a585SLawrence Stewart error = copyout(&cest, uap->cest, sizeof(struct ffclock_estimate)); 447*cf13a585SLawrence Stewart return (error); 448*cf13a585SLawrence Stewart } 449*cf13a585SLawrence Stewart 450*cf13a585SLawrence Stewart #else /* !FFCLOCK */ 451*cf13a585SLawrence Stewart 452*cf13a585SLawrence Stewart int 453*cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 454*cf13a585SLawrence Stewart { 455*cf13a585SLawrence Stewart 456*cf13a585SLawrence Stewart return (ENOSYS); 457*cf13a585SLawrence Stewart } 458*cf13a585SLawrence Stewart 459*cf13a585SLawrence Stewart int 460*cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 461*cf13a585SLawrence Stewart { 462*cf13a585SLawrence Stewart 463*cf13a585SLawrence Stewart return (ENOSYS); 464*cf13a585SLawrence Stewart } 465*cf13a585SLawrence Stewart 466*cf13a585SLawrence Stewart int 467*cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 468*cf13a585SLawrence Stewart { 469*cf13a585SLawrence Stewart 470*cf13a585SLawrence Stewart return (ENOSYS); 471*cf13a585SLawrence Stewart } 472*cf13a585SLawrence Stewart 473*cf13a585SLawrence Stewart #endif /* FFCLOCK */ 474