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 5266761af3SLawrence Stewart FEATURE(ffclock, "Feed-forward clock support"); 5366761af3SLawrence 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 /* 15166dcfed3SLawrence Stewart * Create a new kern.sysclock sysctl node, which will be home to some generic 15266dcfed3SLawrence Stewart * sysclock configuration variables. Feed-forward clock specific variables will 15366dcfed3SLawrence Stewart * live under the ffclock subnode. 1549bce0f05SLawrence Stewart */ 1559bce0f05SLawrence Stewart 15666dcfed3SLawrence Stewart SYSCTL_NODE(_kern, OID_AUTO, sysclock, CTLFLAG_RW, 0, 15766dcfed3SLawrence Stewart "System clock related configuration"); 15866dcfed3SLawrence Stewart SYSCTL_NODE(_kern_sysclock, OID_AUTO, ffclock, CTLFLAG_RW, 0, 15966dcfed3SLawrence Stewart "Feed-forward clock configuration"); 1609bce0f05SLawrence Stewart 16166dcfed3SLawrence Stewart static char *sysclocks[] = {"feedback", "feed-forward"}; 16266dcfed3SLawrence Stewart #define MAX_SYSCLOCK_NAME_LEN 16 163*02abd400SPedro F. Giffuni #define NUM_SYSCLOCKS nitems(sysclocks) 1649bce0f05SLawrence Stewart 16566dcfed3SLawrence Stewart static int ffclock_version = 2; 16666dcfed3SLawrence Stewart SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, version, CTLFLAG_RD, 16766dcfed3SLawrence Stewart &ffclock_version, 0, "Feed-forward clock kernel version"); 16866dcfed3SLawrence Stewart 16966dcfed3SLawrence Stewart /* List available sysclocks. */ 1709bce0f05SLawrence Stewart static int 17166dcfed3SLawrence Stewart sysctl_kern_sysclock_available(SYSCTL_HANDLER_ARGS) 1729bce0f05SLawrence Stewart { 1739bce0f05SLawrence Stewart struct sbuf *s; 1749bce0f05SLawrence Stewart int clk, error; 1759bce0f05SLawrence Stewart 17666dcfed3SLawrence Stewart s = sbuf_new_for_sysctl(NULL, NULL, 17766dcfed3SLawrence Stewart MAX_SYSCLOCK_NAME_LEN * NUM_SYSCLOCKS, req); 1789bce0f05SLawrence Stewart if (s == NULL) 1799bce0f05SLawrence Stewart return (ENOMEM); 1809bce0f05SLawrence Stewart 1819bce0f05SLawrence Stewart for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 1829bce0f05SLawrence Stewart sbuf_cat(s, sysclocks[clk]); 1839bce0f05SLawrence Stewart if (clk + 1 < NUM_SYSCLOCKS) 1849bce0f05SLawrence Stewart sbuf_cat(s, " "); 1859bce0f05SLawrence Stewart } 1869bce0f05SLawrence Stewart error = sbuf_finish(s); 1879bce0f05SLawrence Stewart sbuf_delete(s); 1889bce0f05SLawrence Stewart 1899bce0f05SLawrence Stewart return (error); 1909bce0f05SLawrence Stewart } 1919bce0f05SLawrence Stewart 19266dcfed3SLawrence Stewart SYSCTL_PROC(_kern_sysclock, OID_AUTO, available, CTLTYPE_STRING | CTLFLAG_RD, 19366dcfed3SLawrence Stewart 0, 0, sysctl_kern_sysclock_available, "A", 19466dcfed3SLawrence Stewart "List of available system clocks"); 1959bce0f05SLawrence Stewart 19666dcfed3SLawrence Stewart /* 19766dcfed3SLawrence Stewart * Return the name of the active system clock if read, or attempt to change 19866dcfed3SLawrence Stewart * the active system clock to the user specified one if written to. The active 19966dcfed3SLawrence Stewart * system clock is read when calling any of the [get]{bin,nano,micro}[up]time() 20066dcfed3SLawrence Stewart * functions. 20166dcfed3SLawrence Stewart */ 2029bce0f05SLawrence Stewart static int 20366dcfed3SLawrence Stewart sysctl_kern_sysclock_active(SYSCTL_HANDLER_ARGS) 2049bce0f05SLawrence Stewart { 20566dcfed3SLawrence Stewart char newclock[MAX_SYSCLOCK_NAME_LEN]; 2060e1152fcSHans Petter Selasky int error; 2070e1152fcSHans Petter Selasky int clk; 2089bce0f05SLawrence Stewart 20966dcfed3SLawrence Stewart /* Return the name of the current active sysclock. */ 21066dcfed3SLawrence Stewart strlcpy(newclock, sysclocks[sysclock_active], sizeof(newclock)); 2110e1152fcSHans Petter Selasky error = sysctl_handle_string(oidp, newclock, sizeof(newclock), req); 2120e1152fcSHans Petter Selasky 2130e1152fcSHans Petter Selasky /* Check for error or no change */ 2140e1152fcSHans Petter Selasky if (error != 0 || req->newptr == NULL) 2150e1152fcSHans Petter Selasky goto done; 2160e1152fcSHans Petter Selasky 2170e1152fcSHans Petter Selasky /* Change the active sysclock to the user specified one: */ 21866dcfed3SLawrence Stewart error = EINVAL; 21966dcfed3SLawrence Stewart for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 2200e1152fcSHans Petter Selasky if (strncmp(newclock, sysclocks[clk], 2210e1152fcSHans Petter Selasky MAX_SYSCLOCK_NAME_LEN - 1)) { 2220e1152fcSHans Petter Selasky continue; 2230e1152fcSHans Petter Selasky } 22466dcfed3SLawrence Stewart sysclock_active = clk; 22566dcfed3SLawrence Stewart error = 0; 2269bce0f05SLawrence Stewart break; 2279bce0f05SLawrence Stewart } 2280e1152fcSHans Petter Selasky done: 2299bce0f05SLawrence Stewart return (error); 2309bce0f05SLawrence Stewart } 2319bce0f05SLawrence Stewart 23266dcfed3SLawrence Stewart SYSCTL_PROC(_kern_sysclock, OID_AUTO, active, CTLTYPE_STRING | CTLFLAG_RW, 23366dcfed3SLawrence Stewart 0, 0, sysctl_kern_sysclock_active, "A", 23466dcfed3SLawrence Stewart "Name of the active system clock which is currently serving time"); 2359bce0f05SLawrence Stewart 23666dcfed3SLawrence Stewart static int sysctl_kern_ffclock_ffcounter_bypass = 0; 23766dcfed3SLawrence Stewart SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, ffcounter_bypass, CTLFLAG_RW, 238cf13a585SLawrence Stewart &sysctl_kern_ffclock_ffcounter_bypass, 0, 23966dcfed3SLawrence Stewart "Use reliable hardware timecounter as the feed-forward counter"); 240cf13a585SLawrence Stewart 2419bce0f05SLawrence Stewart /* 2429bce0f05SLawrence Stewart * High level functions to access the Feed-Forward Clock. 2439bce0f05SLawrence Stewart */ 2449bce0f05SLawrence Stewart void 2459bce0f05SLawrence Stewart ffclock_bintime(struct bintime *bt) 2469bce0f05SLawrence Stewart { 2479bce0f05SLawrence Stewart 2489bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2499bce0f05SLawrence Stewart } 2509bce0f05SLawrence Stewart 2519bce0f05SLawrence Stewart void 2529bce0f05SLawrence Stewart ffclock_nanotime(struct timespec *tsp) 2539bce0f05SLawrence Stewart { 2549bce0f05SLawrence Stewart struct bintime bt; 2559bce0f05SLawrence Stewart 2569bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2579bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 2589bce0f05SLawrence Stewart } 2599bce0f05SLawrence Stewart 2609bce0f05SLawrence Stewart void 2619bce0f05SLawrence Stewart ffclock_microtime(struct timeval *tvp) 2629bce0f05SLawrence Stewart { 2639bce0f05SLawrence Stewart struct bintime bt; 2649bce0f05SLawrence Stewart 2659bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2669bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2679bce0f05SLawrence Stewart } 2689bce0f05SLawrence Stewart 2699bce0f05SLawrence Stewart void 2709bce0f05SLawrence Stewart ffclock_getbintime(struct bintime *bt) 2719bce0f05SLawrence Stewart { 2729bce0f05SLawrence Stewart 2739bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 2749bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2759bce0f05SLawrence Stewart } 2769bce0f05SLawrence Stewart 2779bce0f05SLawrence Stewart void 2789bce0f05SLawrence Stewart ffclock_getnanotime(struct timespec *tsp) 2799bce0f05SLawrence Stewart { 2809bce0f05SLawrence Stewart struct bintime bt; 2819bce0f05SLawrence Stewart 2829bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 2839bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2849bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 2859bce0f05SLawrence Stewart } 2869bce0f05SLawrence Stewart 2879bce0f05SLawrence Stewart void 2889bce0f05SLawrence Stewart ffclock_getmicrotime(struct timeval *tvp) 2899bce0f05SLawrence Stewart { 2909bce0f05SLawrence Stewart struct bintime bt; 2919bce0f05SLawrence Stewart 2929bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 2939bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2949bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2959bce0f05SLawrence Stewart } 2969bce0f05SLawrence Stewart 2979bce0f05SLawrence Stewart void 2989bce0f05SLawrence Stewart ffclock_binuptime(struct bintime *bt) 2999bce0f05SLawrence Stewart { 3009bce0f05SLawrence Stewart 3019bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3029bce0f05SLawrence Stewart } 3039bce0f05SLawrence Stewart 3049bce0f05SLawrence Stewart void 3059bce0f05SLawrence Stewart ffclock_nanouptime(struct timespec *tsp) 3069bce0f05SLawrence Stewart { 3079bce0f05SLawrence Stewart struct bintime bt; 3089bce0f05SLawrence Stewart 3099bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3109bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3119bce0f05SLawrence Stewart } 3129bce0f05SLawrence Stewart 3139bce0f05SLawrence Stewart void 3149bce0f05SLawrence Stewart ffclock_microuptime(struct timeval *tvp) 3159bce0f05SLawrence Stewart { 3169bce0f05SLawrence Stewart struct bintime bt; 3179bce0f05SLawrence Stewart 3189bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3199bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3209bce0f05SLawrence Stewart } 3219bce0f05SLawrence Stewart 3229bce0f05SLawrence Stewart void 3239bce0f05SLawrence Stewart ffclock_getbinuptime(struct bintime *bt) 3249bce0f05SLawrence Stewart { 3259bce0f05SLawrence Stewart 3269bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 3279bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3289bce0f05SLawrence Stewart } 3299bce0f05SLawrence Stewart 3309bce0f05SLawrence Stewart void 3319bce0f05SLawrence Stewart ffclock_getnanouptime(struct timespec *tsp) 3329bce0f05SLawrence Stewart { 3339bce0f05SLawrence Stewart struct bintime bt; 3349bce0f05SLawrence Stewart 3359bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 3369bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3379bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3389bce0f05SLawrence Stewart } 3399bce0f05SLawrence Stewart 3409bce0f05SLawrence Stewart void 3419bce0f05SLawrence Stewart ffclock_getmicrouptime(struct timeval *tvp) 3429bce0f05SLawrence Stewart { 3439bce0f05SLawrence Stewart struct bintime bt; 3449bce0f05SLawrence Stewart 3459bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 3469bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3479bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3489bce0f05SLawrence Stewart } 3499bce0f05SLawrence Stewart 3509bce0f05SLawrence Stewart void 3519bce0f05SLawrence Stewart ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt) 3529bce0f05SLawrence Stewart { 3539bce0f05SLawrence Stewart 3549bce0f05SLawrence Stewart ffclock_difftime(ffdelta, bt, NULL); 3559bce0f05SLawrence Stewart } 3569bce0f05SLawrence Stewart 3579bce0f05SLawrence Stewart void 3589bce0f05SLawrence Stewart ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp) 3599bce0f05SLawrence Stewart { 3609bce0f05SLawrence Stewart struct bintime bt; 3619bce0f05SLawrence Stewart 3629bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3639bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3649bce0f05SLawrence Stewart } 3659bce0f05SLawrence Stewart 3669bce0f05SLawrence Stewart void 3679bce0f05SLawrence Stewart ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp) 3689bce0f05SLawrence Stewart { 3699bce0f05SLawrence Stewart struct bintime bt; 3709bce0f05SLawrence Stewart 3719bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3729bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3739bce0f05SLawrence Stewart } 374cf13a585SLawrence Stewart 375cf13a585SLawrence Stewart /* 376cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the current value of 377cf13a585SLawrence Stewart * the Feed-Forward Clock counter. 378cf13a585SLawrence Stewart */ 379cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 380cf13a585SLawrence Stewart struct ffclock_getcounter_args { 381cf13a585SLawrence Stewart ffcounter *ffcount; 382cf13a585SLawrence Stewart }; 383cf13a585SLawrence Stewart #endif 384cf13a585SLawrence Stewart /* ARGSUSED */ 385cf13a585SLawrence Stewart int 386cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 387cf13a585SLawrence Stewart { 388cf13a585SLawrence Stewart ffcounter ffcount; 389cf13a585SLawrence Stewart int error; 390cf13a585SLawrence Stewart 391cf13a585SLawrence Stewart ffcount = 0; 392cf13a585SLawrence Stewart ffclock_read_counter(&ffcount); 393cf13a585SLawrence Stewart if (ffcount == 0) 394cf13a585SLawrence Stewart return (EAGAIN); 395cf13a585SLawrence Stewart error = copyout(&ffcount, uap->ffcount, sizeof(ffcounter)); 396cf13a585SLawrence Stewart 397cf13a585SLawrence Stewart return (error); 398cf13a585SLawrence Stewart } 399cf13a585SLawrence Stewart 400cf13a585SLawrence Stewart /* 401cf13a585SLawrence Stewart * System call allowing the synchronisation daemon to push new feed-foward clock 402cf13a585SLawrence Stewart * estimates to the kernel. Acquire ffclock_mtx to prevent concurrent updates 403cf13a585SLawrence Stewart * and ensure data consistency. 404cf13a585SLawrence Stewart * NOTE: ffclock_updated signals the fftimehands that new estimates are 405cf13a585SLawrence Stewart * available. The updated estimates are picked up by the fftimehands on next 406cf13a585SLawrence Stewart * tick, which could take as long as 1/hz seconds (if ticks are not missed). 407cf13a585SLawrence Stewart */ 408cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 409cf13a585SLawrence Stewart struct ffclock_setestimate_args { 410cf13a585SLawrence Stewart struct ffclock_estimate *cest; 411cf13a585SLawrence Stewart }; 412cf13a585SLawrence Stewart #endif 413cf13a585SLawrence Stewart /* ARGSUSED */ 414cf13a585SLawrence Stewart int 415cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 416cf13a585SLawrence Stewart { 417cf13a585SLawrence Stewart struct ffclock_estimate cest; 418cf13a585SLawrence Stewart int error; 419cf13a585SLawrence Stewart 420cf13a585SLawrence Stewart /* Reuse of PRIV_CLOCK_SETTIME. */ 421cf13a585SLawrence Stewart if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) 422cf13a585SLawrence Stewart return (error); 423cf13a585SLawrence Stewart 424cf13a585SLawrence Stewart if ((error = copyin(uap->cest, &cest, sizeof(struct ffclock_estimate))) 425cf13a585SLawrence Stewart != 0) 426cf13a585SLawrence Stewart return (error); 427cf13a585SLawrence Stewart 428cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 429cf13a585SLawrence Stewart memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 430cf13a585SLawrence Stewart ffclock_updated++; 431cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 432cf13a585SLawrence Stewart return (error); 433cf13a585SLawrence Stewart } 434cf13a585SLawrence Stewart 435cf13a585SLawrence Stewart /* 436cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the clock estimates 437cf13a585SLawrence Stewart * stored within the kernel. It is useful to kickstart the synchronisation 438cf13a585SLawrence Stewart * daemon with the kernel's knowledge of hardware timecounter. 439cf13a585SLawrence Stewart */ 440cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 441cf13a585SLawrence Stewart struct ffclock_getestimate_args { 442cf13a585SLawrence Stewart struct ffclock_estimate *cest; 443cf13a585SLawrence Stewart }; 444cf13a585SLawrence Stewart #endif 445cf13a585SLawrence Stewart /* ARGSUSED */ 446cf13a585SLawrence Stewart int 447cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 448cf13a585SLawrence Stewart { 449cf13a585SLawrence Stewart struct ffclock_estimate cest; 450cf13a585SLawrence Stewart int error; 451cf13a585SLawrence Stewart 452cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 453cf13a585SLawrence Stewart memcpy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); 454cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 455cf13a585SLawrence Stewart error = copyout(&cest, uap->cest, sizeof(struct ffclock_estimate)); 456cf13a585SLawrence Stewart return (error); 457cf13a585SLawrence Stewart } 458cf13a585SLawrence Stewart 459cf13a585SLawrence Stewart #else /* !FFCLOCK */ 460cf13a585SLawrence Stewart 461cf13a585SLawrence Stewart int 462cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 463cf13a585SLawrence Stewart { 464cf13a585SLawrence Stewart 465cf13a585SLawrence Stewart return (ENOSYS); 466cf13a585SLawrence Stewart } 467cf13a585SLawrence Stewart 468cf13a585SLawrence Stewart int 469cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 470cf13a585SLawrence Stewart { 471cf13a585SLawrence Stewart 472cf13a585SLawrence Stewart return (ENOSYS); 473cf13a585SLawrence Stewart } 474cf13a585SLawrence Stewart 475cf13a585SLawrence Stewart int 476cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 477cf13a585SLawrence Stewart { 478cf13a585SLawrence Stewart 479cf13a585SLawrence Stewart return (ENOSYS); 480cf13a585SLawrence Stewart } 481cf13a585SLawrence Stewart 482cf13a585SLawrence Stewart #endif /* FFCLOCK */ 483