1f464c5ccSLawrence Stewart /*- 2*8a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*8a36da99SPedro F. Giffuni * 4f464c5ccSLawrence Stewart * Copyright (c) 2011 The University of Melbourne 5f464c5ccSLawrence Stewart * All rights reserved. 6f464c5ccSLawrence Stewart * 7f464c5ccSLawrence Stewart * This software was developed by Julien Ridoux at the University of Melbourne 8f464c5ccSLawrence Stewart * under sponsorship from the FreeBSD Foundation. 9f464c5ccSLawrence Stewart * 10f464c5ccSLawrence Stewart * Redistribution and use in source and binary forms, with or without 11f464c5ccSLawrence Stewart * modification, are permitted provided that the following conditions 12f464c5ccSLawrence Stewart * are met: 13f464c5ccSLawrence Stewart * 1. Redistributions of source code must retain the above copyright 14f464c5ccSLawrence Stewart * notice, this list of conditions and the following disclaimer. 15f464c5ccSLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright 16f464c5ccSLawrence Stewart * notice, this list of conditions and the following disclaimer in the 17f464c5ccSLawrence Stewart * documentation and/or other materials provided with the distribution. 18f464c5ccSLawrence Stewart * 19f464c5ccSLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20f464c5ccSLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21f464c5ccSLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22f464c5ccSLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23f464c5ccSLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24f464c5ccSLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25f464c5ccSLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26f464c5ccSLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27f464c5ccSLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28f464c5ccSLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29f464c5ccSLawrence Stewart * SUCH DAMAGE. 30f464c5ccSLawrence Stewart */ 31f464c5ccSLawrence Stewart 32f464c5ccSLawrence Stewart #include <sys/cdefs.h> 33f464c5ccSLawrence Stewart __FBSDID("$FreeBSD$"); 34f464c5ccSLawrence Stewart 35cf13a585SLawrence Stewart #include "opt_ffclock.h" 36cf13a585SLawrence Stewart 37f464c5ccSLawrence Stewart #include <sys/param.h> 38cf13a585SLawrence Stewart #include <sys/bus.h> 39cf13a585SLawrence Stewart #include <sys/kernel.h> 40cf13a585SLawrence Stewart #include <sys/lock.h> 41cf13a585SLawrence Stewart #include <sys/module.h> 42cf13a585SLawrence Stewart #include <sys/mutex.h> 43cf13a585SLawrence Stewart #include <sys/priv.h> 44cf13a585SLawrence Stewart #include <sys/proc.h> 459bce0f05SLawrence Stewart #include <sys/sbuf.h> 46cf13a585SLawrence Stewart #include <sys/sysent.h> 47cf13a585SLawrence Stewart #include <sys/sysproto.h> 489bce0f05SLawrence Stewart #include <sys/sysctl.h> 49f464c5ccSLawrence Stewart #include <sys/systm.h> 50f464c5ccSLawrence Stewart #include <sys/timeffc.h> 51f464c5ccSLawrence Stewart 52cf13a585SLawrence Stewart #ifdef FFCLOCK 53cf13a585SLawrence Stewart 5466761af3SLawrence Stewart FEATURE(ffclock, "Feed-forward clock support"); 5566761af3SLawrence Stewart 56f464c5ccSLawrence Stewart extern struct ffclock_estimate ffclock_estimate; 57f464c5ccSLawrence Stewart extern struct bintime ffclock_boottime; 58cf13a585SLawrence Stewart extern int8_t ffclock_updated; 59cf13a585SLawrence Stewart extern struct mtx ffclock_mtx; 60f464c5ccSLawrence Stewart 61f464c5ccSLawrence Stewart /* 62f464c5ccSLawrence Stewart * Feed-forward clock absolute time. This should be the preferred way to read 63f464c5ccSLawrence Stewart * the feed-forward clock for "wall-clock" type time. The flags allow to compose 64f464c5ccSLawrence Stewart * various flavours of absolute time (e.g. with or without leap seconds taken 65f464c5ccSLawrence Stewart * into account). If valid pointers are provided, the ffcounter value and an 66f464c5ccSLawrence Stewart * upper bound on clock error associated with the bintime are provided. 67f464c5ccSLawrence Stewart * NOTE: use ffclock_convert_abs() to differ the conversion of a ffcounter value 68f464c5ccSLawrence Stewart * read earlier. 69f464c5ccSLawrence Stewart */ 70f464c5ccSLawrence Stewart void 71f464c5ccSLawrence Stewart ffclock_abstime(ffcounter *ffcount, struct bintime *bt, 72f464c5ccSLawrence Stewart struct bintime *error_bound, uint32_t flags) 73f464c5ccSLawrence Stewart { 74f464c5ccSLawrence Stewart struct ffclock_estimate cest; 75f464c5ccSLawrence Stewart ffcounter ffc; 76f464c5ccSLawrence Stewart ffcounter update_ffcount; 77f464c5ccSLawrence Stewart ffcounter ffdelta_error; 78f464c5ccSLawrence Stewart 79f464c5ccSLawrence Stewart /* Get counter and corresponding time. */ 80f464c5ccSLawrence Stewart if ((flags & FFCLOCK_FAST) == FFCLOCK_FAST) 81f464c5ccSLawrence Stewart ffclock_last_tick(&ffc, bt, flags); 82f464c5ccSLawrence Stewart else { 83f464c5ccSLawrence Stewart ffclock_read_counter(&ffc); 84f464c5ccSLawrence Stewart ffclock_convert_abs(ffc, bt, flags); 85f464c5ccSLawrence Stewart } 86f464c5ccSLawrence Stewart 87f464c5ccSLawrence Stewart /* Current ffclock estimate, use update_ffcount as generation number. */ 88f464c5ccSLawrence Stewart do { 89f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 90f464c5ccSLawrence Stewart bcopy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 91f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 92f464c5ccSLawrence Stewart 93f464c5ccSLawrence Stewart /* 94f464c5ccSLawrence Stewart * Leap second adjustment. Total as seen by synchronisation algorithm 95f464c5ccSLawrence Stewart * since it started. cest.leapsec_next is the ffcounter prediction of 96f464c5ccSLawrence Stewart * when the next leapsecond occurs. 97f464c5ccSLawrence Stewart */ 98f464c5ccSLawrence Stewart if ((flags & FFCLOCK_LEAPSEC) == FFCLOCK_LEAPSEC) { 99f464c5ccSLawrence Stewart bt->sec -= cest.leapsec_total; 100f464c5ccSLawrence Stewart if (ffc > cest.leapsec_next) 101f464c5ccSLawrence Stewart bt->sec -= cest.leapsec; 102f464c5ccSLawrence Stewart } 103f464c5ccSLawrence Stewart 104f464c5ccSLawrence Stewart /* Boot time adjustment, for uptime/monotonic clocks. */ 105f464c5ccSLawrence Stewart if ((flags & FFCLOCK_UPTIME) == FFCLOCK_UPTIME) { 106f464c5ccSLawrence Stewart bintime_sub(bt, &ffclock_boottime); 107f464c5ccSLawrence Stewart } 108f464c5ccSLawrence Stewart 109f464c5ccSLawrence Stewart /* Compute error bound if a valid pointer has been passed. */ 110f464c5ccSLawrence Stewart if (error_bound) { 111f464c5ccSLawrence Stewart ffdelta_error = ffc - cest.update_ffcount; 112f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta_error, error_bound); 113f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 114f464c5ccSLawrence Stewart bintime_mul(error_bound, cest.errb_rate * 115f464c5ccSLawrence Stewart (uint64_t)18446744073709LL); 116f464c5ccSLawrence Stewart /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns] */ 117f464c5ccSLawrence Stewart bintime_addx(error_bound, cest.errb_abs * 118f464c5ccSLawrence Stewart (uint64_t)18446744073LL); 119f464c5ccSLawrence Stewart } 120f464c5ccSLawrence Stewart 121f464c5ccSLawrence Stewart if (ffcount) 122f464c5ccSLawrence Stewart *ffcount = ffc; 123f464c5ccSLawrence Stewart } 124f464c5ccSLawrence Stewart 125f464c5ccSLawrence Stewart /* 126f464c5ccSLawrence Stewart * Feed-forward difference clock. This should be the preferred way to convert a 127f464c5ccSLawrence Stewart * time interval in ffcounter values into a time interval in seconds. If a valid 128f464c5ccSLawrence Stewart * pointer is passed, an upper bound on the error in computing the time interval 129f464c5ccSLawrence Stewart * in seconds is provided. 130f464c5ccSLawrence Stewart */ 131f464c5ccSLawrence Stewart void 132f464c5ccSLawrence Stewart ffclock_difftime(ffcounter ffdelta, struct bintime *bt, 133f464c5ccSLawrence Stewart struct bintime *error_bound) 134f464c5ccSLawrence Stewart { 135f464c5ccSLawrence Stewart ffcounter update_ffcount; 136f464c5ccSLawrence Stewart uint32_t err_rate; 137f464c5ccSLawrence Stewart 138f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, bt); 139f464c5ccSLawrence Stewart 140f464c5ccSLawrence Stewart if (error_bound) { 141f464c5ccSLawrence Stewart do { 142f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 143f464c5ccSLawrence Stewart err_rate = ffclock_estimate.errb_rate; 144f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 145f464c5ccSLawrence Stewart 146f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, error_bound); 147f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 148f464c5ccSLawrence Stewart bintime_mul(error_bound, err_rate * (uint64_t)18446744073709LL); 149f464c5ccSLawrence Stewart } 150f464c5ccSLawrence Stewart } 1519bce0f05SLawrence Stewart 1529bce0f05SLawrence Stewart /* 15366dcfed3SLawrence Stewart * Create a new kern.sysclock sysctl node, which will be home to some generic 15466dcfed3SLawrence Stewart * sysclock configuration variables. Feed-forward clock specific variables will 15566dcfed3SLawrence Stewart * live under the ffclock subnode. 1569bce0f05SLawrence Stewart */ 1579bce0f05SLawrence Stewart 15866dcfed3SLawrence Stewart SYSCTL_NODE(_kern, OID_AUTO, sysclock, CTLFLAG_RW, 0, 15966dcfed3SLawrence Stewart "System clock related configuration"); 16066dcfed3SLawrence Stewart SYSCTL_NODE(_kern_sysclock, OID_AUTO, ffclock, CTLFLAG_RW, 0, 16166dcfed3SLawrence Stewart "Feed-forward clock configuration"); 1629bce0f05SLawrence Stewart 16366dcfed3SLawrence Stewart static char *sysclocks[] = {"feedback", "feed-forward"}; 16466dcfed3SLawrence Stewart #define MAX_SYSCLOCK_NAME_LEN 16 16502abd400SPedro F. Giffuni #define NUM_SYSCLOCKS nitems(sysclocks) 1669bce0f05SLawrence Stewart 16766dcfed3SLawrence Stewart static int ffclock_version = 2; 16866dcfed3SLawrence Stewart SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, version, CTLFLAG_RD, 16966dcfed3SLawrence Stewart &ffclock_version, 0, "Feed-forward clock kernel version"); 17066dcfed3SLawrence Stewart 17166dcfed3SLawrence Stewart /* List available sysclocks. */ 1729bce0f05SLawrence Stewart static int 17366dcfed3SLawrence Stewart sysctl_kern_sysclock_available(SYSCTL_HANDLER_ARGS) 1749bce0f05SLawrence Stewart { 1759bce0f05SLawrence Stewart struct sbuf *s; 1769bce0f05SLawrence Stewart int clk, error; 1779bce0f05SLawrence Stewart 17866dcfed3SLawrence Stewart s = sbuf_new_for_sysctl(NULL, NULL, 17966dcfed3SLawrence Stewart MAX_SYSCLOCK_NAME_LEN * NUM_SYSCLOCKS, req); 1809bce0f05SLawrence Stewart if (s == NULL) 1819bce0f05SLawrence Stewart return (ENOMEM); 1829bce0f05SLawrence Stewart 1839bce0f05SLawrence Stewart for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 1849bce0f05SLawrence Stewart sbuf_cat(s, sysclocks[clk]); 1859bce0f05SLawrence Stewart if (clk + 1 < NUM_SYSCLOCKS) 1869bce0f05SLawrence Stewart sbuf_cat(s, " "); 1879bce0f05SLawrence Stewart } 1889bce0f05SLawrence Stewart error = sbuf_finish(s); 1899bce0f05SLawrence Stewart sbuf_delete(s); 1909bce0f05SLawrence Stewart 1919bce0f05SLawrence Stewart return (error); 1929bce0f05SLawrence Stewart } 1939bce0f05SLawrence Stewart 19466dcfed3SLawrence Stewart SYSCTL_PROC(_kern_sysclock, OID_AUTO, available, CTLTYPE_STRING | CTLFLAG_RD, 19566dcfed3SLawrence Stewart 0, 0, sysctl_kern_sysclock_available, "A", 19666dcfed3SLawrence Stewart "List of available system clocks"); 1979bce0f05SLawrence Stewart 19866dcfed3SLawrence Stewart /* 19966dcfed3SLawrence Stewart * Return the name of the active system clock if read, or attempt to change 20066dcfed3SLawrence Stewart * the active system clock to the user specified one if written to. The active 20166dcfed3SLawrence Stewart * system clock is read when calling any of the [get]{bin,nano,micro}[up]time() 20266dcfed3SLawrence Stewart * functions. 20366dcfed3SLawrence Stewart */ 2049bce0f05SLawrence Stewart static int 20566dcfed3SLawrence Stewart sysctl_kern_sysclock_active(SYSCTL_HANDLER_ARGS) 2069bce0f05SLawrence Stewart { 20766dcfed3SLawrence Stewart char newclock[MAX_SYSCLOCK_NAME_LEN]; 2080e1152fcSHans Petter Selasky int error; 2090e1152fcSHans Petter Selasky int clk; 2109bce0f05SLawrence Stewart 21166dcfed3SLawrence Stewart /* Return the name of the current active sysclock. */ 21266dcfed3SLawrence Stewart strlcpy(newclock, sysclocks[sysclock_active], sizeof(newclock)); 2130e1152fcSHans Petter Selasky error = sysctl_handle_string(oidp, newclock, sizeof(newclock), req); 2140e1152fcSHans Petter Selasky 2150e1152fcSHans Petter Selasky /* Check for error or no change */ 2160e1152fcSHans Petter Selasky if (error != 0 || req->newptr == NULL) 2170e1152fcSHans Petter Selasky goto done; 2180e1152fcSHans Petter Selasky 2190e1152fcSHans Petter Selasky /* Change the active sysclock to the user specified one: */ 22066dcfed3SLawrence Stewart error = EINVAL; 22166dcfed3SLawrence Stewart for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 2220e1152fcSHans Petter Selasky if (strncmp(newclock, sysclocks[clk], 2230e1152fcSHans Petter Selasky MAX_SYSCLOCK_NAME_LEN - 1)) { 2240e1152fcSHans Petter Selasky continue; 2250e1152fcSHans Petter Selasky } 22666dcfed3SLawrence Stewart sysclock_active = clk; 22766dcfed3SLawrence Stewart error = 0; 2289bce0f05SLawrence Stewart break; 2299bce0f05SLawrence Stewart } 2300e1152fcSHans Petter Selasky done: 2319bce0f05SLawrence Stewart return (error); 2329bce0f05SLawrence Stewart } 2339bce0f05SLawrence Stewart 23466dcfed3SLawrence Stewart SYSCTL_PROC(_kern_sysclock, OID_AUTO, active, CTLTYPE_STRING | CTLFLAG_RW, 23566dcfed3SLawrence Stewart 0, 0, sysctl_kern_sysclock_active, "A", 23666dcfed3SLawrence Stewart "Name of the active system clock which is currently serving time"); 2379bce0f05SLawrence Stewart 23866dcfed3SLawrence Stewart static int sysctl_kern_ffclock_ffcounter_bypass = 0; 23966dcfed3SLawrence Stewart SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, ffcounter_bypass, CTLFLAG_RW, 240cf13a585SLawrence Stewart &sysctl_kern_ffclock_ffcounter_bypass, 0, 24166dcfed3SLawrence Stewart "Use reliable hardware timecounter as the feed-forward counter"); 242cf13a585SLawrence Stewart 2439bce0f05SLawrence Stewart /* 2449bce0f05SLawrence Stewart * High level functions to access the Feed-Forward Clock. 2459bce0f05SLawrence Stewart */ 2469bce0f05SLawrence Stewart void 2479bce0f05SLawrence Stewart ffclock_bintime(struct bintime *bt) 2489bce0f05SLawrence Stewart { 2499bce0f05SLawrence Stewart 2509bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2519bce0f05SLawrence Stewart } 2529bce0f05SLawrence Stewart 2539bce0f05SLawrence Stewart void 2549bce0f05SLawrence Stewart ffclock_nanotime(struct timespec *tsp) 2559bce0f05SLawrence Stewart { 2569bce0f05SLawrence Stewart struct bintime bt; 2579bce0f05SLawrence Stewart 2589bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2599bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 2609bce0f05SLawrence Stewart } 2619bce0f05SLawrence Stewart 2629bce0f05SLawrence Stewart void 2639bce0f05SLawrence Stewart ffclock_microtime(struct timeval *tvp) 2649bce0f05SLawrence Stewart { 2659bce0f05SLawrence Stewart struct bintime bt; 2669bce0f05SLawrence Stewart 2679bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2689bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2699bce0f05SLawrence Stewart } 2709bce0f05SLawrence Stewart 2719bce0f05SLawrence Stewart void 2729bce0f05SLawrence Stewart ffclock_getbintime(struct bintime *bt) 2739bce0f05SLawrence Stewart { 2749bce0f05SLawrence Stewart 2759bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 2769bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2779bce0f05SLawrence Stewart } 2789bce0f05SLawrence Stewart 2799bce0f05SLawrence Stewart void 2809bce0f05SLawrence Stewart ffclock_getnanotime(struct timespec *tsp) 2819bce0f05SLawrence Stewart { 2829bce0f05SLawrence Stewart struct bintime bt; 2839bce0f05SLawrence Stewart 2849bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 2859bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2869bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 2879bce0f05SLawrence Stewart } 2889bce0f05SLawrence Stewart 2899bce0f05SLawrence Stewart void 2909bce0f05SLawrence Stewart ffclock_getmicrotime(struct timeval *tvp) 2919bce0f05SLawrence Stewart { 2929bce0f05SLawrence Stewart struct bintime bt; 2939bce0f05SLawrence Stewart 2949bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 2959bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2969bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2979bce0f05SLawrence Stewart } 2989bce0f05SLawrence Stewart 2999bce0f05SLawrence Stewart void 3009bce0f05SLawrence Stewart ffclock_binuptime(struct bintime *bt) 3019bce0f05SLawrence Stewart { 3029bce0f05SLawrence Stewart 3039bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3049bce0f05SLawrence Stewart } 3059bce0f05SLawrence Stewart 3069bce0f05SLawrence Stewart void 3079bce0f05SLawrence Stewart ffclock_nanouptime(struct timespec *tsp) 3089bce0f05SLawrence Stewart { 3099bce0f05SLawrence Stewart struct bintime bt; 3109bce0f05SLawrence Stewart 3119bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3129bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3139bce0f05SLawrence Stewart } 3149bce0f05SLawrence Stewart 3159bce0f05SLawrence Stewart void 3169bce0f05SLawrence Stewart ffclock_microuptime(struct timeval *tvp) 3179bce0f05SLawrence Stewart { 3189bce0f05SLawrence Stewart struct bintime bt; 3199bce0f05SLawrence Stewart 3209bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3219bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3229bce0f05SLawrence Stewart } 3239bce0f05SLawrence Stewart 3249bce0f05SLawrence Stewart void 3259bce0f05SLawrence Stewart ffclock_getbinuptime(struct bintime *bt) 3269bce0f05SLawrence Stewart { 3279bce0f05SLawrence Stewart 3289bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 3299bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3309bce0f05SLawrence Stewart } 3319bce0f05SLawrence Stewart 3329bce0f05SLawrence Stewart void 3339bce0f05SLawrence Stewart ffclock_getnanouptime(struct timespec *tsp) 3349bce0f05SLawrence Stewart { 3359bce0f05SLawrence Stewart struct bintime bt; 3369bce0f05SLawrence Stewart 3379bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 3389bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3399bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3409bce0f05SLawrence Stewart } 3419bce0f05SLawrence Stewart 3429bce0f05SLawrence Stewart void 3439bce0f05SLawrence Stewart ffclock_getmicrouptime(struct timeval *tvp) 3449bce0f05SLawrence Stewart { 3459bce0f05SLawrence Stewart struct bintime bt; 3469bce0f05SLawrence Stewart 3479bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 3489bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3499bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3509bce0f05SLawrence Stewart } 3519bce0f05SLawrence Stewart 3529bce0f05SLawrence Stewart void 3539bce0f05SLawrence Stewart ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt) 3549bce0f05SLawrence Stewart { 3559bce0f05SLawrence Stewart 3569bce0f05SLawrence Stewart ffclock_difftime(ffdelta, bt, NULL); 3579bce0f05SLawrence Stewart } 3589bce0f05SLawrence Stewart 3599bce0f05SLawrence Stewart void 3609bce0f05SLawrence Stewart ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp) 3619bce0f05SLawrence Stewart { 3629bce0f05SLawrence Stewart struct bintime bt; 3639bce0f05SLawrence Stewart 3649bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3659bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3669bce0f05SLawrence Stewart } 3679bce0f05SLawrence Stewart 3689bce0f05SLawrence Stewart void 3699bce0f05SLawrence Stewart ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp) 3709bce0f05SLawrence Stewart { 3719bce0f05SLawrence Stewart struct bintime bt; 3729bce0f05SLawrence Stewart 3739bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3749bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3759bce0f05SLawrence Stewart } 376cf13a585SLawrence Stewart 377cf13a585SLawrence Stewart /* 378cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the current value of 379cf13a585SLawrence Stewart * the Feed-Forward Clock counter. 380cf13a585SLawrence Stewart */ 381cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 382cf13a585SLawrence Stewart struct ffclock_getcounter_args { 383cf13a585SLawrence Stewart ffcounter *ffcount; 384cf13a585SLawrence Stewart }; 385cf13a585SLawrence Stewart #endif 386cf13a585SLawrence Stewart /* ARGSUSED */ 387cf13a585SLawrence Stewart int 388cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 389cf13a585SLawrence Stewart { 390cf13a585SLawrence Stewart ffcounter ffcount; 391cf13a585SLawrence Stewart int error; 392cf13a585SLawrence Stewart 393cf13a585SLawrence Stewart ffcount = 0; 394cf13a585SLawrence Stewart ffclock_read_counter(&ffcount); 395cf13a585SLawrence Stewart if (ffcount == 0) 396cf13a585SLawrence Stewart return (EAGAIN); 397cf13a585SLawrence Stewart error = copyout(&ffcount, uap->ffcount, sizeof(ffcounter)); 398cf13a585SLawrence Stewart 399cf13a585SLawrence Stewart return (error); 400cf13a585SLawrence Stewart } 401cf13a585SLawrence Stewart 402cf13a585SLawrence Stewart /* 403cf13a585SLawrence Stewart * System call allowing the synchronisation daemon to push new feed-foward clock 404cf13a585SLawrence Stewart * estimates to the kernel. Acquire ffclock_mtx to prevent concurrent updates 405cf13a585SLawrence Stewart * and ensure data consistency. 406cf13a585SLawrence Stewart * NOTE: ffclock_updated signals the fftimehands that new estimates are 407cf13a585SLawrence Stewart * available. The updated estimates are picked up by the fftimehands on next 408cf13a585SLawrence Stewart * tick, which could take as long as 1/hz seconds (if ticks are not missed). 409cf13a585SLawrence Stewart */ 410cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 411cf13a585SLawrence Stewart struct ffclock_setestimate_args { 412cf13a585SLawrence Stewart struct ffclock_estimate *cest; 413cf13a585SLawrence Stewart }; 414cf13a585SLawrence Stewart #endif 415cf13a585SLawrence Stewart /* ARGSUSED */ 416cf13a585SLawrence Stewart int 417cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 418cf13a585SLawrence Stewart { 419cf13a585SLawrence Stewart struct ffclock_estimate cest; 420cf13a585SLawrence Stewart int error; 421cf13a585SLawrence Stewart 422cf13a585SLawrence Stewart /* Reuse of PRIV_CLOCK_SETTIME. */ 423cf13a585SLawrence Stewart if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) 424cf13a585SLawrence Stewart return (error); 425cf13a585SLawrence Stewart 426cf13a585SLawrence Stewart if ((error = copyin(uap->cest, &cest, sizeof(struct ffclock_estimate))) 427cf13a585SLawrence Stewart != 0) 428cf13a585SLawrence Stewart return (error); 429cf13a585SLawrence Stewart 430cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 431cf13a585SLawrence Stewart memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 432cf13a585SLawrence Stewart ffclock_updated++; 433cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 434cf13a585SLawrence Stewart return (error); 435cf13a585SLawrence Stewart } 436cf13a585SLawrence Stewart 437cf13a585SLawrence Stewart /* 438cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the clock estimates 439cf13a585SLawrence Stewart * stored within the kernel. It is useful to kickstart the synchronisation 440cf13a585SLawrence Stewart * daemon with the kernel's knowledge of hardware timecounter. 441cf13a585SLawrence Stewart */ 442cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 443cf13a585SLawrence Stewart struct ffclock_getestimate_args { 444cf13a585SLawrence Stewart struct ffclock_estimate *cest; 445cf13a585SLawrence Stewart }; 446cf13a585SLawrence Stewart #endif 447cf13a585SLawrence Stewart /* ARGSUSED */ 448cf13a585SLawrence Stewart int 449cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 450cf13a585SLawrence Stewart { 451cf13a585SLawrence Stewart struct ffclock_estimate cest; 452cf13a585SLawrence Stewart int error; 453cf13a585SLawrence Stewart 454cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 455cf13a585SLawrence Stewart memcpy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); 456cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 457cf13a585SLawrence Stewart error = copyout(&cest, uap->cest, sizeof(struct ffclock_estimate)); 458cf13a585SLawrence Stewart return (error); 459cf13a585SLawrence Stewart } 460cf13a585SLawrence Stewart 461cf13a585SLawrence Stewart #else /* !FFCLOCK */ 462cf13a585SLawrence Stewart 463cf13a585SLawrence Stewart int 464cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 465cf13a585SLawrence Stewart { 466cf13a585SLawrence Stewart 467cf13a585SLawrence Stewart return (ENOSYS); 468cf13a585SLawrence Stewart } 469cf13a585SLawrence Stewart 470cf13a585SLawrence Stewart int 471cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 472cf13a585SLawrence Stewart { 473cf13a585SLawrence Stewart 474cf13a585SLawrence Stewart return (ENOSYS); 475cf13a585SLawrence Stewart } 476cf13a585SLawrence Stewart 477cf13a585SLawrence Stewart int 478cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 479cf13a585SLawrence Stewart { 480cf13a585SLawrence Stewart 481cf13a585SLawrence Stewart return (ENOSYS); 482cf13a585SLawrence Stewart } 483cf13a585SLawrence Stewart 484cf13a585SLawrence Stewart #endif /* FFCLOCK */ 485