1f464c5ccSLawrence Stewart /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro 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/sysproto.h> 479bce0f05SLawrence Stewart #include <sys/sysctl.h> 48f464c5ccSLawrence Stewart #include <sys/systm.h> 49f464c5ccSLawrence Stewart #include <sys/timeffc.h> 50f464c5ccSLawrence Stewart 51cf13a585SLawrence Stewart #ifdef FFCLOCK 52cf13a585SLawrence Stewart 5366761af3SLawrence Stewart FEATURE(ffclock, "Feed-forward clock support"); 5466761af3SLawrence Stewart 55f464c5ccSLawrence Stewart extern struct ffclock_estimate ffclock_estimate; 56f464c5ccSLawrence Stewart extern struct bintime ffclock_boottime; 57cf13a585SLawrence Stewart extern int8_t ffclock_updated; 58cf13a585SLawrence Stewart extern struct mtx ffclock_mtx; 59f464c5ccSLawrence Stewart 60f464c5ccSLawrence Stewart /* 61f464c5ccSLawrence Stewart * Feed-forward clock absolute time. This should be the preferred way to read 62f464c5ccSLawrence Stewart * the feed-forward clock for "wall-clock" type time. The flags allow to compose 63f464c5ccSLawrence Stewart * various flavours of absolute time (e.g. with or without leap seconds taken 64f464c5ccSLawrence Stewart * into account). If valid pointers are provided, the ffcounter value and an 65f464c5ccSLawrence Stewart * upper bound on clock error associated with the bintime are provided. 66f464c5ccSLawrence Stewart * NOTE: use ffclock_convert_abs() to differ the conversion of a ffcounter value 67f464c5ccSLawrence Stewart * read earlier. 68f464c5ccSLawrence Stewart */ 69f464c5ccSLawrence Stewart void 70f464c5ccSLawrence Stewart ffclock_abstime(ffcounter *ffcount, struct bintime *bt, 71f464c5ccSLawrence Stewart struct bintime *error_bound, uint32_t flags) 72f464c5ccSLawrence Stewart { 73f464c5ccSLawrence Stewart struct ffclock_estimate cest; 74f464c5ccSLawrence Stewart ffcounter ffc; 75f464c5ccSLawrence Stewart ffcounter update_ffcount; 76f464c5ccSLawrence Stewart ffcounter ffdelta_error; 77f464c5ccSLawrence Stewart 78f464c5ccSLawrence Stewart /* Get counter and corresponding time. */ 79f464c5ccSLawrence Stewart if ((flags & FFCLOCK_FAST) == FFCLOCK_FAST) 80f464c5ccSLawrence Stewart ffclock_last_tick(&ffc, bt, flags); 81f464c5ccSLawrence Stewart else { 82f464c5ccSLawrence Stewart ffclock_read_counter(&ffc); 83f464c5ccSLawrence Stewart ffclock_convert_abs(ffc, bt, flags); 84f464c5ccSLawrence Stewart } 85f464c5ccSLawrence Stewart 86f464c5ccSLawrence Stewart /* Current ffclock estimate, use update_ffcount as generation number. */ 87f464c5ccSLawrence Stewart do { 88f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 89f464c5ccSLawrence Stewart bcopy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 90f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 91f464c5ccSLawrence Stewart 92f464c5ccSLawrence Stewart /* 93f464c5ccSLawrence Stewart * Leap second adjustment. Total as seen by synchronisation algorithm 94f464c5ccSLawrence Stewart * since it started. cest.leapsec_next is the ffcounter prediction of 95f464c5ccSLawrence Stewart * when the next leapsecond occurs. 96f464c5ccSLawrence Stewart */ 97f464c5ccSLawrence Stewart if ((flags & FFCLOCK_LEAPSEC) == FFCLOCK_LEAPSEC) { 98f464c5ccSLawrence Stewart bt->sec -= cest.leapsec_total; 99f464c5ccSLawrence Stewart if (ffc > cest.leapsec_next) 100f464c5ccSLawrence Stewart bt->sec -= cest.leapsec; 101f464c5ccSLawrence Stewart } 102f464c5ccSLawrence Stewart 103f464c5ccSLawrence Stewart /* Boot time adjustment, for uptime/monotonic clocks. */ 104f464c5ccSLawrence Stewart if ((flags & FFCLOCK_UPTIME) == FFCLOCK_UPTIME) { 105f464c5ccSLawrence Stewart bintime_sub(bt, &ffclock_boottime); 106f464c5ccSLawrence Stewart } 107f464c5ccSLawrence Stewart 108f464c5ccSLawrence Stewart /* Compute error bound if a valid pointer has been passed. */ 109f464c5ccSLawrence Stewart if (error_bound) { 110f464c5ccSLawrence Stewart ffdelta_error = ffc - cest.update_ffcount; 111f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta_error, error_bound); 112f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 113f464c5ccSLawrence Stewart bintime_mul(error_bound, cest.errb_rate * 114f464c5ccSLawrence Stewart (uint64_t)18446744073709LL); 115f464c5ccSLawrence Stewart /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns] */ 116f464c5ccSLawrence Stewart bintime_addx(error_bound, cest.errb_abs * 117f464c5ccSLawrence Stewart (uint64_t)18446744073LL); 118f464c5ccSLawrence Stewart } 119f464c5ccSLawrence Stewart 120f464c5ccSLawrence Stewart if (ffcount) 121f464c5ccSLawrence Stewart *ffcount = ffc; 122f464c5ccSLawrence Stewart } 123f464c5ccSLawrence Stewart 124f464c5ccSLawrence Stewart /* 125f464c5ccSLawrence Stewart * Feed-forward difference clock. This should be the preferred way to convert a 126f464c5ccSLawrence Stewart * time interval in ffcounter values into a time interval in seconds. If a valid 127f464c5ccSLawrence Stewart * pointer is passed, an upper bound on the error in computing the time interval 128f464c5ccSLawrence Stewart * in seconds is provided. 129f464c5ccSLawrence Stewart */ 130f464c5ccSLawrence Stewart void 131f464c5ccSLawrence Stewart ffclock_difftime(ffcounter ffdelta, struct bintime *bt, 132f464c5ccSLawrence Stewart struct bintime *error_bound) 133f464c5ccSLawrence Stewart { 134f464c5ccSLawrence Stewart ffcounter update_ffcount; 135f464c5ccSLawrence Stewart uint32_t err_rate; 136f464c5ccSLawrence Stewart 137f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, bt); 138f464c5ccSLawrence Stewart 139f464c5ccSLawrence Stewart if (error_bound) { 140f464c5ccSLawrence Stewart do { 141f464c5ccSLawrence Stewart update_ffcount = ffclock_estimate.update_ffcount; 142f464c5ccSLawrence Stewart err_rate = ffclock_estimate.errb_rate; 143f464c5ccSLawrence Stewart } while (update_ffcount != ffclock_estimate.update_ffcount); 144f464c5ccSLawrence Stewart 145f464c5ccSLawrence Stewart ffclock_convert_diff(ffdelta, error_bound); 146f464c5ccSLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s] */ 147f464c5ccSLawrence Stewart bintime_mul(error_bound, err_rate * (uint64_t)18446744073709LL); 148f464c5ccSLawrence Stewart } 149f464c5ccSLawrence Stewart } 1509bce0f05SLawrence Stewart 1519bce0f05SLawrence Stewart /* 15266dcfed3SLawrence Stewart * Create a new kern.sysclock sysctl node, which will be home to some generic 15366dcfed3SLawrence Stewart * sysclock configuration variables. Feed-forward clock specific variables will 15466dcfed3SLawrence Stewart * live under the ffclock subnode. 1559bce0f05SLawrence Stewart */ 1569bce0f05SLawrence Stewart 1577029da5cSPawel Biernacki SYSCTL_NODE(_kern, OID_AUTO, sysclock, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 15866dcfed3SLawrence Stewart "System clock related configuration"); 1597029da5cSPawel Biernacki SYSCTL_NODE(_kern_sysclock, OID_AUTO, ffclock, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 16066dcfed3SLawrence Stewart "Feed-forward clock configuration"); 1619bce0f05SLawrence Stewart 16266dcfed3SLawrence Stewart static char *sysclocks[] = {"feedback", "feed-forward"}; 16366dcfed3SLawrence Stewart #define MAX_SYSCLOCK_NAME_LEN 16 16402abd400SPedro F. Giffuni #define NUM_SYSCLOCKS nitems(sysclocks) 1659bce0f05SLawrence Stewart 16666dcfed3SLawrence Stewart static int ffclock_version = 2; 16766dcfed3SLawrence Stewart SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, version, CTLFLAG_RD, 16866dcfed3SLawrence Stewart &ffclock_version, 0, "Feed-forward clock kernel version"); 16966dcfed3SLawrence Stewart 17066dcfed3SLawrence Stewart /* List available sysclocks. */ 1719bce0f05SLawrence Stewart static int 17266dcfed3SLawrence Stewart sysctl_kern_sysclock_available(SYSCTL_HANDLER_ARGS) 1739bce0f05SLawrence Stewart { 1749bce0f05SLawrence Stewart struct sbuf *s; 1759bce0f05SLawrence Stewart int clk, error; 1769bce0f05SLawrence Stewart 17766dcfed3SLawrence Stewart s = sbuf_new_for_sysctl(NULL, NULL, 17866dcfed3SLawrence Stewart MAX_SYSCLOCK_NAME_LEN * NUM_SYSCLOCKS, req); 1799bce0f05SLawrence Stewart if (s == NULL) 1809bce0f05SLawrence Stewart return (ENOMEM); 1819bce0f05SLawrence Stewart 1829bce0f05SLawrence Stewart for (clk = 0; clk < NUM_SYSCLOCKS; clk++) { 1839bce0f05SLawrence Stewart sbuf_cat(s, sysclocks[clk]); 1849bce0f05SLawrence Stewart if (clk + 1 < NUM_SYSCLOCKS) 1859bce0f05SLawrence Stewart sbuf_cat(s, " "); 1869bce0f05SLawrence Stewart } 1879bce0f05SLawrence Stewart error = sbuf_finish(s); 1889bce0f05SLawrence Stewart sbuf_delete(s); 1899bce0f05SLawrence Stewart 1909bce0f05SLawrence Stewart return (error); 1919bce0f05SLawrence Stewart } 1929bce0f05SLawrence Stewart 1937029da5cSPawel Biernacki SYSCTL_PROC(_kern_sysclock, OID_AUTO, available, 1947029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 0, 0, 1957029da5cSPawel Biernacki 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 2347029da5cSPawel Biernacki SYSCTL_PROC(_kern_sysclock, OID_AUTO, active, 2357029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 0, 0, 2367029da5cSPawel Biernacki sysctl_kern_sysclock_active, "A", 23766dcfed3SLawrence Stewart "Name of the active system clock which is currently serving time"); 2389bce0f05SLawrence Stewart 23966dcfed3SLawrence Stewart static int sysctl_kern_ffclock_ffcounter_bypass = 0; 24066dcfed3SLawrence Stewart SYSCTL_INT(_kern_sysclock_ffclock, OID_AUTO, ffcounter_bypass, CTLFLAG_RW, 241cf13a585SLawrence Stewart &sysctl_kern_ffclock_ffcounter_bypass, 0, 24266dcfed3SLawrence Stewart "Use reliable hardware timecounter as the feed-forward counter"); 243cf13a585SLawrence Stewart 2449bce0f05SLawrence Stewart /* 2459bce0f05SLawrence Stewart * High level functions to access the Feed-Forward Clock. 2469bce0f05SLawrence Stewart */ 2479bce0f05SLawrence Stewart void 2489bce0f05SLawrence Stewart ffclock_bintime(struct bintime *bt) 2499bce0f05SLawrence Stewart { 2509bce0f05SLawrence Stewart 2519bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2529bce0f05SLawrence Stewart } 2539bce0f05SLawrence Stewart 2549bce0f05SLawrence Stewart void 2559bce0f05SLawrence Stewart ffclock_nanotime(struct timespec *tsp) 2569bce0f05SLawrence Stewart { 2579bce0f05SLawrence Stewart struct bintime bt; 2589bce0f05SLawrence Stewart 2599bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2609bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 2619bce0f05SLawrence Stewart } 2629bce0f05SLawrence Stewart 2639bce0f05SLawrence Stewart void 2649bce0f05SLawrence Stewart ffclock_microtime(struct timeval *tvp) 2659bce0f05SLawrence Stewart { 2669bce0f05SLawrence Stewart struct bintime bt; 2679bce0f05SLawrence Stewart 2689bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC); 2699bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2709bce0f05SLawrence Stewart } 2719bce0f05SLawrence Stewart 2729bce0f05SLawrence Stewart void 2739bce0f05SLawrence Stewart ffclock_getbintime(struct bintime *bt) 2749bce0f05SLawrence Stewart { 2759bce0f05SLawrence Stewart 2769bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 2779bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2789bce0f05SLawrence Stewart } 2799bce0f05SLawrence Stewart 2809bce0f05SLawrence Stewart void 2819bce0f05SLawrence Stewart ffclock_getnanotime(struct timespec *tsp) 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 bintime2timespec(&bt, tsp); 2889bce0f05SLawrence Stewart } 2899bce0f05SLawrence Stewart 2909bce0f05SLawrence Stewart void 2919bce0f05SLawrence Stewart ffclock_getmicrotime(struct timeval *tvp) 2929bce0f05SLawrence Stewart { 2939bce0f05SLawrence Stewart struct bintime bt; 2949bce0f05SLawrence Stewart 2959bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 2969bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST); 2979bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 2989bce0f05SLawrence Stewart } 2999bce0f05SLawrence Stewart 3009bce0f05SLawrence Stewart void 3019bce0f05SLawrence Stewart ffclock_binuptime(struct bintime *bt) 3029bce0f05SLawrence Stewart { 3039bce0f05SLawrence Stewart 3049bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3059bce0f05SLawrence Stewart } 3069bce0f05SLawrence Stewart 3079bce0f05SLawrence Stewart void 3089bce0f05SLawrence Stewart ffclock_nanouptime(struct timespec *tsp) 3099bce0f05SLawrence Stewart { 3109bce0f05SLawrence Stewart struct bintime bt; 3119bce0f05SLawrence Stewart 3129bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3139bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3149bce0f05SLawrence Stewart } 3159bce0f05SLawrence Stewart 3169bce0f05SLawrence Stewart void 3179bce0f05SLawrence Stewart ffclock_microuptime(struct timeval *tvp) 3189bce0f05SLawrence Stewart { 3199bce0f05SLawrence Stewart struct bintime bt; 3209bce0f05SLawrence Stewart 3219bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME); 3229bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3239bce0f05SLawrence Stewart } 3249bce0f05SLawrence Stewart 3259bce0f05SLawrence Stewart void 3269bce0f05SLawrence Stewart ffclock_getbinuptime(struct bintime *bt) 3279bce0f05SLawrence Stewart { 3289bce0f05SLawrence Stewart 3299bce0f05SLawrence Stewart ffclock_abstime(NULL, bt, NULL, 3309bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3319bce0f05SLawrence Stewart } 3329bce0f05SLawrence Stewart 3339bce0f05SLawrence Stewart void 3349bce0f05SLawrence Stewart ffclock_getnanouptime(struct timespec *tsp) 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 bintime2timespec(&bt, tsp); 3419bce0f05SLawrence Stewart } 3429bce0f05SLawrence Stewart 3439bce0f05SLawrence Stewart void 3449bce0f05SLawrence Stewart ffclock_getmicrouptime(struct timeval *tvp) 3459bce0f05SLawrence Stewart { 3469bce0f05SLawrence Stewart struct bintime bt; 3479bce0f05SLawrence Stewart 3489bce0f05SLawrence Stewart ffclock_abstime(NULL, &bt, NULL, 3499bce0f05SLawrence Stewart FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST); 3509bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3519bce0f05SLawrence Stewart } 3529bce0f05SLawrence Stewart 3539bce0f05SLawrence Stewart void 3549bce0f05SLawrence Stewart ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt) 3559bce0f05SLawrence Stewart { 3569bce0f05SLawrence Stewart 3579bce0f05SLawrence Stewart ffclock_difftime(ffdelta, bt, NULL); 3589bce0f05SLawrence Stewart } 3599bce0f05SLawrence Stewart 3609bce0f05SLawrence Stewart void 3619bce0f05SLawrence Stewart ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp) 3629bce0f05SLawrence Stewart { 3639bce0f05SLawrence Stewart struct bintime bt; 3649bce0f05SLawrence Stewart 3659bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3669bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3679bce0f05SLawrence Stewart } 3689bce0f05SLawrence Stewart 3699bce0f05SLawrence Stewart void 3709bce0f05SLawrence Stewart ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp) 3719bce0f05SLawrence Stewart { 3729bce0f05SLawrence Stewart struct bintime bt; 3739bce0f05SLawrence Stewart 3749bce0f05SLawrence Stewart ffclock_difftime(ffdelta, &bt, NULL); 3759bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3769bce0f05SLawrence Stewart } 377cf13a585SLawrence Stewart 378cf13a585SLawrence Stewart /* 379cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the current value of 380cf13a585SLawrence Stewart * the Feed-Forward Clock counter. 381cf13a585SLawrence Stewart */ 382cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 383cf13a585SLawrence Stewart struct ffclock_getcounter_args { 384cf13a585SLawrence Stewart ffcounter *ffcount; 385cf13a585SLawrence Stewart }; 386cf13a585SLawrence Stewart #endif 387cf13a585SLawrence Stewart /* ARGSUSED */ 388cf13a585SLawrence Stewart int 389cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 390cf13a585SLawrence Stewart { 391cf13a585SLawrence Stewart ffcounter ffcount; 392cf13a585SLawrence Stewart int error; 393cf13a585SLawrence Stewart 394cf13a585SLawrence Stewart ffcount = 0; 395cf13a585SLawrence Stewart ffclock_read_counter(&ffcount); 396cf13a585SLawrence Stewart if (ffcount == 0) 397cf13a585SLawrence Stewart return (EAGAIN); 398cf13a585SLawrence Stewart error = copyout(&ffcount, uap->ffcount, sizeof(ffcounter)); 399cf13a585SLawrence Stewart 400cf13a585SLawrence Stewart return (error); 401cf13a585SLawrence Stewart } 402cf13a585SLawrence Stewart 403cf13a585SLawrence Stewart /* 4045a78ec9eSGordon Bergling * System call allowing the synchronisation daemon to push new feed-forward clock 405cf13a585SLawrence Stewart * estimates to the kernel. Acquire ffclock_mtx to prevent concurrent updates 406cf13a585SLawrence Stewart * and ensure data consistency. 407cf13a585SLawrence Stewart * NOTE: ffclock_updated signals the fftimehands that new estimates are 408cf13a585SLawrence Stewart * available. The updated estimates are picked up by the fftimehands on next 409cf13a585SLawrence Stewart * tick, which could take as long as 1/hz seconds (if ticks are not missed). 410cf13a585SLawrence Stewart */ 411cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 412cf13a585SLawrence Stewart struct ffclock_setestimate_args { 413cf13a585SLawrence Stewart struct ffclock_estimate *cest; 414cf13a585SLawrence Stewart }; 415cf13a585SLawrence Stewart #endif 416cf13a585SLawrence Stewart /* ARGSUSED */ 417cf13a585SLawrence Stewart int 418cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 419cf13a585SLawrence Stewart { 420cf13a585SLawrence Stewart struct ffclock_estimate cest; 421cf13a585SLawrence Stewart int error; 422cf13a585SLawrence Stewart 423cf13a585SLawrence Stewart /* Reuse of PRIV_CLOCK_SETTIME. */ 424cf13a585SLawrence Stewart if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) 425cf13a585SLawrence Stewart return (error); 426cf13a585SLawrence Stewart 427cf13a585SLawrence Stewart if ((error = copyin(uap->cest, &cest, sizeof(struct ffclock_estimate))) 428cf13a585SLawrence Stewart != 0) 429cf13a585SLawrence Stewart return (error); 430cf13a585SLawrence Stewart 431cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 432cf13a585SLawrence Stewart memcpy(&ffclock_estimate, &cest, sizeof(struct ffclock_estimate)); 433cf13a585SLawrence Stewart ffclock_updated++; 434cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 435cf13a585SLawrence Stewart return (error); 436cf13a585SLawrence Stewart } 437cf13a585SLawrence Stewart 438cf13a585SLawrence Stewart /* 439cf13a585SLawrence Stewart * System call allowing userland applications to retrieve the clock estimates 440cf13a585SLawrence Stewart * stored within the kernel. It is useful to kickstart the synchronisation 441cf13a585SLawrence Stewart * daemon with the kernel's knowledge of hardware timecounter. 442cf13a585SLawrence Stewart */ 443cf13a585SLawrence Stewart #ifndef _SYS_SYSPROTO_H_ 444cf13a585SLawrence Stewart struct ffclock_getestimate_args { 445cf13a585SLawrence Stewart struct ffclock_estimate *cest; 446cf13a585SLawrence Stewart }; 447cf13a585SLawrence Stewart #endif 448cf13a585SLawrence Stewart /* ARGSUSED */ 449cf13a585SLawrence Stewart int 450cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 451cf13a585SLawrence Stewart { 452cf13a585SLawrence Stewart struct ffclock_estimate cest; 453cf13a585SLawrence Stewart int error; 454cf13a585SLawrence Stewart 455cf13a585SLawrence Stewart mtx_lock(&ffclock_mtx); 456cf13a585SLawrence Stewart memcpy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); 457cf13a585SLawrence Stewart mtx_unlock(&ffclock_mtx); 458cf13a585SLawrence Stewart error = copyout(&cest, uap->cest, sizeof(struct ffclock_estimate)); 459cf13a585SLawrence Stewart return (error); 460cf13a585SLawrence Stewart } 461cf13a585SLawrence Stewart 462cf13a585SLawrence Stewart #else /* !FFCLOCK */ 463cf13a585SLawrence Stewart 464cf13a585SLawrence Stewart int 465cf13a585SLawrence Stewart sys_ffclock_getcounter(struct thread *td, struct ffclock_getcounter_args *uap) 466cf13a585SLawrence Stewart { 467cf13a585SLawrence Stewart 468cf13a585SLawrence Stewart return (ENOSYS); 469cf13a585SLawrence Stewart } 470cf13a585SLawrence Stewart 471cf13a585SLawrence Stewart int 472cf13a585SLawrence Stewart sys_ffclock_setestimate(struct thread *td, struct ffclock_setestimate_args *uap) 473cf13a585SLawrence Stewart { 474cf13a585SLawrence Stewart 475cf13a585SLawrence Stewart return (ENOSYS); 476cf13a585SLawrence Stewart } 477cf13a585SLawrence Stewart 478cf13a585SLawrence Stewart int 479cf13a585SLawrence Stewart sys_ffclock_getestimate(struct thread *td, struct ffclock_getestimate_args *uap) 480cf13a585SLawrence Stewart { 481cf13a585SLawrence Stewart 482cf13a585SLawrence Stewart return (ENOSYS); 483cf13a585SLawrence Stewart } 484cf13a585SLawrence Stewart 485cf13a585SLawrence Stewart #endif /* FFCLOCK */ 486