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