139acc78aSPoul-Henning Kamp /*- 264de3fddSPedro F. Giffuni * SPDX-License-Identifier: Beerware 364de3fddSPedro F. Giffuni * 491266b96SPoul-Henning Kamp * ---------------------------------------------------------------------------- 591266b96SPoul-Henning Kamp * "THE BEER-WARE LICENSE" (Revision 42): 691266b96SPoul-Henning Kamp * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 791266b96SPoul-Henning Kamp * can do whatever you want with this stuff. If we meet some day, and you think 891266b96SPoul-Henning Kamp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 991266b96SPoul-Henning Kamp * ---------------------------------------------------------------------------- 10b0fdc837SLawrence Stewart * 1116808549SKonstantin Belousov * Copyright (c) 2011, 2015, 2016 The FreeBSD Foundation 12b0fdc837SLawrence Stewart * 13b0fdc837SLawrence Stewart * Portions of this software were developed by Julien Ridoux at the University 14b0fdc837SLawrence Stewart * of Melbourne under sponsorship from the FreeBSD Foundation. 1516808549SKonstantin Belousov * 1616808549SKonstantin Belousov * Portions of this software were developed by Konstantin Belousov 1716808549SKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 18df8bae1dSRodney W. Grimes */ 19df8bae1dSRodney W. Grimes 20677b542eSDavid E. O'Brien #include <sys/cdefs.h> 21677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 22677b542eSDavid E. O'Brien 2332c20357SPoul-Henning Kamp #include "opt_ntp.h" 24b0fdc837SLawrence Stewart #include "opt_ffclock.h" 2532c20357SPoul-Henning Kamp 26df8bae1dSRodney W. Grimes #include <sys/param.h> 2791266b96SPoul-Henning Kamp #include <sys/kernel.h> 285b999a6bSDavide Italiano #include <sys/limits.h> 29b0fdc837SLawrence Stewart #include <sys/lock.h> 30b0fdc837SLawrence Stewart #include <sys/mutex.h> 319dbdf2a1SEric van Gyzen #include <sys/proc.h> 3291d9eda2SIan Lepore #include <sys/sbuf.h> 339dbdf2a1SEric van Gyzen #include <sys/sleepqueue.h> 3491266b96SPoul-Henning Kamp #include <sys/sysctl.h> 354e74721cSPoul-Henning Kamp #include <sys/syslog.h> 3691266b96SPoul-Henning Kamp #include <sys/systm.h> 37b0fdc837SLawrence Stewart #include <sys/timeffc.h> 3832c20357SPoul-Henning Kamp #include <sys/timepps.h> 3948e5da55SPoul-Henning Kamp #include <sys/timetc.h> 4039acc78aSPoul-Henning Kamp #include <sys/timex.h> 41aea81038SKonstantin Belousov #include <sys/vdso.h> 4239acc78aSPoul-Henning Kamp 433bac064fSPoul-Henning Kamp /* 44c1cccd1eSWarner Losh * A large step happens on boot. This constant detects such steps. 45c1cccd1eSWarner Losh * It is relatively small so that ntp_update_second gets called enough 46c1cccd1eSWarner Losh * in the typical 'missed a couple of seconds' case, but doesn't loop 47c1cccd1eSWarner Losh * forever when the time step is large. 484f2073fbSWarner Losh */ 494f2073fbSWarner Losh #define LARGE_STEP 200 504f2073fbSWarner Losh 514f2073fbSWarner Losh /* 5262efba6aSPoul-Henning Kamp * Implement a dummy timecounter which we can use until we get a real one 5362efba6aSPoul-Henning Kamp * in the air. This allows the console and other early stuff to use 5462efba6aSPoul-Henning Kamp * time services. 553bac064fSPoul-Henning Kamp */ 563bac064fSPoul-Henning Kamp 576b00cf46SPoul-Henning Kamp static u_int 5862efba6aSPoul-Henning Kamp dummy_get_timecount(struct timecounter *tc) 5962efba6aSPoul-Henning Kamp { 606b00cf46SPoul-Henning Kamp static u_int now; 6162efba6aSPoul-Henning Kamp 6262efba6aSPoul-Henning Kamp return (++now); 6362efba6aSPoul-Henning Kamp } 6462efba6aSPoul-Henning Kamp 6562efba6aSPoul-Henning Kamp static struct timecounter dummy_timecounter = { 6678a49a45SPoul-Henning Kamp dummy_get_timecount, 0, ~0u, 1000000, "dummy", -1000000 6762efba6aSPoul-Henning Kamp }; 6862efba6aSPoul-Henning Kamp 6962efba6aSPoul-Henning Kamp struct timehands { 7062efba6aSPoul-Henning Kamp /* These fields must be initialized by the driver. */ 716b00cf46SPoul-Henning Kamp struct timecounter *th_counter; 726b00cf46SPoul-Henning Kamp int64_t th_adjustment; 7360ae52f7SEd Schouten uint64_t th_scale; 746cf2362eSKonstantin Belousov u_int th_large_delta; 756b00cf46SPoul-Henning Kamp u_int th_offset_count; 766b00cf46SPoul-Henning Kamp struct bintime th_offset; 7750c22263SKonstantin Belousov struct bintime th_bintime; 786b00cf46SPoul-Henning Kamp struct timeval th_microtime; 796b00cf46SPoul-Henning Kamp struct timespec th_nanotime; 805760b029SKonstantin Belousov struct bintime th_boottime; 8139acc78aSPoul-Henning Kamp /* Fields not to be copied in tc_windup start with th_generation. */ 822c6946dcSKonstantin Belousov u_int th_generation; 836b00cf46SPoul-Henning Kamp struct timehands *th_next; 8462efba6aSPoul-Henning Kamp }; 8562efba6aSPoul-Henning Kamp 864b23dec4SKonstantin Belousov static struct timehands ths[16] = { 874b23dec4SKonstantin Belousov [0] = { 88a83c016fSKonstantin Belousov .th_counter = &dummy_timecounter, 89a83c016fSKonstantin Belousov .th_scale = (uint64_t)-1 / 1000000, 906cf2362eSKonstantin Belousov .th_large_delta = 1000000, 91a83c016fSKonstantin Belousov .th_offset = { .sec = 1 }, 92a83c016fSKonstantin Belousov .th_generation = 1, 934b23dec4SKonstantin Belousov }, 94f5d157fbSPoul-Henning Kamp }; 9562efba6aSPoul-Henning Kamp 964b23dec4SKonstantin Belousov static struct timehands *volatile timehands = &ths[0]; 9762efba6aSPoul-Henning Kamp struct timecounter *timecounter = &dummy_timecounter; 9862efba6aSPoul-Henning Kamp static struct timecounter *timecounters = &dummy_timecounter; 993bac064fSPoul-Henning Kamp 100621fd9dcSMark Johnston /* Mutex to protect the timecounter list. */ 101621fd9dcSMark Johnston static struct mtx tc_lock; 102621fd9dcSMark Johnston 1030e189873SAlexander Motin int tc_min_ticktock_freq = 1; 1040e189873SAlexander Motin 105a8df530dSJohn Baldwin volatile time_t time_second = 1; 106a8df530dSJohn Baldwin volatile time_t time_uptime = 1; 107227ee8a1SPoul-Henning Kamp 108a512d0abSWarner Losh /* 109a512d0abSWarner Losh * The system time is always computed by summing the estimated boot time and the 110a512d0abSWarner Losh * system uptime. The timehands track boot time, but it changes when the system 111a512d0abSWarner Losh * time is set by the user, stepped by ntpd or adjusted when resuming. It 112a512d0abSWarner Losh * is set to new_time - uptime. 113a512d0abSWarner Losh */ 114a7bc3102SPeter Wemm static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS); 1157029da5cSPawel Biernacki SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, 1167029da5cSPawel Biernacki CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, 1177029da5cSPawel Biernacki sysctl_kern_boottime, "S,timeval", 118a512d0abSWarner Losh "Estimated system boottime"); 11937d38777SBruce Evans 1207029da5cSPawel Biernacki SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1217029da5cSPawel Biernacki ""); 1227029da5cSPawel Biernacki static SYSCTL_NODE(_kern_timecounter, OID_AUTO, tc, 1237029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1247029da5cSPawel Biernacki ""); 12591266b96SPoul-Henning Kamp 1264e74721cSPoul-Henning Kamp static int timestepwarnings; 127fa9da1f5SMark Johnston SYSCTL_INT(_kern_timecounter, OID_AUTO, stepwarnings, CTLFLAG_RWTUN, 1282baa5cddSRebecca Cran ×tepwarnings, 0, "Log time steps"); 1294e74721cSPoul-Henning Kamp 1304b23dec4SKonstantin Belousov static int timehands_count = 2; 1316c46ce7eSKonstantin Belousov SYSCTL_INT(_kern_timecounter, OID_AUTO, timehands_count, 1326c46ce7eSKonstantin Belousov CTLFLAG_RDTUN | CTLFLAG_NOFETCH, 1334b23dec4SKonstantin Belousov &timehands_count, 0, "Count of timehands in rotation"); 1344b23dec4SKonstantin Belousov 1355b999a6bSDavide Italiano struct bintime bt_timethreshold; 1365b999a6bSDavide Italiano struct bintime bt_tickthreshold; 1375b999a6bSDavide Italiano sbintime_t sbt_timethreshold; 1385b999a6bSDavide Italiano sbintime_t sbt_tickthreshold; 1395b999a6bSDavide Italiano struct bintime tc_tick_bt; 1405b999a6bSDavide Italiano sbintime_t tc_tick_sbt; 1415b999a6bSDavide Italiano int tc_precexp; 1425b999a6bSDavide Italiano int tc_timepercentage = TC_DEFAULTPERC; 1435b999a6bSDavide Italiano static int sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS); 1445b999a6bSDavide Italiano SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation, 145af3b2549SHans Petter Selasky CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, 1465b999a6bSDavide Italiano sysctl_kern_timecounter_adjprecision, "I", 1475b999a6bSDavide Italiano "Allowed time interval deviation in percents"); 1485b999a6bSDavide Italiano 1499dbdf2a1SEric van Gyzen volatile int rtc_generation = 1; 1509dbdf2a1SEric van Gyzen 151e8bac3f2SIan Lepore static int tc_chosen; /* Non-zero if a specific tc was chosen via sysctl. */ 15256b9bee6SKonstantin Belousov static char tc_from_tunable[16]; 153e8bac3f2SIan Lepore 1545760b029SKonstantin Belousov static void tc_windup(struct bintime *new_boottimebin); 155e8444a7eSPoul-Henning Kamp static void cpu_tick_calibrate(int); 1569e1b5510SPoul-Henning Kamp 15757d025c3SGeorge V. Neville-Neil void dtrace_getnanotime(struct timespec *tsp); 15830b68ecdSRobert Watson void dtrace_getnanouptime(struct timespec *tsp); 15957d025c3SGeorge V. Neville-Neil 160a7bc3102SPeter Wemm static int 161a7bc3102SPeter Wemm sysctl_kern_boottime(SYSCTL_HANDLER_ARGS) 162a7bc3102SPeter Wemm { 163584b675eSKonstantin Belousov struct timeval boottime; 164584b675eSKonstantin Belousov 165584b675eSKonstantin Belousov getboottime(&boottime); 166584b675eSKonstantin Belousov 1677045ac43SOlivier Houchard /* i386 is the only arch which uses a 32bits time_t */ 1687045ac43SOlivier Houchard #ifdef __amd64__ 169a7bc3102SPeter Wemm #ifdef SCTL_MASK32 170a7bc3102SPeter Wemm int tv[2]; 171a7bc3102SPeter Wemm 172a7bc3102SPeter Wemm if (req->flags & SCTL_MASK32) { 173a7bc3102SPeter Wemm tv[0] = boottime.tv_sec; 174a7bc3102SPeter Wemm tv[1] = boottime.tv_usec; 175584b675eSKonstantin Belousov return (SYSCTL_OUT(req, tv, sizeof(tv))); 176584b675eSKonstantin Belousov } 177a7bc3102SPeter Wemm #endif 1789624d947SJuli Mallett #endif 179584b675eSKonstantin Belousov return (SYSCTL_OUT(req, &boottime, sizeof(boottime))); 180a7bc3102SPeter Wemm } 1815b1a8eb3SPoul-Henning Kamp 18293ef14a7SDavid Malone static int 18393ef14a7SDavid Malone sysctl_kern_timecounter_get(SYSCTL_HANDLER_ARGS) 18493ef14a7SDavid Malone { 18593ef14a7SDavid Malone u_int ncount; 18693ef14a7SDavid Malone struct timecounter *tc = arg1; 18793ef14a7SDavid Malone 18893ef14a7SDavid Malone ncount = tc->tc_get_timecount(tc); 1894d29106eSKonstantin Belousov return (sysctl_handle_int(oidp, &ncount, 0, req)); 19093ef14a7SDavid Malone } 19193ef14a7SDavid Malone 19293ef14a7SDavid Malone static int 19393ef14a7SDavid Malone sysctl_kern_timecounter_freq(SYSCTL_HANDLER_ARGS) 19493ef14a7SDavid Malone { 19560ae52f7SEd Schouten uint64_t freq; 19693ef14a7SDavid Malone struct timecounter *tc = arg1; 19793ef14a7SDavid Malone 19893ef14a7SDavid Malone freq = tc->tc_frequency; 1994d29106eSKonstantin Belousov return (sysctl_handle_64(oidp, &freq, 0, req)); 20093ef14a7SDavid Malone } 20193ef14a7SDavid Malone 20239acc78aSPoul-Henning Kamp /* 20339acc78aSPoul-Henning Kamp * Return the difference between the timehands' counter value now and what 20439acc78aSPoul-Henning Kamp * was when we copied it to the timehands' offset_count. 20539acc78aSPoul-Henning Kamp */ 2066b00cf46SPoul-Henning Kamp static __inline u_int 2076b00cf46SPoul-Henning Kamp tc_delta(struct timehands *th) 208e796e00dSPoul-Henning Kamp { 2096b00cf46SPoul-Henning Kamp struct timecounter *tc; 210e796e00dSPoul-Henning Kamp 2116b00cf46SPoul-Henning Kamp tc = th->th_counter; 2126b00cf46SPoul-Henning Kamp return ((tc->tc_get_timecount(tc) - th->th_offset_count) & 2136b00cf46SPoul-Henning Kamp tc->tc_counter_mask); 214e796e00dSPoul-Henning Kamp } 215a0502b19SPoul-Henning Kamp 2163d9d64aaSAndriy Gapon static __inline void 2173d9d64aaSAndriy Gapon bintime_add_tc_delta(struct bintime *bt, uint64_t scale, 2183d9d64aaSAndriy Gapon uint64_t large_delta, uint64_t delta) 2193d9d64aaSAndriy Gapon { 2203d9d64aaSAndriy Gapon uint64_t x; 2213d9d64aaSAndriy Gapon 2223d9d64aaSAndriy Gapon if (__predict_false(delta >= large_delta)) { 2233d9d64aaSAndriy Gapon /* Avoid overflow for scale * delta. */ 2243d9d64aaSAndriy Gapon x = (scale >> 32) * delta; 2253d9d64aaSAndriy Gapon bt->sec += x >> 32; 2263d9d64aaSAndriy Gapon bintime_addx(bt, x << 32); 2273d9d64aaSAndriy Gapon bintime_addx(bt, (scale & 0xffffffff) * delta); 2283d9d64aaSAndriy Gapon } else { 2293d9d64aaSAndriy Gapon bintime_addx(bt, scale * delta); 2303d9d64aaSAndriy Gapon } 2313d9d64aaSAndriy Gapon } 2323d9d64aaSAndriy Gapon 23339acc78aSPoul-Henning Kamp /* 2346b00cf46SPoul-Henning Kamp * Functions for reading the time. We have to loop until we are sure that 23539acc78aSPoul-Henning Kamp * the timehands that we operated on was not updated under our feet. See 23639acc78aSPoul-Henning Kamp * the comment in <sys/time.h> for a description of these 12 functions. 2376b00cf46SPoul-Henning Kamp */ 2386b00cf46SPoul-Henning Kamp 2396cf2362eSKonstantin Belousov static __inline void 2406cf2362eSKonstantin Belousov bintime_off(struct bintime *bt, u_int off) 2419bce0f05SLawrence Stewart { 2429bce0f05SLawrence Stewart struct timehands *th; 2436cf2362eSKonstantin Belousov struct bintime *btp; 2443d9d64aaSAndriy Gapon uint64_t scale; 2456cf2362eSKonstantin Belousov u_int delta, gen, large_delta; 2469bce0f05SLawrence Stewart 2479bce0f05SLawrence Stewart do { 2489bce0f05SLawrence Stewart th = timehands; 249f4b5a972SKonstantin Belousov gen = atomic_load_acq_int(&th->th_generation); 2506cf2362eSKonstantin Belousov btp = (struct bintime *)((vm_offset_t)th + off); 2516cf2362eSKonstantin Belousov *bt = *btp; 2526cf2362eSKonstantin Belousov scale = th->th_scale; 2536cf2362eSKonstantin Belousov delta = tc_delta(th); 2546cf2362eSKonstantin Belousov large_delta = th->th_large_delta; 255f4b5a972SKonstantin Belousov atomic_thread_fence_acq(); 256f4b5a972SKonstantin Belousov } while (gen == 0 || gen != th->th_generation); 2576cf2362eSKonstantin Belousov 2583d9d64aaSAndriy Gapon bintime_add_tc_delta(bt, scale, large_delta, delta); 2596cf2362eSKonstantin Belousov } 2606cf2362eSKonstantin Belousov #define GETTHBINTIME(dst, member) \ 2616cf2362eSKonstantin Belousov do { \ 2626cf2362eSKonstantin Belousov _Static_assert(_Generic(((struct timehands *)NULL)->member, \ 2636cf2362eSKonstantin Belousov struct bintime: 1, default: 0) == 1, \ 2646cf2362eSKonstantin Belousov "struct timehands member is not of struct bintime type"); \ 2656cf2362eSKonstantin Belousov bintime_off(dst, __offsetof(struct timehands, member)); \ 2666cf2362eSKonstantin Belousov } while (0) 2676cf2362eSKonstantin Belousov 2686cf2362eSKonstantin Belousov static __inline void 2696cf2362eSKonstantin Belousov getthmember(void *out, size_t out_size, u_int off) 2706cf2362eSKonstantin Belousov { 2716cf2362eSKonstantin Belousov struct timehands *th; 2726cf2362eSKonstantin Belousov u_int gen; 2736cf2362eSKonstantin Belousov 2746cf2362eSKonstantin Belousov do { 2756cf2362eSKonstantin Belousov th = timehands; 2766cf2362eSKonstantin Belousov gen = atomic_load_acq_int(&th->th_generation); 2776cf2362eSKonstantin Belousov memcpy(out, (char *)th + off, out_size); 2786cf2362eSKonstantin Belousov atomic_thread_fence_acq(); 2796cf2362eSKonstantin Belousov } while (gen == 0 || gen != th->th_generation); 2806cf2362eSKonstantin Belousov } 2816cf2362eSKonstantin Belousov #define GETTHMEMBER(dst, member) \ 2826cf2362eSKonstantin Belousov do { \ 2836cf2362eSKonstantin Belousov _Static_assert(_Generic(*dst, \ 2846cf2362eSKonstantin Belousov __typeof(((struct timehands *)NULL)->member): 1, \ 2856cf2362eSKonstantin Belousov default: 0) == 1, \ 2866cf2362eSKonstantin Belousov "*dst and struct timehands member have different types"); \ 2876cf2362eSKonstantin Belousov getthmember(dst, sizeof(*dst), __offsetof(struct timehands, \ 2886cf2362eSKonstantin Belousov member)); \ 2896cf2362eSKonstantin Belousov } while (0) 2906cf2362eSKonstantin Belousov 2916cf2362eSKonstantin Belousov #ifdef FFCLOCK 2926cf2362eSKonstantin Belousov void 2936cf2362eSKonstantin Belousov fbclock_binuptime(struct bintime *bt) 2946cf2362eSKonstantin Belousov { 2956cf2362eSKonstantin Belousov 2966cf2362eSKonstantin Belousov GETTHBINTIME(bt, th_offset); 2979bce0f05SLawrence Stewart } 2989bce0f05SLawrence Stewart 299e977bac3SLawrence Stewart void 3009bce0f05SLawrence Stewart fbclock_nanouptime(struct timespec *tsp) 3019bce0f05SLawrence Stewart { 3029bce0f05SLawrence Stewart struct bintime bt; 3039bce0f05SLawrence Stewart 304c2a4ee99SLawrence Stewart fbclock_binuptime(&bt); 3059bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3069bce0f05SLawrence Stewart } 3079bce0f05SLawrence Stewart 308e977bac3SLawrence Stewart void 3099bce0f05SLawrence Stewart fbclock_microuptime(struct timeval *tvp) 3109bce0f05SLawrence Stewart { 3119bce0f05SLawrence Stewart struct bintime bt; 3129bce0f05SLawrence Stewart 313c2a4ee99SLawrence Stewart fbclock_binuptime(&bt); 3149bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3159bce0f05SLawrence Stewart } 3169bce0f05SLawrence Stewart 317e977bac3SLawrence Stewart void 3189bce0f05SLawrence Stewart fbclock_bintime(struct bintime *bt) 3199bce0f05SLawrence Stewart { 3209bce0f05SLawrence Stewart 3216cf2362eSKonstantin Belousov GETTHBINTIME(bt, th_bintime); 3229bce0f05SLawrence Stewart } 3239bce0f05SLawrence Stewart 324e977bac3SLawrence Stewart void 3259bce0f05SLawrence Stewart fbclock_nanotime(struct timespec *tsp) 3269bce0f05SLawrence Stewart { 3279bce0f05SLawrence Stewart struct bintime bt; 3289bce0f05SLawrence Stewart 329c2a4ee99SLawrence Stewart fbclock_bintime(&bt); 3309bce0f05SLawrence Stewart bintime2timespec(&bt, tsp); 3319bce0f05SLawrence Stewart } 3329bce0f05SLawrence Stewart 333e977bac3SLawrence Stewart void 3349bce0f05SLawrence Stewart fbclock_microtime(struct timeval *tvp) 3359bce0f05SLawrence Stewart { 3369bce0f05SLawrence Stewart struct bintime bt; 3379bce0f05SLawrence Stewart 338c2a4ee99SLawrence Stewart fbclock_bintime(&bt); 3399bce0f05SLawrence Stewart bintime2timeval(&bt, tvp); 3409bce0f05SLawrence Stewart } 3419bce0f05SLawrence Stewart 342e977bac3SLawrence Stewart void 3439bce0f05SLawrence Stewart fbclock_getbinuptime(struct bintime *bt) 3449bce0f05SLawrence Stewart { 3459bce0f05SLawrence Stewart 3466cf2362eSKonstantin Belousov GETTHMEMBER(bt, th_offset); 3479bce0f05SLawrence Stewart } 3489bce0f05SLawrence Stewart 349e977bac3SLawrence Stewart void 3509bce0f05SLawrence Stewart fbclock_getnanouptime(struct timespec *tsp) 3519bce0f05SLawrence Stewart { 3526cf2362eSKonstantin Belousov struct bintime bt; 3539bce0f05SLawrence Stewart 3546cf2362eSKonstantin Belousov GETTHMEMBER(&bt, th_offset); 3556cf2362eSKonstantin Belousov bintime2timespec(&bt, tsp); 3569bce0f05SLawrence Stewart } 3579bce0f05SLawrence Stewart 358e977bac3SLawrence Stewart void 3599bce0f05SLawrence Stewart fbclock_getmicrouptime(struct timeval *tvp) 3609bce0f05SLawrence Stewart { 3616cf2362eSKonstantin Belousov struct bintime bt; 3629bce0f05SLawrence Stewart 3636cf2362eSKonstantin Belousov GETTHMEMBER(&bt, th_offset); 3646cf2362eSKonstantin Belousov bintime2timeval(&bt, tvp); 3659bce0f05SLawrence Stewart } 3669bce0f05SLawrence Stewart 367e977bac3SLawrence Stewart void 3689bce0f05SLawrence Stewart fbclock_getbintime(struct bintime *bt) 3699bce0f05SLawrence Stewart { 3709bce0f05SLawrence Stewart 3716cf2362eSKonstantin Belousov GETTHMEMBER(bt, th_bintime); 3729bce0f05SLawrence Stewart } 3739bce0f05SLawrence Stewart 374e977bac3SLawrence Stewart void 3759bce0f05SLawrence Stewart fbclock_getnanotime(struct timespec *tsp) 3769bce0f05SLawrence Stewart { 3779bce0f05SLawrence Stewart 3786cf2362eSKonstantin Belousov GETTHMEMBER(tsp, th_nanotime); 3799bce0f05SLawrence Stewart } 3809bce0f05SLawrence Stewart 381e977bac3SLawrence Stewart void 3829bce0f05SLawrence Stewart fbclock_getmicrotime(struct timeval *tvp) 3839bce0f05SLawrence Stewart { 3849bce0f05SLawrence Stewart 3856cf2362eSKonstantin Belousov GETTHMEMBER(tvp, th_microtime); 3869bce0f05SLawrence Stewart } 3879bce0f05SLawrence Stewart #else /* !FFCLOCK */ 3886cf2362eSKonstantin Belousov 389a0502b19SPoul-Henning Kamp void 3902028c0cdSPoul-Henning Kamp binuptime(struct bintime *bt) 3912028c0cdSPoul-Henning Kamp { 3922028c0cdSPoul-Henning Kamp 3936cf2362eSKonstantin Belousov GETTHBINTIME(bt, th_offset); 3942028c0cdSPoul-Henning Kamp } 3952028c0cdSPoul-Henning Kamp 3962028c0cdSPoul-Henning Kamp void 39739acc78aSPoul-Henning Kamp nanouptime(struct timespec *tsp) 398056abcabSPoul-Henning Kamp { 399056abcabSPoul-Henning Kamp struct bintime bt; 400056abcabSPoul-Henning Kamp 401056abcabSPoul-Henning Kamp binuptime(&bt); 40239acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 403056abcabSPoul-Henning Kamp } 404056abcabSPoul-Henning Kamp 405056abcabSPoul-Henning Kamp void 40639acc78aSPoul-Henning Kamp microuptime(struct timeval *tvp) 407056abcabSPoul-Henning Kamp { 408056abcabSPoul-Henning Kamp struct bintime bt; 409056abcabSPoul-Henning Kamp 410056abcabSPoul-Henning Kamp binuptime(&bt); 41139acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 412056abcabSPoul-Henning Kamp } 413056abcabSPoul-Henning Kamp 414056abcabSPoul-Henning Kamp void 4152028c0cdSPoul-Henning Kamp bintime(struct bintime *bt) 4162028c0cdSPoul-Henning Kamp { 4172028c0cdSPoul-Henning Kamp 4186cf2362eSKonstantin Belousov GETTHBINTIME(bt, th_bintime); 4192028c0cdSPoul-Henning Kamp } 4202028c0cdSPoul-Henning Kamp 4212028c0cdSPoul-Henning Kamp void 42239acc78aSPoul-Henning Kamp nanotime(struct timespec *tsp) 42300af9731SPoul-Henning Kamp { 4242028c0cdSPoul-Henning Kamp struct bintime bt; 42500af9731SPoul-Henning Kamp 4262028c0cdSPoul-Henning Kamp bintime(&bt); 42739acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 42848115288SPoul-Henning Kamp } 42948115288SPoul-Henning Kamp 43048115288SPoul-Henning Kamp void 43139acc78aSPoul-Henning Kamp microtime(struct timeval *tvp) 432056abcabSPoul-Henning Kamp { 433056abcabSPoul-Henning Kamp struct bintime bt; 434056abcabSPoul-Henning Kamp 435056abcabSPoul-Henning Kamp bintime(&bt); 43639acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 437056abcabSPoul-Henning Kamp } 438056abcabSPoul-Henning Kamp 439056abcabSPoul-Henning Kamp void 440056abcabSPoul-Henning Kamp getbinuptime(struct bintime *bt) 44100af9731SPoul-Henning Kamp { 44200af9731SPoul-Henning Kamp 4436cf2362eSKonstantin Belousov GETTHMEMBER(bt, th_offset); 444a0502b19SPoul-Henning Kamp } 445a0502b19SPoul-Henning Kamp 446a0502b19SPoul-Henning Kamp void 447c21410e1SPoul-Henning Kamp getnanouptime(struct timespec *tsp) 448a0502b19SPoul-Henning Kamp { 4496cf2362eSKonstantin Belousov struct bintime bt; 450a0502b19SPoul-Henning Kamp 4516cf2362eSKonstantin Belousov GETTHMEMBER(&bt, th_offset); 4526cf2362eSKonstantin Belousov bintime2timespec(&bt, tsp); 453a0502b19SPoul-Henning Kamp } 454a0502b19SPoul-Henning Kamp 455c7c9a816SPoul-Henning Kamp void 456056abcabSPoul-Henning Kamp getmicrouptime(struct timeval *tvp) 457c7c9a816SPoul-Henning Kamp { 4586cf2362eSKonstantin Belousov struct bintime bt; 4597ec73f64SPoul-Henning Kamp 4606cf2362eSKonstantin Belousov GETTHMEMBER(&bt, th_offset); 4616cf2362eSKonstantin Belousov bintime2timeval(&bt, tvp); 4627ec73f64SPoul-Henning Kamp } 4637ec73f64SPoul-Henning Kamp 4647ec73f64SPoul-Henning Kamp void 465056abcabSPoul-Henning Kamp getbintime(struct bintime *bt) 4667ec73f64SPoul-Henning Kamp { 4677ec73f64SPoul-Henning Kamp 4686cf2362eSKonstantin Belousov GETTHMEMBER(bt, th_bintime); 469056abcabSPoul-Henning Kamp } 470056abcabSPoul-Henning Kamp 471056abcabSPoul-Henning Kamp void 472056abcabSPoul-Henning Kamp getnanotime(struct timespec *tsp) 473056abcabSPoul-Henning Kamp { 474056abcabSPoul-Henning Kamp 4756cf2362eSKonstantin Belousov GETTHMEMBER(tsp, th_nanotime); 476056abcabSPoul-Henning Kamp } 477056abcabSPoul-Henning Kamp 478056abcabSPoul-Henning Kamp void 479056abcabSPoul-Henning Kamp getmicrotime(struct timeval *tvp) 480056abcabSPoul-Henning Kamp { 481056abcabSPoul-Henning Kamp 4826cf2362eSKonstantin Belousov GETTHMEMBER(tvp, th_microtime); 4837ec73f64SPoul-Henning Kamp } 4849bce0f05SLawrence Stewart #endif /* FFCLOCK */ 4857ec73f64SPoul-Henning Kamp 486584b675eSKonstantin Belousov void 487584b675eSKonstantin Belousov getboottime(struct timeval *boottime) 488584b675eSKonstantin Belousov { 4895760b029SKonstantin Belousov struct bintime boottimebin; 490584b675eSKonstantin Belousov 4915760b029SKonstantin Belousov getboottimebin(&boottimebin); 4925760b029SKonstantin Belousov bintime2timeval(&boottimebin, boottime); 493584b675eSKonstantin Belousov } 494584b675eSKonstantin Belousov 495584b675eSKonstantin Belousov void 496584b675eSKonstantin Belousov getboottimebin(struct bintime *boottimebin) 497584b675eSKonstantin Belousov { 498584b675eSKonstantin Belousov 4996cf2362eSKonstantin Belousov GETTHMEMBER(boottimebin, th_boottime); 500584b675eSKonstantin Belousov } 501584b675eSKonstantin Belousov 502b0fdc837SLawrence Stewart #ifdef FFCLOCK 503b0fdc837SLawrence Stewart /* 504b0fdc837SLawrence Stewart * Support for feed-forward synchronization algorithms. This is heavily inspired 505b0fdc837SLawrence Stewart * by the timehands mechanism but kept independent from it. *_windup() functions 506b0fdc837SLawrence Stewart * have some connection to avoid accessing the timecounter hardware more than 507b0fdc837SLawrence Stewart * necessary. 508b0fdc837SLawrence Stewart */ 509b0fdc837SLawrence Stewart 510b0fdc837SLawrence Stewart /* Feed-forward clock estimates kept updated by the synchronization daemon. */ 511b0fdc837SLawrence Stewart struct ffclock_estimate ffclock_estimate; 512b0fdc837SLawrence Stewart struct bintime ffclock_boottime; /* Feed-forward boot time estimate. */ 513b0fdc837SLawrence Stewart uint32_t ffclock_status; /* Feed-forward clock status. */ 514b0fdc837SLawrence Stewart int8_t ffclock_updated; /* New estimates are available. */ 515b0fdc837SLawrence Stewart struct mtx ffclock_mtx; /* Mutex on ffclock_estimate. */ 516b0fdc837SLawrence Stewart 517b0fdc837SLawrence Stewart struct fftimehands { 518b0fdc837SLawrence Stewart struct ffclock_estimate cest; 519b0fdc837SLawrence Stewart struct bintime tick_time; 520b0fdc837SLawrence Stewart struct bintime tick_time_lerp; 521b0fdc837SLawrence Stewart ffcounter tick_ffcount; 522b0fdc837SLawrence Stewart uint64_t period_lerp; 523b0fdc837SLawrence Stewart volatile uint8_t gen; 524b0fdc837SLawrence Stewart struct fftimehands *next; 525b0fdc837SLawrence Stewart }; 526b0fdc837SLawrence Stewart 527b0fdc837SLawrence Stewart #define NUM_ELEMENTS(x) (sizeof(x) / sizeof(*x)) 528b0fdc837SLawrence Stewart 529b0fdc837SLawrence Stewart static struct fftimehands ffth[10]; 530b0fdc837SLawrence Stewart static struct fftimehands *volatile fftimehands = ffth; 531b0fdc837SLawrence Stewart 532b0fdc837SLawrence Stewart static void 533b0fdc837SLawrence Stewart ffclock_init(void) 534b0fdc837SLawrence Stewart { 535b0fdc837SLawrence Stewart struct fftimehands *cur; 536b0fdc837SLawrence Stewart struct fftimehands *last; 537b0fdc837SLawrence Stewart 538b0fdc837SLawrence Stewart memset(ffth, 0, sizeof(ffth)); 539b0fdc837SLawrence Stewart 540b0fdc837SLawrence Stewart last = ffth + NUM_ELEMENTS(ffth) - 1; 541b0fdc837SLawrence Stewart for (cur = ffth; cur < last; cur++) 542b0fdc837SLawrence Stewart cur->next = cur + 1; 543b0fdc837SLawrence Stewart last->next = ffth; 544b0fdc837SLawrence Stewart 545b0fdc837SLawrence Stewart ffclock_updated = 0; 546b0fdc837SLawrence Stewart ffclock_status = FFCLOCK_STA_UNSYNC; 547b0fdc837SLawrence Stewart mtx_init(&ffclock_mtx, "ffclock lock", NULL, MTX_DEF); 548b0fdc837SLawrence Stewart } 549b0fdc837SLawrence Stewart 550b0fdc837SLawrence Stewart /* 551b0fdc837SLawrence Stewart * Reset the feed-forward clock estimates. Called from inittodr() to get things 552b0fdc837SLawrence Stewart * kick started and uses the timecounter nominal frequency as a first period 553b0fdc837SLawrence Stewart * estimate. Note: this function may be called several time just after boot. 554b0fdc837SLawrence Stewart * Note: this is the only function that sets the value of boot time for the 555b0fdc837SLawrence Stewart * monotonic (i.e. uptime) version of the feed-forward clock. 556b0fdc837SLawrence Stewart */ 557b0fdc837SLawrence Stewart void 558b0fdc837SLawrence Stewart ffclock_reset_clock(struct timespec *ts) 559b0fdc837SLawrence Stewart { 560b0fdc837SLawrence Stewart struct timecounter *tc; 561b0fdc837SLawrence Stewart struct ffclock_estimate cest; 562b0fdc837SLawrence Stewart 563b0fdc837SLawrence Stewart tc = timehands->th_counter; 564b0fdc837SLawrence Stewart memset(&cest, 0, sizeof(struct ffclock_estimate)); 565b0fdc837SLawrence Stewart 566b0fdc837SLawrence Stewart timespec2bintime(ts, &ffclock_boottime); 567b0fdc837SLawrence Stewart timespec2bintime(ts, &(cest.update_time)); 568b0fdc837SLawrence Stewart ffclock_read_counter(&cest.update_ffcount); 569b0fdc837SLawrence Stewart cest.leapsec_next = 0; 570b0fdc837SLawrence Stewart cest.period = ((1ULL << 63) / tc->tc_frequency) << 1; 571b0fdc837SLawrence Stewart cest.errb_abs = 0; 572b0fdc837SLawrence Stewart cest.errb_rate = 0; 573b0fdc837SLawrence Stewart cest.status = FFCLOCK_STA_UNSYNC; 574b0fdc837SLawrence Stewart cest.leapsec_total = 0; 575b0fdc837SLawrence Stewart cest.leapsec = 0; 576b0fdc837SLawrence Stewart 577b0fdc837SLawrence Stewart mtx_lock(&ffclock_mtx); 578b0fdc837SLawrence Stewart bcopy(&cest, &ffclock_estimate, sizeof(struct ffclock_estimate)); 579b0fdc837SLawrence Stewart ffclock_updated = INT8_MAX; 580b0fdc837SLawrence Stewart mtx_unlock(&ffclock_mtx); 581b0fdc837SLawrence Stewart 582b0fdc837SLawrence Stewart printf("ffclock reset: %s (%llu Hz), time = %ld.%09lu\n", tc->tc_name, 583b0fdc837SLawrence Stewart (unsigned long long)tc->tc_frequency, (long)ts->tv_sec, 584b0fdc837SLawrence Stewart (unsigned long)ts->tv_nsec); 585b0fdc837SLawrence Stewart } 586b0fdc837SLawrence Stewart 587b0fdc837SLawrence Stewart /* 588b0fdc837SLawrence Stewart * Sub-routine to convert a time interval measured in RAW counter units to time 589b0fdc837SLawrence Stewart * in seconds stored in bintime format. 590b0fdc837SLawrence Stewart * NOTE: bintime_mul requires u_int, but the value of the ffcounter may be 591b0fdc837SLawrence Stewart * larger than the max value of u_int (on 32 bit architecture). Loop to consume 592b0fdc837SLawrence Stewart * extra cycles. 593b0fdc837SLawrence Stewart */ 594b0fdc837SLawrence Stewart static void 595b0fdc837SLawrence Stewart ffclock_convert_delta(ffcounter ffdelta, uint64_t period, struct bintime *bt) 596b0fdc837SLawrence Stewart { 597b0fdc837SLawrence Stewart struct bintime bt2; 598b0fdc837SLawrence Stewart ffcounter delta, delta_max; 599b0fdc837SLawrence Stewart 600b0fdc837SLawrence Stewart delta_max = (1ULL << (8 * sizeof(unsigned int))) - 1; 601b0fdc837SLawrence Stewart bintime_clear(bt); 602b0fdc837SLawrence Stewart do { 603b0fdc837SLawrence Stewart if (ffdelta > delta_max) 604b0fdc837SLawrence Stewart delta = delta_max; 605b0fdc837SLawrence Stewart else 606b0fdc837SLawrence Stewart delta = ffdelta; 607b0fdc837SLawrence Stewart bt2.sec = 0; 608b0fdc837SLawrence Stewart bt2.frac = period; 609b0fdc837SLawrence Stewart bintime_mul(&bt2, (unsigned int)delta); 610b0fdc837SLawrence Stewart bintime_add(bt, &bt2); 611b0fdc837SLawrence Stewart ffdelta -= delta; 612b0fdc837SLawrence Stewart } while (ffdelta > 0); 613b0fdc837SLawrence Stewart } 614b0fdc837SLawrence Stewart 615b0fdc837SLawrence Stewart /* 616b0fdc837SLawrence Stewart * Update the fftimehands. 617b0fdc837SLawrence Stewart * Push the tick ffcount and time(s) forward based on current clock estimate. 618b0fdc837SLawrence Stewart * The conversion from ffcounter to bintime relies on the difference clock 619b0fdc837SLawrence Stewart * principle, whose accuracy relies on computing small time intervals. If a new 620b0fdc837SLawrence Stewart * clock estimate has been passed by the synchronisation daemon, make it 621b0fdc837SLawrence Stewart * current, and compute the linear interpolation for monotonic time if needed. 622b0fdc837SLawrence Stewart */ 623b0fdc837SLawrence Stewart static void 624b0fdc837SLawrence Stewart ffclock_windup(unsigned int delta) 625b0fdc837SLawrence Stewart { 626b0fdc837SLawrence Stewart struct ffclock_estimate *cest; 627b0fdc837SLawrence Stewart struct fftimehands *ffth; 628b0fdc837SLawrence Stewart struct bintime bt, gap_lerp; 629b0fdc837SLawrence Stewart ffcounter ffdelta; 630b0fdc837SLawrence Stewart uint64_t frac; 631b0fdc837SLawrence Stewart unsigned int polling; 632b0fdc837SLawrence Stewart uint8_t forward_jump, ogen; 633b0fdc837SLawrence Stewart 634b0fdc837SLawrence Stewart /* 635b0fdc837SLawrence Stewart * Pick the next timehand, copy current ffclock estimates and move tick 636b0fdc837SLawrence Stewart * times and counter forward. 637b0fdc837SLawrence Stewart */ 638b0fdc837SLawrence Stewart forward_jump = 0; 639b0fdc837SLawrence Stewart ffth = fftimehands->next; 640b0fdc837SLawrence Stewart ogen = ffth->gen; 641b0fdc837SLawrence Stewart ffth->gen = 0; 642b0fdc837SLawrence Stewart cest = &ffth->cest; 643b0fdc837SLawrence Stewart bcopy(&fftimehands->cest, cest, sizeof(struct ffclock_estimate)); 644b0fdc837SLawrence Stewart ffdelta = (ffcounter)delta; 645b0fdc837SLawrence Stewart ffth->period_lerp = fftimehands->period_lerp; 646b0fdc837SLawrence Stewart 647b0fdc837SLawrence Stewart ffth->tick_time = fftimehands->tick_time; 648b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, cest->period, &bt); 649b0fdc837SLawrence Stewart bintime_add(&ffth->tick_time, &bt); 650b0fdc837SLawrence Stewart 651b0fdc837SLawrence Stewart ffth->tick_time_lerp = fftimehands->tick_time_lerp; 652b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, ffth->period_lerp, &bt); 653b0fdc837SLawrence Stewart bintime_add(&ffth->tick_time_lerp, &bt); 654b0fdc837SLawrence Stewart 655b0fdc837SLawrence Stewart ffth->tick_ffcount = fftimehands->tick_ffcount + ffdelta; 656b0fdc837SLawrence Stewart 657b0fdc837SLawrence Stewart /* 658b0fdc837SLawrence Stewart * Assess the status of the clock, if the last update is too old, it is 659b0fdc837SLawrence Stewart * likely the synchronisation daemon is dead and the clock is free 660b0fdc837SLawrence Stewart * running. 661b0fdc837SLawrence Stewart */ 662b0fdc837SLawrence Stewart if (ffclock_updated == 0) { 663b0fdc837SLawrence Stewart ffdelta = ffth->tick_ffcount - cest->update_ffcount; 664b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, cest->period, &bt); 665b0fdc837SLawrence Stewart if (bt.sec > 2 * FFCLOCK_SKM_SCALE) 666b0fdc837SLawrence Stewart ffclock_status |= FFCLOCK_STA_UNSYNC; 667b0fdc837SLawrence Stewart } 668b0fdc837SLawrence Stewart 669b0fdc837SLawrence Stewart /* 670b0fdc837SLawrence Stewart * If available, grab updated clock estimates and make them current. 671b0fdc837SLawrence Stewart * Recompute time at this tick using the updated estimates. The clock 672b0fdc837SLawrence Stewart * estimates passed the feed-forward synchronisation daemon may result 673b0fdc837SLawrence Stewart * in time conversion that is not monotonically increasing (just after 674b0fdc837SLawrence Stewart * the update). time_lerp is a particular linear interpolation over the 675b0fdc837SLawrence Stewart * synchronisation algo polling period that ensures monotonicity for the 676b0fdc837SLawrence Stewart * clock ids requesting it. 677b0fdc837SLawrence Stewart */ 678b0fdc837SLawrence Stewart if (ffclock_updated > 0) { 679b0fdc837SLawrence Stewart bcopy(&ffclock_estimate, cest, sizeof(struct ffclock_estimate)); 680b0fdc837SLawrence Stewart ffdelta = ffth->tick_ffcount - cest->update_ffcount; 681b0fdc837SLawrence Stewart ffth->tick_time = cest->update_time; 682b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, cest->period, &bt); 683b0fdc837SLawrence Stewart bintime_add(&ffth->tick_time, &bt); 684b0fdc837SLawrence Stewart 685b0fdc837SLawrence Stewart /* ffclock_reset sets ffclock_updated to INT8_MAX */ 686b0fdc837SLawrence Stewart if (ffclock_updated == INT8_MAX) 687b0fdc837SLawrence Stewart ffth->tick_time_lerp = ffth->tick_time; 688b0fdc837SLawrence Stewart 689b0fdc837SLawrence Stewart if (bintime_cmp(&ffth->tick_time, &ffth->tick_time_lerp, >)) 690b0fdc837SLawrence Stewart forward_jump = 1; 691b0fdc837SLawrence Stewart else 692b0fdc837SLawrence Stewart forward_jump = 0; 693b0fdc837SLawrence Stewart 694b0fdc837SLawrence Stewart bintime_clear(&gap_lerp); 695b0fdc837SLawrence Stewart if (forward_jump) { 696b0fdc837SLawrence Stewart gap_lerp = ffth->tick_time; 697b0fdc837SLawrence Stewart bintime_sub(&gap_lerp, &ffth->tick_time_lerp); 698b0fdc837SLawrence Stewart } else { 699b0fdc837SLawrence Stewart gap_lerp = ffth->tick_time_lerp; 700b0fdc837SLawrence Stewart bintime_sub(&gap_lerp, &ffth->tick_time); 701b0fdc837SLawrence Stewart } 702b0fdc837SLawrence Stewart 703b0fdc837SLawrence Stewart /* 704b0fdc837SLawrence Stewart * The reset from the RTC clock may be far from accurate, and 705b0fdc837SLawrence Stewart * reducing the gap between real time and interpolated time 706b0fdc837SLawrence Stewart * could take a very long time if the interpolated clock insists 707b0fdc837SLawrence Stewart * on strict monotonicity. The clock is reset under very strict 708b0fdc837SLawrence Stewart * conditions (kernel time is known to be wrong and 709b0fdc837SLawrence Stewart * synchronization daemon has been restarted recently. 710b0fdc837SLawrence Stewart * ffclock_boottime absorbs the jump to ensure boot time is 711b0fdc837SLawrence Stewart * correct and uptime functions stay consistent. 712b0fdc837SLawrence Stewart */ 713b0fdc837SLawrence Stewart if (((ffclock_status & FFCLOCK_STA_UNSYNC) == FFCLOCK_STA_UNSYNC) && 714b0fdc837SLawrence Stewart ((cest->status & FFCLOCK_STA_UNSYNC) == 0) && 715b0fdc837SLawrence Stewart ((cest->status & FFCLOCK_STA_WARMUP) == FFCLOCK_STA_WARMUP)) { 716b0fdc837SLawrence Stewart if (forward_jump) 717b0fdc837SLawrence Stewart bintime_add(&ffclock_boottime, &gap_lerp); 718b0fdc837SLawrence Stewart else 719b0fdc837SLawrence Stewart bintime_sub(&ffclock_boottime, &gap_lerp); 720b0fdc837SLawrence Stewart ffth->tick_time_lerp = ffth->tick_time; 721b0fdc837SLawrence Stewart bintime_clear(&gap_lerp); 722b0fdc837SLawrence Stewart } 723b0fdc837SLawrence Stewart 724b0fdc837SLawrence Stewart ffclock_status = cest->status; 725b0fdc837SLawrence Stewart ffth->period_lerp = cest->period; 726b0fdc837SLawrence Stewart 727b0fdc837SLawrence Stewart /* 728b0fdc837SLawrence Stewart * Compute corrected period used for the linear interpolation of 729b0fdc837SLawrence Stewart * time. The rate of linear interpolation is capped to 5000PPM 730b0fdc837SLawrence Stewart * (5ms/s). 731b0fdc837SLawrence Stewart */ 732b0fdc837SLawrence Stewart if (bintime_isset(&gap_lerp)) { 733b0fdc837SLawrence Stewart ffdelta = cest->update_ffcount; 734b0fdc837SLawrence Stewart ffdelta -= fftimehands->cest.update_ffcount; 735b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, cest->period, &bt); 736b0fdc837SLawrence Stewart polling = bt.sec; 737b0fdc837SLawrence Stewart bt.sec = 0; 738b0fdc837SLawrence Stewart bt.frac = 5000000 * (uint64_t)18446744073LL; 739b0fdc837SLawrence Stewart bintime_mul(&bt, polling); 740b0fdc837SLawrence Stewart if (bintime_cmp(&gap_lerp, &bt, >)) 741b0fdc837SLawrence Stewart gap_lerp = bt; 742b0fdc837SLawrence Stewart 743b0fdc837SLawrence Stewart /* Approximate 1 sec by 1-(1/2^64) to ease arithmetic */ 744b0fdc837SLawrence Stewart frac = 0; 745b0fdc837SLawrence Stewart if (gap_lerp.sec > 0) { 746b0fdc837SLawrence Stewart frac -= 1; 747b0fdc837SLawrence Stewart frac /= ffdelta / gap_lerp.sec; 748b0fdc837SLawrence Stewart } 749b0fdc837SLawrence Stewart frac += gap_lerp.frac / ffdelta; 750b0fdc837SLawrence Stewart 751b0fdc837SLawrence Stewart if (forward_jump) 752b0fdc837SLawrence Stewart ffth->period_lerp += frac; 753b0fdc837SLawrence Stewart else 754b0fdc837SLawrence Stewart ffth->period_lerp -= frac; 755b0fdc837SLawrence Stewart } 756b0fdc837SLawrence Stewart 757b0fdc837SLawrence Stewart ffclock_updated = 0; 758b0fdc837SLawrence Stewart } 759b0fdc837SLawrence Stewart if (++ogen == 0) 760b0fdc837SLawrence Stewart ogen = 1; 761b0fdc837SLawrence Stewart ffth->gen = ogen; 762b0fdc837SLawrence Stewart fftimehands = ffth; 763b0fdc837SLawrence Stewart } 764b0fdc837SLawrence Stewart 765b0fdc837SLawrence Stewart /* 766b0fdc837SLawrence Stewart * Adjust the fftimehands when the timecounter is changed. Stating the obvious, 767b0fdc837SLawrence Stewart * the old and new hardware counter cannot be read simultaneously. tc_windup() 768b0fdc837SLawrence Stewart * does read the two counters 'back to back', but a few cycles are effectively 769b0fdc837SLawrence Stewart * lost, and not accumulated in tick_ffcount. This is a fairly radical 770b0fdc837SLawrence Stewart * operation for a feed-forward synchronization daemon, and it is its job to not 771b0fdc837SLawrence Stewart * pushing irrelevant data to the kernel. Because there is no locking here, 772b0fdc837SLawrence Stewart * simply force to ignore pending or next update to give daemon a chance to 773b0fdc837SLawrence Stewart * realize the counter has changed. 774b0fdc837SLawrence Stewart */ 775b0fdc837SLawrence Stewart static void 776b0fdc837SLawrence Stewart ffclock_change_tc(struct timehands *th) 777b0fdc837SLawrence Stewart { 778b0fdc837SLawrence Stewart struct fftimehands *ffth; 779b0fdc837SLawrence Stewart struct ffclock_estimate *cest; 780b0fdc837SLawrence Stewart struct timecounter *tc; 781b0fdc837SLawrence Stewart uint8_t ogen; 782b0fdc837SLawrence Stewart 783b0fdc837SLawrence Stewart tc = th->th_counter; 784b0fdc837SLawrence Stewart ffth = fftimehands->next; 785b0fdc837SLawrence Stewart ogen = ffth->gen; 786b0fdc837SLawrence Stewart ffth->gen = 0; 787b0fdc837SLawrence Stewart 788b0fdc837SLawrence Stewart cest = &ffth->cest; 789b0fdc837SLawrence Stewart bcopy(&(fftimehands->cest), cest, sizeof(struct ffclock_estimate)); 790b0fdc837SLawrence Stewart cest->period = ((1ULL << 63) / tc->tc_frequency ) << 1; 791b0fdc837SLawrence Stewart cest->errb_abs = 0; 792b0fdc837SLawrence Stewart cest->errb_rate = 0; 793b0fdc837SLawrence Stewart cest->status |= FFCLOCK_STA_UNSYNC; 794b0fdc837SLawrence Stewart 795b0fdc837SLawrence Stewart ffth->tick_ffcount = fftimehands->tick_ffcount; 796b0fdc837SLawrence Stewart ffth->tick_time_lerp = fftimehands->tick_time_lerp; 797b0fdc837SLawrence Stewart ffth->tick_time = fftimehands->tick_time; 798b0fdc837SLawrence Stewart ffth->period_lerp = cest->period; 799b0fdc837SLawrence Stewart 800b0fdc837SLawrence Stewart /* Do not lock but ignore next update from synchronization daemon. */ 801b0fdc837SLawrence Stewart ffclock_updated--; 802b0fdc837SLawrence Stewart 803b0fdc837SLawrence Stewart if (++ogen == 0) 804b0fdc837SLawrence Stewart ogen = 1; 805b0fdc837SLawrence Stewart ffth->gen = ogen; 806b0fdc837SLawrence Stewart fftimehands = ffth; 807b0fdc837SLawrence Stewart } 808b0fdc837SLawrence Stewart 809b0fdc837SLawrence Stewart /* 810b0fdc837SLawrence Stewart * Retrieve feed-forward counter and time of last kernel tick. 811b0fdc837SLawrence Stewart */ 812b0fdc837SLawrence Stewart void 813b0fdc837SLawrence Stewart ffclock_last_tick(ffcounter *ffcount, struct bintime *bt, uint32_t flags) 814b0fdc837SLawrence Stewart { 815b0fdc837SLawrence Stewart struct fftimehands *ffth; 816b0fdc837SLawrence Stewart uint8_t gen; 817b0fdc837SLawrence Stewart 818b0fdc837SLawrence Stewart /* 819b0fdc837SLawrence Stewart * No locking but check generation has not changed. Also need to make 820b0fdc837SLawrence Stewart * sure ffdelta is positive, i.e. ffcount > tick_ffcount. 821b0fdc837SLawrence Stewart */ 822b0fdc837SLawrence Stewart do { 823b0fdc837SLawrence Stewart ffth = fftimehands; 824b0fdc837SLawrence Stewart gen = ffth->gen; 825b0fdc837SLawrence Stewart if ((flags & FFCLOCK_LERP) == FFCLOCK_LERP) 826b0fdc837SLawrence Stewart *bt = ffth->tick_time_lerp; 827b0fdc837SLawrence Stewart else 828b0fdc837SLawrence Stewart *bt = ffth->tick_time; 829b0fdc837SLawrence Stewart *ffcount = ffth->tick_ffcount; 830b0fdc837SLawrence Stewart } while (gen == 0 || gen != ffth->gen); 831b0fdc837SLawrence Stewart } 832b0fdc837SLawrence Stewart 833b0fdc837SLawrence Stewart /* 834b0fdc837SLawrence Stewart * Absolute clock conversion. Low level function to convert ffcounter to 835b0fdc837SLawrence Stewart * bintime. The ffcounter is converted using the current ffclock period estimate 836b0fdc837SLawrence Stewart * or the "interpolated period" to ensure monotonicity. 837b0fdc837SLawrence Stewart * NOTE: this conversion may have been deferred, and the clock updated since the 838b0fdc837SLawrence Stewart * hardware counter has been read. 839b0fdc837SLawrence Stewart */ 840b0fdc837SLawrence Stewart void 841b0fdc837SLawrence Stewart ffclock_convert_abs(ffcounter ffcount, struct bintime *bt, uint32_t flags) 842b0fdc837SLawrence Stewart { 843b0fdc837SLawrence Stewart struct fftimehands *ffth; 844b0fdc837SLawrence Stewart struct bintime bt2; 845b0fdc837SLawrence Stewart ffcounter ffdelta; 846b0fdc837SLawrence Stewart uint8_t gen; 847b0fdc837SLawrence Stewart 848b0fdc837SLawrence Stewart /* 849b0fdc837SLawrence Stewart * No locking but check generation has not changed. Also need to make 850b0fdc837SLawrence Stewart * sure ffdelta is positive, i.e. ffcount > tick_ffcount. 851b0fdc837SLawrence Stewart */ 852b0fdc837SLawrence Stewart do { 853b0fdc837SLawrence Stewart ffth = fftimehands; 854b0fdc837SLawrence Stewart gen = ffth->gen; 855b0fdc837SLawrence Stewart if (ffcount > ffth->tick_ffcount) 856b0fdc837SLawrence Stewart ffdelta = ffcount - ffth->tick_ffcount; 857b0fdc837SLawrence Stewart else 858b0fdc837SLawrence Stewart ffdelta = ffth->tick_ffcount - ffcount; 859b0fdc837SLawrence Stewart 860b0fdc837SLawrence Stewart if ((flags & FFCLOCK_LERP) == FFCLOCK_LERP) { 861b0fdc837SLawrence Stewart *bt = ffth->tick_time_lerp; 862b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, ffth->period_lerp, &bt2); 863b0fdc837SLawrence Stewart } else { 864b0fdc837SLawrence Stewart *bt = ffth->tick_time; 865b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, ffth->cest.period, &bt2); 866b0fdc837SLawrence Stewart } 867b0fdc837SLawrence Stewart 868b0fdc837SLawrence Stewart if (ffcount > ffth->tick_ffcount) 869b0fdc837SLawrence Stewart bintime_add(bt, &bt2); 870b0fdc837SLawrence Stewart else 871b0fdc837SLawrence Stewart bintime_sub(bt, &bt2); 872b0fdc837SLawrence Stewart } while (gen == 0 || gen != ffth->gen); 873b0fdc837SLawrence Stewart } 874b0fdc837SLawrence Stewart 875b0fdc837SLawrence Stewart /* 876b0fdc837SLawrence Stewart * Difference clock conversion. 877b0fdc837SLawrence Stewart * Low level function to Convert a time interval measured in RAW counter units 878b0fdc837SLawrence Stewart * into bintime. The difference clock allows measuring small intervals much more 879b0fdc837SLawrence Stewart * reliably than the absolute clock. 880b0fdc837SLawrence Stewart */ 881b0fdc837SLawrence Stewart void 882b0fdc837SLawrence Stewart ffclock_convert_diff(ffcounter ffdelta, struct bintime *bt) 883b0fdc837SLawrence Stewart { 884b0fdc837SLawrence Stewart struct fftimehands *ffth; 885b0fdc837SLawrence Stewart uint8_t gen; 886b0fdc837SLawrence Stewart 887b0fdc837SLawrence Stewart /* No locking but check generation has not changed. */ 888b0fdc837SLawrence Stewart do { 889b0fdc837SLawrence Stewart ffth = fftimehands; 890b0fdc837SLawrence Stewart gen = ffth->gen; 891b0fdc837SLawrence Stewart ffclock_convert_delta(ffdelta, ffth->cest.period, bt); 892b0fdc837SLawrence Stewart } while (gen == 0 || gen != ffth->gen); 893b0fdc837SLawrence Stewart } 894b0fdc837SLawrence Stewart 895b0fdc837SLawrence Stewart /* 896b0fdc837SLawrence Stewart * Access to current ffcounter value. 897b0fdc837SLawrence Stewart */ 898b0fdc837SLawrence Stewart void 899b0fdc837SLawrence Stewart ffclock_read_counter(ffcounter *ffcount) 900b0fdc837SLawrence Stewart { 901b0fdc837SLawrence Stewart struct timehands *th; 902b0fdc837SLawrence Stewart struct fftimehands *ffth; 903b0fdc837SLawrence Stewart unsigned int gen, delta; 904b0fdc837SLawrence Stewart 905b0fdc837SLawrence Stewart /* 906b0fdc837SLawrence Stewart * ffclock_windup() called from tc_windup(), safe to rely on 907b0fdc837SLawrence Stewart * th->th_generation only, for correct delta and ffcounter. 908b0fdc837SLawrence Stewart */ 909b0fdc837SLawrence Stewart do { 910b0fdc837SLawrence Stewart th = timehands; 911f4b5a972SKonstantin Belousov gen = atomic_load_acq_int(&th->th_generation); 912b0fdc837SLawrence Stewart ffth = fftimehands; 913b0fdc837SLawrence Stewart delta = tc_delta(th); 914b0fdc837SLawrence Stewart *ffcount = ffth->tick_ffcount; 915f4b5a972SKonstantin Belousov atomic_thread_fence_acq(); 916f4b5a972SKonstantin Belousov } while (gen == 0 || gen != th->th_generation); 917b0fdc837SLawrence Stewart 918b0fdc837SLawrence Stewart *ffcount += delta; 919b0fdc837SLawrence Stewart } 9209bce0f05SLawrence Stewart 9219bce0f05SLawrence Stewart void 9229bce0f05SLawrence Stewart binuptime(struct bintime *bt) 9239bce0f05SLawrence Stewart { 9249bce0f05SLawrence Stewart 92588394fe4SLawrence Stewart binuptime_fromclock(bt, sysclock_active); 9269bce0f05SLawrence Stewart } 9279bce0f05SLawrence Stewart 9289bce0f05SLawrence Stewart void 9299bce0f05SLawrence Stewart nanouptime(struct timespec *tsp) 9309bce0f05SLawrence Stewart { 9319bce0f05SLawrence Stewart 93288394fe4SLawrence Stewart nanouptime_fromclock(tsp, sysclock_active); 9339bce0f05SLawrence Stewart } 9349bce0f05SLawrence Stewart 9359bce0f05SLawrence Stewart void 9369bce0f05SLawrence Stewart microuptime(struct timeval *tvp) 9379bce0f05SLawrence Stewart { 9389bce0f05SLawrence Stewart 93988394fe4SLawrence Stewart microuptime_fromclock(tvp, sysclock_active); 9409bce0f05SLawrence Stewart } 9419bce0f05SLawrence Stewart 9429bce0f05SLawrence Stewart void 9439bce0f05SLawrence Stewart bintime(struct bintime *bt) 9449bce0f05SLawrence Stewart { 9459bce0f05SLawrence Stewart 94688394fe4SLawrence Stewart bintime_fromclock(bt, sysclock_active); 9479bce0f05SLawrence Stewart } 9489bce0f05SLawrence Stewart 9499bce0f05SLawrence Stewart void 9509bce0f05SLawrence Stewart nanotime(struct timespec *tsp) 9519bce0f05SLawrence Stewart { 9529bce0f05SLawrence Stewart 95388394fe4SLawrence Stewart nanotime_fromclock(tsp, sysclock_active); 9549bce0f05SLawrence Stewart } 9559bce0f05SLawrence Stewart 9569bce0f05SLawrence Stewart void 9579bce0f05SLawrence Stewart microtime(struct timeval *tvp) 9589bce0f05SLawrence Stewart { 9599bce0f05SLawrence Stewart 96088394fe4SLawrence Stewart microtime_fromclock(tvp, sysclock_active); 9619bce0f05SLawrence Stewart } 9629bce0f05SLawrence Stewart 9639bce0f05SLawrence Stewart void 9649bce0f05SLawrence Stewart getbinuptime(struct bintime *bt) 9659bce0f05SLawrence Stewart { 9669bce0f05SLawrence Stewart 96788394fe4SLawrence Stewart getbinuptime_fromclock(bt, sysclock_active); 9689bce0f05SLawrence Stewart } 9699bce0f05SLawrence Stewart 9709bce0f05SLawrence Stewart void 9719bce0f05SLawrence Stewart getnanouptime(struct timespec *tsp) 9729bce0f05SLawrence Stewart { 9739bce0f05SLawrence Stewart 97488394fe4SLawrence Stewart getnanouptime_fromclock(tsp, sysclock_active); 9759bce0f05SLawrence Stewart } 9769bce0f05SLawrence Stewart 9779bce0f05SLawrence Stewart void 9789bce0f05SLawrence Stewart getmicrouptime(struct timeval *tvp) 9799bce0f05SLawrence Stewart { 9809bce0f05SLawrence Stewart 98188394fe4SLawrence Stewart getmicrouptime_fromclock(tvp, sysclock_active); 9829bce0f05SLawrence Stewart } 9839bce0f05SLawrence Stewart 9849bce0f05SLawrence Stewart void 9859bce0f05SLawrence Stewart getbintime(struct bintime *bt) 9869bce0f05SLawrence Stewart { 9879bce0f05SLawrence Stewart 98888394fe4SLawrence Stewart getbintime_fromclock(bt, sysclock_active); 9899bce0f05SLawrence Stewart } 9909bce0f05SLawrence Stewart 9919bce0f05SLawrence Stewart void 9929bce0f05SLawrence Stewart getnanotime(struct timespec *tsp) 9939bce0f05SLawrence Stewart { 9949bce0f05SLawrence Stewart 99588394fe4SLawrence Stewart getnanotime_fromclock(tsp, sysclock_active); 9969bce0f05SLawrence Stewart } 9979bce0f05SLawrence Stewart 9989bce0f05SLawrence Stewart void 9999bce0f05SLawrence Stewart getmicrotime(struct timeval *tvp) 10009bce0f05SLawrence Stewart { 10019bce0f05SLawrence Stewart 100288394fe4SLawrence Stewart getmicrouptime_fromclock(tvp, sysclock_active); 10039bce0f05SLawrence Stewart } 10046cedd609SLawrence Stewart 1005b0fdc837SLawrence Stewart #endif /* FFCLOCK */ 1006b0fdc837SLawrence Stewart 100739acc78aSPoul-Henning Kamp /* 100857d025c3SGeorge V. Neville-Neil * This is a clone of getnanotime and used for walltimestamps. 100957d025c3SGeorge V. Neville-Neil * The dtrace_ prefix prevents fbt from creating probes for 101057d025c3SGeorge V. Neville-Neil * it so walltimestamp can be safely used in all fbt probes. 101157d025c3SGeorge V. Neville-Neil */ 101257d025c3SGeorge V. Neville-Neil void 101357d025c3SGeorge V. Neville-Neil dtrace_getnanotime(struct timespec *tsp) 101457d025c3SGeorge V. Neville-Neil { 101557d025c3SGeorge V. Neville-Neil 10166cf2362eSKonstantin Belousov GETTHMEMBER(tsp, th_nanotime); 101757d025c3SGeorge V. Neville-Neil } 101857d025c3SGeorge V. Neville-Neil 101957d025c3SGeorge V. Neville-Neil /* 102030b68ecdSRobert Watson * This is a clone of getnanouptime used for time since boot. 102130b68ecdSRobert Watson * The dtrace_ prefix prevents fbt from creating probes for 102230b68ecdSRobert Watson * it so an uptime that can be safely used in all fbt probes. 102330b68ecdSRobert Watson */ 102430b68ecdSRobert Watson void 102530b68ecdSRobert Watson dtrace_getnanouptime(struct timespec *tsp) 102630b68ecdSRobert Watson { 102730b68ecdSRobert Watson struct bintime bt; 102830b68ecdSRobert Watson 102930b68ecdSRobert Watson GETTHMEMBER(&bt, th_offset); 103030b68ecdSRobert Watson bintime2timespec(&bt, tsp); 103130b68ecdSRobert Watson } 103230b68ecdSRobert Watson 103330b68ecdSRobert Watson /* 10346cedd609SLawrence Stewart * System clock currently providing time to the system. Modifiable via sysctl 10356cedd609SLawrence Stewart * when the FFCLOCK option is defined. 10366cedd609SLawrence Stewart */ 10376cedd609SLawrence Stewart int sysclock_active = SYSCLOCK_FBCK; 10386cedd609SLawrence Stewart 10396cedd609SLawrence Stewart /* Internal NTP status and error estimates. */ 10406cedd609SLawrence Stewart extern int time_status; 10416cedd609SLawrence Stewart extern long time_esterror; 10426cedd609SLawrence Stewart 10436cedd609SLawrence Stewart /* 10446cedd609SLawrence Stewart * Take a snapshot of sysclock data which can be used to compare system clocks 10456cedd609SLawrence Stewart * and generate timestamps after the fact. 10466cedd609SLawrence Stewart */ 10476cedd609SLawrence Stewart void 10486cedd609SLawrence Stewart sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast) 10496cedd609SLawrence Stewart { 10506cedd609SLawrence Stewart struct fbclock_info *fbi; 10516cedd609SLawrence Stewart struct timehands *th; 10526cedd609SLawrence Stewart struct bintime bt; 10536cedd609SLawrence Stewart unsigned int delta, gen; 10546cedd609SLawrence Stewart #ifdef FFCLOCK 10556cedd609SLawrence Stewart ffcounter ffcount; 10566cedd609SLawrence Stewart struct fftimehands *ffth; 10576cedd609SLawrence Stewart struct ffclock_info *ffi; 10586cedd609SLawrence Stewart struct ffclock_estimate cest; 10596cedd609SLawrence Stewart 10606cedd609SLawrence Stewart ffi = &clock_snap->ff_info; 10616cedd609SLawrence Stewart #endif 10626cedd609SLawrence Stewart 10636cedd609SLawrence Stewart fbi = &clock_snap->fb_info; 10646cedd609SLawrence Stewart delta = 0; 10656cedd609SLawrence Stewart 10666cedd609SLawrence Stewart do { 10676cedd609SLawrence Stewart th = timehands; 1068f4b5a972SKonstantin Belousov gen = atomic_load_acq_int(&th->th_generation); 10696cedd609SLawrence Stewart fbi->th_scale = th->th_scale; 10706cedd609SLawrence Stewart fbi->tick_time = th->th_offset; 10716cedd609SLawrence Stewart #ifdef FFCLOCK 10726cedd609SLawrence Stewart ffth = fftimehands; 10736cedd609SLawrence Stewart ffi->tick_time = ffth->tick_time_lerp; 10746cedd609SLawrence Stewart ffi->tick_time_lerp = ffth->tick_time_lerp; 10756cedd609SLawrence Stewart ffi->period = ffth->cest.period; 10766cedd609SLawrence Stewart ffi->period_lerp = ffth->period_lerp; 10776cedd609SLawrence Stewart clock_snap->ffcount = ffth->tick_ffcount; 10786cedd609SLawrence Stewart cest = ffth->cest; 10796cedd609SLawrence Stewart #endif 10806cedd609SLawrence Stewart if (!fast) 10816cedd609SLawrence Stewart delta = tc_delta(th); 1082f4b5a972SKonstantin Belousov atomic_thread_fence_acq(); 1083f4b5a972SKonstantin Belousov } while (gen == 0 || gen != th->th_generation); 10846cedd609SLawrence Stewart 10856cedd609SLawrence Stewart clock_snap->delta = delta; 10866cedd609SLawrence Stewart clock_snap->sysclock_active = sysclock_active; 10876cedd609SLawrence Stewart 10886cedd609SLawrence Stewart /* Record feedback clock status and error. */ 10896cedd609SLawrence Stewart clock_snap->fb_info.status = time_status; 10906cedd609SLawrence Stewart /* XXX: Very crude estimate of feedback clock error. */ 10916cedd609SLawrence Stewart bt.sec = time_esterror / 1000000; 10926cedd609SLawrence Stewart bt.frac = ((time_esterror - bt.sec) * 1000000) * 10936cedd609SLawrence Stewart (uint64_t)18446744073709ULL; 10946cedd609SLawrence Stewart clock_snap->fb_info.error = bt; 10956cedd609SLawrence Stewart 10966cedd609SLawrence Stewart #ifdef FFCLOCK 10976cedd609SLawrence Stewart if (!fast) 10986cedd609SLawrence Stewart clock_snap->ffcount += delta; 10996cedd609SLawrence Stewart 11006cedd609SLawrence Stewart /* Record feed-forward clock leap second adjustment. */ 11016cedd609SLawrence Stewart ffi->leapsec_adjustment = cest.leapsec_total; 11026cedd609SLawrence Stewart if (clock_snap->ffcount > cest.leapsec_next) 11036cedd609SLawrence Stewart ffi->leapsec_adjustment -= cest.leapsec; 11046cedd609SLawrence Stewart 11056cedd609SLawrence Stewart /* Record feed-forward clock status and error. */ 11066cedd609SLawrence Stewart clock_snap->ff_info.status = cest.status; 11076cedd609SLawrence Stewart ffcount = clock_snap->ffcount - cest.update_ffcount; 11086cedd609SLawrence Stewart ffclock_convert_delta(ffcount, cest.period, &bt); 11096cedd609SLawrence Stewart /* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s]. */ 11106cedd609SLawrence Stewart bintime_mul(&bt, cest.errb_rate * (uint64_t)18446744073709ULL); 11116cedd609SLawrence Stewart /* 18446744073 = int(2^64 / 1e9), since err_abs in [ns]. */ 11126cedd609SLawrence Stewart bintime_addx(&bt, cest.errb_abs * (uint64_t)18446744073ULL); 11136cedd609SLawrence Stewart clock_snap->ff_info.error = bt; 11146cedd609SLawrence Stewart #endif 11156cedd609SLawrence Stewart } 11166cedd609SLawrence Stewart 11176cedd609SLawrence Stewart /* 11186cedd609SLawrence Stewart * Convert a sysclock snapshot into a struct bintime based on the specified 11196cedd609SLawrence Stewart * clock source and flags. 11206cedd609SLawrence Stewart */ 11216cedd609SLawrence Stewart int 11226cedd609SLawrence Stewart sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, 11236cedd609SLawrence Stewart int whichclock, uint32_t flags) 11246cedd609SLawrence Stewart { 1125584b675eSKonstantin Belousov struct bintime boottimebin; 11266cedd609SLawrence Stewart #ifdef FFCLOCK 11276cedd609SLawrence Stewart struct bintime bt2; 11286cedd609SLawrence Stewart uint64_t period; 11296cedd609SLawrence Stewart #endif 11306cedd609SLawrence Stewart 11316cedd609SLawrence Stewart switch (whichclock) { 11326cedd609SLawrence Stewart case SYSCLOCK_FBCK: 11336cedd609SLawrence Stewart *bt = cs->fb_info.tick_time; 11346cedd609SLawrence Stewart 11356cedd609SLawrence Stewart /* If snapshot was created with !fast, delta will be >0. */ 11366cedd609SLawrence Stewart if (cs->delta > 0) 11376cedd609SLawrence Stewart bintime_addx(bt, cs->fb_info.th_scale * cs->delta); 11386cedd609SLawrence Stewart 1139584b675eSKonstantin Belousov if ((flags & FBCLOCK_UPTIME) == 0) { 1140584b675eSKonstantin Belousov getboottimebin(&boottimebin); 11416cedd609SLawrence Stewart bintime_add(bt, &boottimebin); 1142584b675eSKonstantin Belousov } 11436cedd609SLawrence Stewart break; 11446cedd609SLawrence Stewart #ifdef FFCLOCK 11456cedd609SLawrence Stewart case SYSCLOCK_FFWD: 11466cedd609SLawrence Stewart if (flags & FFCLOCK_LERP) { 11476cedd609SLawrence Stewart *bt = cs->ff_info.tick_time_lerp; 11486cedd609SLawrence Stewart period = cs->ff_info.period_lerp; 11496cedd609SLawrence Stewart } else { 11506cedd609SLawrence Stewart *bt = cs->ff_info.tick_time; 11516cedd609SLawrence Stewart period = cs->ff_info.period; 11526cedd609SLawrence Stewart } 11536cedd609SLawrence Stewart 11546cedd609SLawrence Stewart /* If snapshot was created with !fast, delta will be >0. */ 11556cedd609SLawrence Stewart if (cs->delta > 0) { 11566cedd609SLawrence Stewart ffclock_convert_delta(cs->delta, period, &bt2); 11576cedd609SLawrence Stewart bintime_add(bt, &bt2); 11586cedd609SLawrence Stewart } 11596cedd609SLawrence Stewart 11606cedd609SLawrence Stewart /* Leap second adjustment. */ 11616cedd609SLawrence Stewart if (flags & FFCLOCK_LEAPSEC) 11626cedd609SLawrence Stewart bt->sec -= cs->ff_info.leapsec_adjustment; 11636cedd609SLawrence Stewart 11646cedd609SLawrence Stewart /* Boot time adjustment, for uptime/monotonic clocks. */ 11656cedd609SLawrence Stewart if (flags & FFCLOCK_UPTIME) 11666cedd609SLawrence Stewart bintime_sub(bt, &ffclock_boottime); 1167de02885aSKevin Lo break; 11686cedd609SLawrence Stewart #endif 11696cedd609SLawrence Stewart default: 11706cedd609SLawrence Stewart return (EINVAL); 11716cedd609SLawrence Stewart break; 11726cedd609SLawrence Stewart } 11736cedd609SLawrence Stewart 11746cedd609SLawrence Stewart return (0); 11756cedd609SLawrence Stewart } 11766cedd609SLawrence Stewart 11776cedd609SLawrence Stewart /* 117878a49a45SPoul-Henning Kamp * Initialize a new timecounter and possibly use it. 11794e2befc0SPoul-Henning Kamp */ 11807ec73f64SPoul-Henning Kamp void 118191266b96SPoul-Henning Kamp tc_init(struct timecounter *tc) 11827ec73f64SPoul-Henning Kamp { 1183555a5de2SPoul-Henning Kamp u_int u; 118493ef14a7SDavid Malone struct sysctl_oid *tc_root; 11857ec73f64SPoul-Henning Kamp 1186c679c734SPoul-Henning Kamp u = tc->tc_frequency / tc->tc_counter_mask; 1187555a5de2SPoul-Henning Kamp /* XXX: We need some margin here, 10% is a guess */ 1188555a5de2SPoul-Henning Kamp u *= 11; 1189555a5de2SPoul-Henning Kamp u /= 10; 1190c679c734SPoul-Henning Kamp if (u > hz && tc->tc_quality >= 0) { 1191c679c734SPoul-Henning Kamp tc->tc_quality = -2000; 1192c679c734SPoul-Henning Kamp if (bootverbose) { 1193c679c734SPoul-Henning Kamp printf("Timecounter \"%s\" frequency %ju Hz", 1194555a5de2SPoul-Henning Kamp tc->tc_name, (uintmax_t)tc->tc_frequency); 1195c679c734SPoul-Henning Kamp printf(" -- Insufficient hz, needs at least %u\n", u); 1196c679c734SPoul-Henning Kamp } 1197c679c734SPoul-Henning Kamp } else if (tc->tc_quality >= 0 || bootverbose) { 1198555a5de2SPoul-Henning Kamp printf("Timecounter \"%s\" frequency %ju Hz quality %d\n", 1199555a5de2SPoul-Henning Kamp tc->tc_name, (uintmax_t)tc->tc_frequency, 120078a49a45SPoul-Henning Kamp tc->tc_quality); 1201e46eeb89SPoul-Henning Kamp } 1202c679c734SPoul-Henning Kamp 1203555a5de2SPoul-Henning Kamp /* 120493ef14a7SDavid Malone * Set up sysctl tree for this counter. 120593ef14a7SDavid Malone */ 1206fd0f5970SEd Schouten tc_root = SYSCTL_ADD_NODE_WITH_LABEL(NULL, 120793ef14a7SDavid Malone SYSCTL_STATIC_CHILDREN(_kern_timecounter_tc), OID_AUTO, tc->tc_name, 12087029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 12097029da5cSPawel Biernacki "timecounter description", "timecounter"); 121093ef14a7SDavid Malone SYSCTL_ADD_UINT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, 121193ef14a7SDavid Malone "mask", CTLFLAG_RD, &(tc->tc_counter_mask), 0, 121293ef14a7SDavid Malone "mask for implemented bits"); 121393ef14a7SDavid Malone SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, 12147029da5cSPawel Biernacki "counter", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_MPSAFE, tc, 12157029da5cSPawel Biernacki sizeof(*tc), sysctl_kern_timecounter_get, "IU", 12167029da5cSPawel Biernacki "current timecounter value"); 121793ef14a7SDavid Malone SYSCTL_ADD_PROC(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, 12187029da5cSPawel Biernacki "frequency", CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE, tc, 12197029da5cSPawel Biernacki sizeof(*tc), sysctl_kern_timecounter_freq, "QU", 12207029da5cSPawel Biernacki "timecounter frequency"); 122193ef14a7SDavid Malone SYSCTL_ADD_INT(NULL, SYSCTL_CHILDREN(tc_root), OID_AUTO, 122293ef14a7SDavid Malone "quality", CTLFLAG_RD, &(tc->tc_quality), 0, 122393ef14a7SDavid Malone "goodness of time counter"); 1224621fd9dcSMark Johnston 1225621fd9dcSMark Johnston mtx_lock(&tc_lock); 1226621fd9dcSMark Johnston tc->tc_next = timecounters; 1227621fd9dcSMark Johnston timecounters = tc; 1228621fd9dcSMark Johnston 122993ef14a7SDavid Malone /* 1230e8bac3f2SIan Lepore * Do not automatically switch if the current tc was specifically 1231e8bac3f2SIan Lepore * chosen. Never automatically use a timecounter with negative quality. 1232555a5de2SPoul-Henning Kamp * Even though we run on the dummy counter, switching here may be 1233e8bac3f2SIan Lepore * worse since this timecounter may not be monotonic. 1234555a5de2SPoul-Henning Kamp */ 1235e8bac3f2SIan Lepore if (tc_chosen) 1236621fd9dcSMark Johnston goto unlock; 123778a49a45SPoul-Henning Kamp if (tc->tc_quality < 0) 1238621fd9dcSMark Johnston goto unlock; 123956b9bee6SKonstantin Belousov if (tc_from_tunable[0] != '\0' && 124056b9bee6SKonstantin Belousov strcmp(tc->tc_name, tc_from_tunable) == 0) { 124156b9bee6SKonstantin Belousov tc_chosen = 1; 124256b9bee6SKonstantin Belousov tc_from_tunable[0] = '\0'; 124356b9bee6SKonstantin Belousov } else { 124478a49a45SPoul-Henning Kamp if (tc->tc_quality < timecounter->tc_quality) 1245621fd9dcSMark Johnston goto unlock; 1246555a5de2SPoul-Henning Kamp if (tc->tc_quality == timecounter->tc_quality && 1247555a5de2SPoul-Henning Kamp tc->tc_frequency < timecounter->tc_frequency) 1248621fd9dcSMark Johnston goto unlock; 124956b9bee6SKonstantin Belousov } 1250555a5de2SPoul-Henning Kamp (void)tc->tc_get_timecount(tc); 12517ec73f64SPoul-Henning Kamp timecounter = tc; 1252621fd9dcSMark Johnston unlock: 1253621fd9dcSMark Johnston mtx_unlock(&tc_lock); 125462efba6aSPoul-Henning Kamp } 125562efba6aSPoul-Henning Kamp 125639acc78aSPoul-Henning Kamp /* Report the frequency of the current timecounter. */ 125760ae52f7SEd Schouten uint64_t 125862efba6aSPoul-Henning Kamp tc_getfrequency(void) 125962efba6aSPoul-Henning Kamp { 126062efba6aSPoul-Henning Kamp 12616b00cf46SPoul-Henning Kamp return (timehands->th_counter->tc_frequency); 12627ec73f64SPoul-Henning Kamp } 12637ec73f64SPoul-Henning Kamp 12649dbdf2a1SEric van Gyzen static bool 12659dbdf2a1SEric van Gyzen sleeping_on_old_rtc(struct thread *td) 12669dbdf2a1SEric van Gyzen { 12679dbdf2a1SEric van Gyzen 12688addc72bSEric van Gyzen /* 12698addc72bSEric van Gyzen * td_rtcgen is modified by curthread when it is running, 12708addc72bSEric van Gyzen * and by other threads in this function. By finding the thread 12718addc72bSEric van Gyzen * on a sleepqueue and holding the lock on the sleepqueue 12728addc72bSEric van Gyzen * chain, we guarantee that the thread is not running and that 12738addc72bSEric van Gyzen * modifying td_rtcgen is safe. Setting td_rtcgen to zero informs 12748addc72bSEric van Gyzen * the thread that it was woken due to a real-time clock adjustment. 12758addc72bSEric van Gyzen * (The declaration of td_rtcgen refers to this comment.) 12768addc72bSEric van Gyzen */ 12779dbdf2a1SEric van Gyzen if (td->td_rtcgen != 0 && td->td_rtcgen != rtc_generation) { 12789dbdf2a1SEric van Gyzen td->td_rtcgen = 0; 12799dbdf2a1SEric van Gyzen return (true); 12809dbdf2a1SEric van Gyzen } 12819dbdf2a1SEric van Gyzen return (false); 12829dbdf2a1SEric van Gyzen } 12839dbdf2a1SEric van Gyzen 12845760b029SKonstantin Belousov static struct mtx tc_setclock_mtx; 12855760b029SKonstantin Belousov MTX_SYSINIT(tc_setclock_init, &tc_setclock_mtx, "tcsetc", MTX_SPIN); 12865760b029SKonstantin Belousov 128739acc78aSPoul-Henning Kamp /* 12884e82e5f6SWarner Losh * Step our concept of UTC. This is done by modifying our estimate of 12894e74721cSPoul-Henning Kamp * when we booted. 12906b00cf46SPoul-Henning Kamp */ 12917ec73f64SPoul-Henning Kamp void 129291266b96SPoul-Henning Kamp tc_setclock(struct timespec *ts) 12937ec73f64SPoul-Henning Kamp { 12945b51d1deSPoul-Henning Kamp struct timespec tbef, taft; 12954e74721cSPoul-Henning Kamp struct bintime bt, bt2; 12967ec73f64SPoul-Henning Kamp 12974e74721cSPoul-Henning Kamp timespec2bintime(ts, &bt); 12985760b029SKonstantin Belousov nanotime(&tbef); 12995760b029SKonstantin Belousov mtx_lock_spin(&tc_setclock_mtx); 13005760b029SKonstantin Belousov cpu_tick_calibrate(1); 13015b51d1deSPoul-Henning Kamp binuptime(&bt2); 13024e74721cSPoul-Henning Kamp bintime_sub(&bt, &bt2); 130339acc78aSPoul-Henning Kamp 130439acc78aSPoul-Henning Kamp /* XXX fiddle all the little crinkly bits around the fiords... */ 13055760b029SKonstantin Belousov tc_windup(&bt); 13065760b029SKonstantin Belousov mtx_unlock_spin(&tc_setclock_mtx); 13078addc72bSEric van Gyzen 13089dbdf2a1SEric van Gyzen /* Avoid rtc_generation == 0, since td_rtcgen == 0 is special. */ 13099dbdf2a1SEric van Gyzen atomic_add_rel_int(&rtc_generation, 2); 13109dbdf2a1SEric van Gyzen sleepq_chains_remove_matching(sleeping_on_old_rtc); 13114e74721cSPoul-Henning Kamp if (timestepwarnings) { 13125760b029SKonstantin Belousov nanotime(&taft); 13135b51d1deSPoul-Henning Kamp log(LOG_INFO, 13145b51d1deSPoul-Henning Kamp "Time stepped from %jd.%09ld to %jd.%09ld (%jd.%09ld)\n", 13155b51d1deSPoul-Henning Kamp (intmax_t)tbef.tv_sec, tbef.tv_nsec, 13165b51d1deSPoul-Henning Kamp (intmax_t)taft.tv_sec, taft.tv_nsec, 1317ee57aeeaSPoul-Henning Kamp (intmax_t)ts->tv_sec, ts->tv_nsec); 13184e74721cSPoul-Henning Kamp } 13197ec73f64SPoul-Henning Kamp } 13207ec73f64SPoul-Henning Kamp 132139acc78aSPoul-Henning Kamp /* 1322ae750fbaSSebastian Huber * Recalculate the scaling factor. We want the number of 1/2^64 1323ae750fbaSSebastian Huber * fractions of a second per period of the hardware counter, taking 1324ae750fbaSSebastian Huber * into account the th_adjustment factor which the NTP PLL/adjtime(2) 1325ae750fbaSSebastian Huber * processing provides us with. 1326ae750fbaSSebastian Huber * 1327ae750fbaSSebastian Huber * The th_adjustment is nanoseconds per second with 32 bit binary 1328ae750fbaSSebastian Huber * fraction and we want 64 bit binary fraction of second: 1329ae750fbaSSebastian Huber * 1330ae750fbaSSebastian Huber * x = a * 2^32 / 10^9 = a * 4.294967296 1331ae750fbaSSebastian Huber * 1332ae750fbaSSebastian Huber * The range of th_adjustment is +/- 5000PPM so inside a 64bit int 1333ae750fbaSSebastian Huber * we can only multiply by about 850 without overflowing, that 1334ae750fbaSSebastian Huber * leaves no suitably precise fractions for multiply before divide. 1335ae750fbaSSebastian Huber * 1336ae750fbaSSebastian Huber * Divide before multiply with a fraction of 2199/512 results in a 1337ae750fbaSSebastian Huber * systematic undercompensation of 10PPM of th_adjustment. On a 1338ae750fbaSSebastian Huber * 5000PPM adjustment this is a 0.05PPM error. This is acceptable. 1339ae750fbaSSebastian Huber * 1340ae750fbaSSebastian Huber * We happily sacrifice the lowest of the 64 bits of our result 1341ae750fbaSSebastian Huber * to the goddess of code clarity. 1342ae750fbaSSebastian Huber */ 1343ae750fbaSSebastian Huber static void 1344ae750fbaSSebastian Huber recalculate_scaling_factor_and_large_delta(struct timehands *th) 1345ae750fbaSSebastian Huber { 1346ae750fbaSSebastian Huber uint64_t scale; 1347ae750fbaSSebastian Huber 1348ae750fbaSSebastian Huber scale = (uint64_t)1 << 63; 1349ae750fbaSSebastian Huber scale += (th->th_adjustment / 1024) * 2199; 1350ae750fbaSSebastian Huber scale /= th->th_counter->tc_frequency; 1351ae750fbaSSebastian Huber th->th_scale = scale * 2; 1352ae750fbaSSebastian Huber th->th_large_delta = MIN(((uint64_t)1 << 63) / scale, UINT_MAX); 1353ae750fbaSSebastian Huber } 1354ae750fbaSSebastian Huber 1355ae750fbaSSebastian Huber /* 135639acc78aSPoul-Henning Kamp * Initialize the next struct timehands in the ring and make 13576b00cf46SPoul-Henning Kamp * it the active timehands. Along the way we might switch to a different 13586b00cf46SPoul-Henning Kamp * timecounter and/or do seconds processing in NTP. Slightly magic. 13596b00cf46SPoul-Henning Kamp */ 13609e1b5510SPoul-Henning Kamp static void 13615760b029SKonstantin Belousov tc_windup(struct bintime *new_boottimebin) 13627ec73f64SPoul-Henning Kamp { 13632028c0cdSPoul-Henning Kamp struct bintime bt; 136426f76aeaSMark Johnston struct timecounter *tc; 136539acc78aSPoul-Henning Kamp struct timehands *th, *tho; 136639acc78aSPoul-Henning Kamp u_int delta, ncount, ogen; 136739acc78aSPoul-Henning Kamp int i; 13684f2073fbSWarner Losh time_t t; 13697ec73f64SPoul-Henning Kamp 137039acc78aSPoul-Henning Kamp /* 1371f4b5a972SKonstantin Belousov * Make the next timehands a copy of the current one, but do 1372f4b5a972SKonstantin Belousov * not overwrite the generation or next pointer. While we 1373f4b5a972SKonstantin Belousov * update the contents, the generation must be zero. We need 1374f4b5a972SKonstantin Belousov * to ensure that the zero generation is visible before the 1375f4b5a972SKonstantin Belousov * data updates become visible, which requires release fence. 1376f4b5a972SKonstantin Belousov * For similar reasons, re-reading of the generation after the 1377f4b5a972SKonstantin Belousov * data is read should use acquire fence. 13786b00cf46SPoul-Henning Kamp */ 13796b00cf46SPoul-Henning Kamp tho = timehands; 13806b00cf46SPoul-Henning Kamp th = tho->th_next; 13816b00cf46SPoul-Henning Kamp ogen = th->th_generation; 1382f4b5a972SKonstantin Belousov th->th_generation = 0; 1383f4b5a972SKonstantin Belousov atomic_thread_fence_rel(); 13845ec2c936SMateusz Guzik memcpy(th, tho, offsetof(struct timehands, th_generation)); 13855760b029SKonstantin Belousov if (new_boottimebin != NULL) 13865760b029SKonstantin Belousov th->th_boottime = *new_boottimebin; 13876b00cf46SPoul-Henning Kamp 138839acc78aSPoul-Henning Kamp /* 13896b00cf46SPoul-Henning Kamp * Capture a timecounter delta on the current timecounter and if 13906b00cf46SPoul-Henning Kamp * changing timecounters, a counter value from the new timecounter. 13916b00cf46SPoul-Henning Kamp * Update the offset fields accordingly. 13926b00cf46SPoul-Henning Kamp */ 139326f76aeaSMark Johnston tc = atomic_load_ptr(&timecounter); 13946b00cf46SPoul-Henning Kamp delta = tc_delta(th); 139526f76aeaSMark Johnston if (th->th_counter != tc) 139626f76aeaSMark Johnston ncount = tc->tc_get_timecount(tc); 139739acc78aSPoul-Henning Kamp else 139839acc78aSPoul-Henning Kamp ncount = 0; 1399b0fdc837SLawrence Stewart #ifdef FFCLOCK 1400b0fdc837SLawrence Stewart ffclock_windup(delta); 1401b0fdc837SLawrence Stewart #endif 14026b00cf46SPoul-Henning Kamp th->th_offset_count += delta; 14036b00cf46SPoul-Henning Kamp th->th_offset_count &= th->th_counter->tc_counter_mask; 14043d9d64aaSAndriy Gapon bintime_add_tc_delta(&th->th_offset, th->th_scale, 14053d9d64aaSAndriy Gapon th->th_large_delta, delta); 14066b00cf46SPoul-Henning Kamp 140739acc78aSPoul-Henning Kamp /* 14086b00cf46SPoul-Henning Kamp * Hardware latching timecounters may not generate interrupts on 14096b00cf46SPoul-Henning Kamp * PPS events, so instead we poll them. There is a finite risk that 14106b00cf46SPoul-Henning Kamp * the hardware might capture a count which is later than the one we 14116b00cf46SPoul-Henning Kamp * got above, and therefore possibly in the next NTP second which might 14126b00cf46SPoul-Henning Kamp * have a different rate than the current NTP second. It doesn't 14136b00cf46SPoul-Henning Kamp * matter in practice. 14146b00cf46SPoul-Henning Kamp */ 14156b00cf46SPoul-Henning Kamp if (tho->th_counter->tc_poll_pps) 14166b00cf46SPoul-Henning Kamp tho->th_counter->tc_poll_pps(tho->th_counter); 14176b00cf46SPoul-Henning Kamp 141839acc78aSPoul-Henning Kamp /* 1419ae750fbaSSebastian Huber * Deal with NTP second processing. The loop normally 1420c1cccd1eSWarner Losh * iterates at most once, but in extreme situations it might 1421c1cccd1eSWarner Losh * keep NTP sane if timeouts are not run for several seconds. 1422c1cccd1eSWarner Losh * At boot, the time step can be large when the TOD hardware 1423c1cccd1eSWarner Losh * has been read, so on really large steps, we call 1424c1cccd1eSWarner Losh * ntp_update_second only twice. We need to call it twice in 1425c1cccd1eSWarner Losh * case we missed a leap second. 14264f2073fbSWarner Losh */ 14274f2073fbSWarner Losh bt = th->th_offset; 14285760b029SKonstantin Belousov bintime_add(&bt, &th->th_boottime); 142945cc9f5fSWarner Losh i = bt.sec - tho->th_microtime.tv_sec; 1430ae750fbaSSebastian Huber if (i > 0) { 143145cc9f5fSWarner Losh if (i > LARGE_STEP) 143245cc9f5fSWarner Losh i = 2; 1433ae750fbaSSebastian Huber 1434ae750fbaSSebastian Huber do { 14354f2073fbSWarner Losh t = bt.sec; 14364f2073fbSWarner Losh ntp_update_second(&th->th_adjustment, &bt.sec); 14374f2073fbSWarner Losh if (bt.sec != t) 14385760b029SKonstantin Belousov th->th_boottime.sec += bt.sec - t; 1439ae750fbaSSebastian Huber --i; 1440ae750fbaSSebastian Huber } while (i > 0); 1441ae750fbaSSebastian Huber 1442ae750fbaSSebastian Huber recalculate_scaling_factor_and_large_delta(th); 14434f2073fbSWarner Losh } 1444ae750fbaSSebastian Huber 1445c1cccd1eSWarner Losh /* Update the UTC timestamps used by the get*() functions. */ 144670e3b262SKonstantin Belousov th->th_bintime = bt; 1447c1cccd1eSWarner Losh bintime2timeval(&bt, &th->th_microtime); 1448c1cccd1eSWarner Losh bintime2timespec(&bt, &th->th_nanotime); 14496b00cf46SPoul-Henning Kamp 14506b00cf46SPoul-Henning Kamp /* Now is a good time to change timecounters. */ 145126f76aeaSMark Johnston if (th->th_counter != tc) { 145208e1b4f4SJung-uk Kim #ifndef __arm__ 145326f76aeaSMark Johnston if ((tc->tc_flags & TC_FLAGS_C2STOP) != 0) 145492597e06SJohn Baldwin cpu_disable_c2_sleep++; 145592597e06SJohn Baldwin if ((th->th_counter->tc_flags & TC_FLAGS_C2STOP) != 0) 145692597e06SJohn Baldwin cpu_disable_c2_sleep--; 145708e1b4f4SJung-uk Kim #endif 145826f76aeaSMark Johnston th->th_counter = tc; 14596b00cf46SPoul-Henning Kamp th->th_offset_count = ncount; 146026f76aeaSMark Johnston tc_min_ticktock_freq = max(1, tc->tc_frequency / 146126f76aeaSMark Johnston (((uint64_t)tc->tc_counter_mask + 1) / 3)); 1462ae750fbaSSebastian Huber recalculate_scaling_factor_and_large_delta(th); 1463b0fdc837SLawrence Stewart #ifdef FFCLOCK 1464b0fdc837SLawrence Stewart ffclock_change_tc(th); 1465b0fdc837SLawrence Stewart #endif 14667ec73f64SPoul-Henning Kamp } 14677ec73f64SPoul-Henning Kamp 146839acc78aSPoul-Henning Kamp /* 146939acc78aSPoul-Henning Kamp * Now that the struct timehands is again consistent, set the new 14706b00cf46SPoul-Henning Kamp * generation number, making sure to not make it zero. 14716b00cf46SPoul-Henning Kamp */ 14726b00cf46SPoul-Henning Kamp if (++ogen == 0) 147339acc78aSPoul-Henning Kamp ogen = 1; 1474f4b5a972SKonstantin Belousov atomic_store_rel_int(&th->th_generation, ogen); 14756b00cf46SPoul-Henning Kamp 147639acc78aSPoul-Henning Kamp /* Go live with the new struct timehands. */ 14779bce0f05SLawrence Stewart #ifdef FFCLOCK 14789bce0f05SLawrence Stewart switch (sysclock_active) { 14799bce0f05SLawrence Stewart case SYSCLOCK_FBCK: 14809bce0f05SLawrence Stewart #endif 14816b00cf46SPoul-Henning Kamp time_second = th->th_microtime.tv_sec; 148238b0884cSPoul-Henning Kamp time_uptime = th->th_offset.sec; 14839bce0f05SLawrence Stewart #ifdef FFCLOCK 14849bce0f05SLawrence Stewart break; 14859bce0f05SLawrence Stewart case SYSCLOCK_FFWD: 14869bce0f05SLawrence Stewart time_second = fftimehands->tick_time_lerp.sec; 14879bce0f05SLawrence Stewart time_uptime = fftimehands->tick_time_lerp.sec - ffclock_boottime.sec; 14889bce0f05SLawrence Stewart break; 14899bce0f05SLawrence Stewart } 14909bce0f05SLawrence Stewart #endif 14919bce0f05SLawrence Stewart 14926b00cf46SPoul-Henning Kamp timehands = th; 149321c295efSKonstantin Belousov timekeep_push_vdso(); 14946b00cf46SPoul-Henning Kamp } 14956b00cf46SPoul-Henning Kamp 149639acc78aSPoul-Henning Kamp /* Report or change the active timecounter hardware. */ 14976b6ef746SBruce Evans static int 149882d9ae4eSPoul-Henning Kamp sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) 14996b6ef746SBruce Evans { 15006b6ef746SBruce Evans char newname[32]; 15016b6ef746SBruce Evans struct timecounter *newtc, *tc; 15026b6ef746SBruce Evans int error; 15036b6ef746SBruce Evans 1504621fd9dcSMark Johnston mtx_lock(&tc_lock); 150562efba6aSPoul-Henning Kamp tc = timecounter; 1506e80fb434SRobert Drehmel strlcpy(newname, tc->tc_name, sizeof(newname)); 1507621fd9dcSMark Johnston mtx_unlock(&tc_lock); 1508e80fb434SRobert Drehmel 15096b6ef746SBruce Evans error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); 1510e8bac3f2SIan Lepore if (error != 0 || req->newptr == NULL) 151162efba6aSPoul-Henning Kamp return (error); 1512621fd9dcSMark Johnston 1513621fd9dcSMark Johnston mtx_lock(&tc_lock); 1514e8bac3f2SIan Lepore /* Record that the tc in use now was specifically chosen. */ 1515e8bac3f2SIan Lepore tc_chosen = 1; 1516621fd9dcSMark Johnston if (strcmp(newname, tc->tc_name) == 0) { 1517621fd9dcSMark Johnston mtx_unlock(&tc_lock); 1518e8bac3f2SIan Lepore return (0); 1519621fd9dcSMark Johnston } 152062efba6aSPoul-Henning Kamp for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) { 152139acc78aSPoul-Henning Kamp if (strcmp(newname, newtc->tc_name) != 0) 152262efba6aSPoul-Henning Kamp continue; 152339acc78aSPoul-Henning Kamp 15246b6ef746SBruce Evans /* Warm up new timecounter. */ 15256b6ef746SBruce Evans (void)newtc->tc_get_timecount(newtc); 152639acc78aSPoul-Henning Kamp 152762efba6aSPoul-Henning Kamp timecounter = newtc; 1528d1b1b600SNeel Natu 1529d1b1b600SNeel Natu /* 1530d1b1b600SNeel Natu * The vdso timehands update is deferred until the next 1531d1b1b600SNeel Natu * 'tc_windup()'. 1532d1b1b600SNeel Natu * 1533d1b1b600SNeel Natu * This is prudent given that 'timekeep_push_vdso()' does not 1534d1b1b600SNeel Natu * use any locking and that it can be called in hard interrupt 1535d1b1b600SNeel Natu * context via 'tc_windup()'. 1536d1b1b600SNeel Natu */ 1537621fd9dcSMark Johnston break; 15386b6ef746SBruce Evans } 1539621fd9dcSMark Johnston mtx_unlock(&tc_lock); 1540621fd9dcSMark Johnston return (newtc != NULL ? 0 : EINVAL); 15416b6ef746SBruce Evans } 15427029da5cSPawel Biernacki SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, 154356b9bee6SKonstantin Belousov CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_NOFETCH | CTLFLAG_MPSAFE, 0, 0, 15447029da5cSPawel Biernacki sysctl_kern_timecounter_hardware, "A", 1545b389be97SRebecca Cran "Timecounter hardware selected"); 15466b6ef746SBruce Evans 1547e8bac3f2SIan Lepore /* Report the available timecounter hardware. */ 154878a49a45SPoul-Henning Kamp static int 154978a49a45SPoul-Henning Kamp sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS) 155078a49a45SPoul-Henning Kamp { 155191d9eda2SIan Lepore struct sbuf sb; 155278a49a45SPoul-Henning Kamp struct timecounter *tc; 155378a49a45SPoul-Henning Kamp int error; 155478a49a45SPoul-Henning Kamp 1555621fd9dcSMark Johnston error = sysctl_wire_old_buffer(req, 0); 1556621fd9dcSMark Johnston if (error != 0) 1557621fd9dcSMark Johnston return (error); 155891d9eda2SIan Lepore sbuf_new_for_sysctl(&sb, NULL, 0, req); 1559621fd9dcSMark Johnston mtx_lock(&tc_lock); 156091d9eda2SIan Lepore for (tc = timecounters; tc != NULL; tc = tc->tc_next) { 156191d9eda2SIan Lepore if (tc != timecounters) 156291d9eda2SIan Lepore sbuf_putc(&sb, ' '); 156391d9eda2SIan Lepore sbuf_printf(&sb, "%s(%d)", tc->tc_name, tc->tc_quality); 156478a49a45SPoul-Henning Kamp } 1565621fd9dcSMark Johnston mtx_unlock(&tc_lock); 156691d9eda2SIan Lepore error = sbuf_finish(&sb); 156791d9eda2SIan Lepore sbuf_delete(&sb); 156878a49a45SPoul-Henning Kamp return (error); 156978a49a45SPoul-Henning Kamp } 157078a49a45SPoul-Henning Kamp 15717029da5cSPawel Biernacki SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, 15727029da5cSPawel Biernacki CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0, 15737029da5cSPawel Biernacki sysctl_kern_timecounter_choice, "A", 15747029da5cSPawel Biernacki "Timecounter hardware detected"); 157578a49a45SPoul-Henning Kamp 157639acc78aSPoul-Henning Kamp /* 15776b00cf46SPoul-Henning Kamp * RFC 2783 PPS-API implementation. 15786b00cf46SPoul-Henning Kamp */ 15797ec73f64SPoul-Henning Kamp 158028315e27SIan Lepore /* 158128315e27SIan Lepore * Return true if the driver is aware of the abi version extensions in the 158228315e27SIan Lepore * pps_state structure, and it supports at least the given abi version number. 158328315e27SIan Lepore */ 158428315e27SIan Lepore static inline int 158528315e27SIan Lepore abi_aware(struct pps_state *pps, int vers) 158628315e27SIan Lepore { 158728315e27SIan Lepore 158828315e27SIan Lepore return ((pps->kcmode & KCMODE_ABIFLAG) && pps->driver_abi >= vers); 158928315e27SIan Lepore } 159028315e27SIan Lepore 1591a1137de9SIan Lepore static int 1592a1137de9SIan Lepore pps_fetch(struct pps_fetch_args *fapi, struct pps_state *pps) 1593a1137de9SIan Lepore { 1594a1137de9SIan Lepore int err, timo; 1595a1137de9SIan Lepore pps_seq_t aseq, cseq; 1596a1137de9SIan Lepore struct timeval tv; 1597a1137de9SIan Lepore 1598a1137de9SIan Lepore if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) 1599a1137de9SIan Lepore return (EINVAL); 1600a1137de9SIan Lepore 1601a1137de9SIan Lepore /* 1602a1137de9SIan Lepore * If no timeout is requested, immediately return whatever values were 1603a1137de9SIan Lepore * most recently captured. If timeout seconds is -1, that's a request 1604a1137de9SIan Lepore * to block without a timeout. WITNESS won't let us sleep forever 1605a1137de9SIan Lepore * without a lock (we really don't need a lock), so just repeatedly 1606a1137de9SIan Lepore * sleep a long time. 1607a1137de9SIan Lepore */ 1608a1137de9SIan Lepore if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) { 1609a1137de9SIan Lepore if (fapi->timeout.tv_sec == -1) 1610a1137de9SIan Lepore timo = 0x7fffffff; 1611a1137de9SIan Lepore else { 1612a1137de9SIan Lepore tv.tv_sec = fapi->timeout.tv_sec; 1613a1137de9SIan Lepore tv.tv_usec = fapi->timeout.tv_nsec / 1000; 1614a1137de9SIan Lepore timo = tvtohz(&tv); 1615a1137de9SIan Lepore } 16166f697994SKonstantin Belousov aseq = atomic_load_int(&pps->ppsinfo.assert_sequence); 16176f697994SKonstantin Belousov cseq = atomic_load_int(&pps->ppsinfo.clear_sequence); 16186f697994SKonstantin Belousov while (aseq == atomic_load_int(&pps->ppsinfo.assert_sequence) && 16196f697994SKonstantin Belousov cseq == atomic_load_int(&pps->ppsinfo.clear_sequence)) { 162028315e27SIan Lepore if (abi_aware(pps, 1) && pps->driver_mtx != NULL) { 162128315e27SIan Lepore if (pps->flags & PPSFLAG_MTX_SPIN) { 162228315e27SIan Lepore err = msleep_spin(pps, pps->driver_mtx, 162328315e27SIan Lepore "ppsfch", timo); 162428315e27SIan Lepore } else { 162528315e27SIan Lepore err = msleep(pps, pps->driver_mtx, PCATCH, 162628315e27SIan Lepore "ppsfch", timo); 162728315e27SIan Lepore } 162828315e27SIan Lepore } else { 1629a1137de9SIan Lepore err = tsleep(pps, PCATCH, "ppsfch", timo); 163028315e27SIan Lepore } 16316f7a9f7cSIan Lepore if (err == EWOULDBLOCK) { 16326f7a9f7cSIan Lepore if (fapi->timeout.tv_sec == -1) { 1633a1137de9SIan Lepore continue; 16346f7a9f7cSIan Lepore } else { 16356f7a9f7cSIan Lepore return (ETIMEDOUT); 16366f7a9f7cSIan Lepore } 1637a1137de9SIan Lepore } else if (err != 0) { 1638a1137de9SIan Lepore return (err); 1639a1137de9SIan Lepore } 1640a1137de9SIan Lepore } 1641a1137de9SIan Lepore } 1642a1137de9SIan Lepore 1643a1137de9SIan Lepore pps->ppsinfo.current_mode = pps->ppsparam.mode; 1644a1137de9SIan Lepore fapi->pps_info_buf = pps->ppsinfo; 1645a1137de9SIan Lepore 1646a1137de9SIan Lepore return (0); 1647a1137de9SIan Lepore } 1648a1137de9SIan Lepore 164932c20357SPoul-Henning Kamp int 165032c20357SPoul-Henning Kamp pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) 165132c20357SPoul-Henning Kamp { 165232c20357SPoul-Henning Kamp pps_params_t *app; 1653b7424f2dSJohn Hay struct pps_fetch_args *fapi; 165465e359a1SLawrence Stewart #ifdef FFCLOCK 165565e359a1SLawrence Stewart struct pps_fetch_ffc_args *fapi_ffc; 165665e359a1SLawrence Stewart #endif 1657de3f8889SPeter Wemm #ifdef PPS_SYNC 1658b7424f2dSJohn Hay struct pps_kcbind_args *kapi; 1659de3f8889SPeter Wemm #endif 166032c20357SPoul-Henning Kamp 1661d8e8b675SPoul-Henning Kamp KASSERT(pps != NULL, ("NULL pps pointer in pps_ioctl")); 166232c20357SPoul-Henning Kamp switch (cmd) { 166332c20357SPoul-Henning Kamp case PPS_IOC_CREATE: 166432c20357SPoul-Henning Kamp return (0); 166532c20357SPoul-Henning Kamp case PPS_IOC_DESTROY: 166632c20357SPoul-Henning Kamp return (0); 166732c20357SPoul-Henning Kamp case PPS_IOC_SETPARAMS: 166832c20357SPoul-Henning Kamp app = (pps_params_t *)data; 166932c20357SPoul-Henning Kamp if (app->mode & ~pps->ppscap) 167032c20357SPoul-Henning Kamp return (EINVAL); 167165e359a1SLawrence Stewart #ifdef FFCLOCK 167265e359a1SLawrence Stewart /* Ensure only a single clock is selected for ffc timestamp. */ 167365e359a1SLawrence Stewart if ((app->mode & PPS_TSCLK_MASK) == PPS_TSCLK_MASK) 167465e359a1SLawrence Stewart return (EINVAL); 167565e359a1SLawrence Stewart #endif 167632c20357SPoul-Henning Kamp pps->ppsparam = *app; 167732c20357SPoul-Henning Kamp return (0); 167832c20357SPoul-Henning Kamp case PPS_IOC_GETPARAMS: 167932c20357SPoul-Henning Kamp app = (pps_params_t *)data; 168032c20357SPoul-Henning Kamp *app = pps->ppsparam; 1681b7424f2dSJohn Hay app->api_version = PPS_API_VERS_1; 168232c20357SPoul-Henning Kamp return (0); 168332c20357SPoul-Henning Kamp case PPS_IOC_GETCAP: 168432c20357SPoul-Henning Kamp *(int*)data = pps->ppscap; 168532c20357SPoul-Henning Kamp return (0); 168632c20357SPoul-Henning Kamp case PPS_IOC_FETCH: 1687b7424f2dSJohn Hay fapi = (struct pps_fetch_args *)data; 1688a1137de9SIan Lepore return (pps_fetch(fapi, pps)); 168965e359a1SLawrence Stewart #ifdef FFCLOCK 169065e359a1SLawrence Stewart case PPS_IOC_FETCH_FFCOUNTER: 169165e359a1SLawrence Stewart fapi_ffc = (struct pps_fetch_ffc_args *)data; 169265e359a1SLawrence Stewart if (fapi_ffc->tsformat && fapi_ffc->tsformat != 169365e359a1SLawrence Stewart PPS_TSFMT_TSPEC) 169465e359a1SLawrence Stewart return (EINVAL); 169565e359a1SLawrence Stewart if (fapi_ffc->timeout.tv_sec || fapi_ffc->timeout.tv_nsec) 169665e359a1SLawrence Stewart return (EOPNOTSUPP); 169765e359a1SLawrence Stewart pps->ppsinfo_ffc.current_mode = pps->ppsparam.mode; 169865e359a1SLawrence Stewart fapi_ffc->pps_info_buf_ffc = pps->ppsinfo_ffc; 169965e359a1SLawrence Stewart /* Overwrite timestamps if feedback clock selected. */ 170065e359a1SLawrence Stewart switch (pps->ppsparam.mode & PPS_TSCLK_MASK) { 170165e359a1SLawrence Stewart case PPS_TSCLK_FBCK: 170265e359a1SLawrence Stewart fapi_ffc->pps_info_buf_ffc.assert_timestamp = 170365e359a1SLawrence Stewart pps->ppsinfo.assert_timestamp; 170465e359a1SLawrence Stewart fapi_ffc->pps_info_buf_ffc.clear_timestamp = 170565e359a1SLawrence Stewart pps->ppsinfo.clear_timestamp; 170665e359a1SLawrence Stewart break; 170765e359a1SLawrence Stewart case PPS_TSCLK_FFWD: 170865e359a1SLawrence Stewart break; 170965e359a1SLawrence Stewart default: 171065e359a1SLawrence Stewart break; 171165e359a1SLawrence Stewart } 171265e359a1SLawrence Stewart return (0); 171365e359a1SLawrence Stewart #endif /* FFCLOCK */ 1714b7424f2dSJohn Hay case PPS_IOC_KCBIND: 1715b7424f2dSJohn Hay #ifdef PPS_SYNC 1716b7424f2dSJohn Hay kapi = (struct pps_kcbind_args *)data; 1717b7424f2dSJohn Hay /* XXX Only root should be able to do this */ 1718b7424f2dSJohn Hay if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC) 1719b7424f2dSJohn Hay return (EINVAL); 1720b7424f2dSJohn Hay if (kapi->kernel_consumer != PPS_KC_HARDPPS) 1721b7424f2dSJohn Hay return (EINVAL); 1722b7424f2dSJohn Hay if (kapi->edge & ~pps->ppscap) 1723b7424f2dSJohn Hay return (EINVAL); 172428315e27SIan Lepore pps->kcmode = (kapi->edge & KCMODE_EDGEMASK) | 172528315e27SIan Lepore (pps->kcmode & KCMODE_ABIFLAG); 1726b7424f2dSJohn Hay return (0); 1727b7424f2dSJohn Hay #else 1728b7424f2dSJohn Hay return (EOPNOTSUPP); 1729b7424f2dSJohn Hay #endif 173032c20357SPoul-Henning Kamp default: 1731f8385624SPoul-Henning Kamp return (ENOIOCTL); 173232c20357SPoul-Henning Kamp } 173332c20357SPoul-Henning Kamp } 173432c20357SPoul-Henning Kamp 173532c20357SPoul-Henning Kamp void 173632c20357SPoul-Henning Kamp pps_init(struct pps_state *pps) 173732c20357SPoul-Henning Kamp { 1738a1137de9SIan Lepore pps->ppscap |= PPS_TSFMT_TSPEC | PPS_CANWAIT; 173932c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTUREASSERT) 174032c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETASSERT; 174132c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTURECLEAR) 174232c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETCLEAR; 174365e359a1SLawrence Stewart #ifdef FFCLOCK 174465e359a1SLawrence Stewart pps->ppscap |= PPS_TSCLK_MASK; 174565e359a1SLawrence Stewart #endif 174628315e27SIan Lepore pps->kcmode &= ~KCMODE_ABIFLAG; 174728315e27SIan Lepore } 174828315e27SIan Lepore 174928315e27SIan Lepore void 175028315e27SIan Lepore pps_init_abi(struct pps_state *pps) 175128315e27SIan Lepore { 175228315e27SIan Lepore 175328315e27SIan Lepore pps_init(pps); 175428315e27SIan Lepore if (pps->driver_abi > 0) { 175528315e27SIan Lepore pps->kcmode |= KCMODE_ABIFLAG; 175628315e27SIan Lepore pps->kernel_abi = PPS_ABI_VERSION; 175728315e27SIan Lepore } 175832c20357SPoul-Henning Kamp } 175932c20357SPoul-Henning Kamp 176032c20357SPoul-Henning Kamp void 17617bf758bfSPoul-Henning Kamp pps_capture(struct pps_state *pps) 17627bf758bfSPoul-Henning Kamp { 17636b00cf46SPoul-Henning Kamp struct timehands *th; 1764cb2a028bSSebastian Huber struct timecounter *tc; 17657bf758bfSPoul-Henning Kamp 1766d8e8b675SPoul-Henning Kamp KASSERT(pps != NULL, ("NULL pps pointer in pps_capture")); 17676b00cf46SPoul-Henning Kamp th = timehands; 1768f4b5a972SKonstantin Belousov pps->capgen = atomic_load_acq_int(&th->th_generation); 17696b00cf46SPoul-Henning Kamp pps->capth = th; 177065e359a1SLawrence Stewart #ifdef FFCLOCK 177165e359a1SLawrence Stewart pps->capffth = fftimehands; 177265e359a1SLawrence Stewart #endif 1773cb2a028bSSebastian Huber tc = th->th_counter; 1774cb2a028bSSebastian Huber pps->capcount = tc->tc_get_timecount(tc); 17757bf758bfSPoul-Henning Kamp } 17767bf758bfSPoul-Henning Kamp 17777bf758bfSPoul-Henning Kamp void 17787bf758bfSPoul-Henning Kamp pps_event(struct pps_state *pps, int event) 177932c20357SPoul-Henning Kamp { 1780fd88f4e1SSebastian Huber struct timehands *capth; 1781fd88f4e1SSebastian Huber struct timecounter *captc; 1782fd88f4e1SSebastian Huber uint64_t capth_scale; 178339acc78aSPoul-Henning Kamp struct bintime bt; 17841e48d9d3SSebastian Huber struct timespec *tsp, *osp; 17856b00cf46SPoul-Henning Kamp u_int tcount, *pcount; 1786aaca7045SEnji Cooper int foff; 178732c20357SPoul-Henning Kamp pps_seq_t *pseq; 178865e359a1SLawrence Stewart #ifdef FFCLOCK 178965e359a1SLawrence Stewart struct timespec *tsp_ffc; 179065e359a1SLawrence Stewart pps_seq_t *pseq_ffc; 179165e359a1SLawrence Stewart ffcounter *ffcount; 179265e359a1SLawrence Stewart #endif 1793aaca7045SEnji Cooper #ifdef PPS_SYNC 1794aaca7045SEnji Cooper int fhard; 1795aaca7045SEnji Cooper #endif 179632c20357SPoul-Henning Kamp 1797d8e8b675SPoul-Henning Kamp KASSERT(pps != NULL, ("NULL pps pointer in pps_event")); 1798721b5817SIan Lepore /* Nothing to do if not currently set to capture this event type. */ 1799721b5817SIan Lepore if ((event & pps->ppsparam.mode) == 0) 1800721b5817SIan Lepore return; 1801fd88f4e1SSebastian Huber 1802fd88f4e1SSebastian Huber /* Make a snapshot of the captured timehand */ 1803fd88f4e1SSebastian Huber capth = pps->capth; 1804fd88f4e1SSebastian Huber captc = capth->th_counter; 1805fd88f4e1SSebastian Huber capth_scale = capth->th_scale; 1806fd88f4e1SSebastian Huber tcount = capth->th_offset_count; 1807fd88f4e1SSebastian Huber bt = capth->th_bintime; 1808fd88f4e1SSebastian Huber 180939acc78aSPoul-Henning Kamp /* If the timecounter was wound up underneath us, bail out. */ 1810fd88f4e1SSebastian Huber atomic_thread_fence_acq(); 1811fd88f4e1SSebastian Huber if (pps->capgen == 0 || pps->capgen != capth->th_generation) 18127bf758bfSPoul-Henning Kamp return; 18137bf758bfSPoul-Henning Kamp 181439acc78aSPoul-Henning Kamp /* Things would be easier with arrays. */ 181532c20357SPoul-Henning Kamp if (event == PPS_CAPTUREASSERT) { 181632c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.assert_timestamp; 181732c20357SPoul-Henning Kamp osp = &pps->ppsparam.assert_offset; 181832c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETASSERT; 1819aaca7045SEnji Cooper #ifdef PPS_SYNC 1820b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTUREASSERT; 1821aaca7045SEnji Cooper #endif 182232c20357SPoul-Henning Kamp pcount = &pps->ppscount[0]; 182332c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.assert_sequence; 182465e359a1SLawrence Stewart #ifdef FFCLOCK 182565e359a1SLawrence Stewart ffcount = &pps->ppsinfo_ffc.assert_ffcount; 182665e359a1SLawrence Stewart tsp_ffc = &pps->ppsinfo_ffc.assert_timestamp; 182765e359a1SLawrence Stewart pseq_ffc = &pps->ppsinfo_ffc.assert_sequence; 182865e359a1SLawrence Stewart #endif 182932c20357SPoul-Henning Kamp } else { 183032c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.clear_timestamp; 183132c20357SPoul-Henning Kamp osp = &pps->ppsparam.clear_offset; 183232c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; 1833aaca7045SEnji Cooper #ifdef PPS_SYNC 1834b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTURECLEAR; 1835aaca7045SEnji Cooper #endif 183632c20357SPoul-Henning Kamp pcount = &pps->ppscount[1]; 183732c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.clear_sequence; 183865e359a1SLawrence Stewart #ifdef FFCLOCK 183965e359a1SLawrence Stewart ffcount = &pps->ppsinfo_ffc.clear_ffcount; 184065e359a1SLawrence Stewart tsp_ffc = &pps->ppsinfo_ffc.clear_timestamp; 184165e359a1SLawrence Stewart pseq_ffc = &pps->ppsinfo_ffc.clear_sequence; 184265e359a1SLawrence Stewart #endif 184332c20357SPoul-Henning Kamp } 184432c20357SPoul-Henning Kamp 18450448501fSSebastian Huber *pcount = pps->capcount; 18460448501fSSebastian Huber 184739acc78aSPoul-Henning Kamp /* 18486b00cf46SPoul-Henning Kamp * If the timecounter changed, we cannot compare the count values, so 18496b00cf46SPoul-Henning Kamp * we have to drop the rest of the PPS-stuff until the next event. 18506b00cf46SPoul-Henning Kamp */ 1851fd88f4e1SSebastian Huber if (__predict_false(pps->ppstc != captc)) { 1852fd88f4e1SSebastian Huber pps->ppstc = captc; 18537bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 185432c20357SPoul-Henning Kamp return; 185532c20357SPoul-Henning Kamp } 185632c20357SPoul-Henning Kamp 18570448501fSSebastian Huber (*pseq)++; 18580448501fSSebastian Huber 185939acc78aSPoul-Henning Kamp /* Convert the count to a timespec. */ 1860fd88f4e1SSebastian Huber tcount = pps->capcount - tcount; 1861fd88f4e1SSebastian Huber tcount &= captc->tc_counter_mask; 1862fd88f4e1SSebastian Huber bintime_addx(&bt, capth_scale * tcount); 18638a142484SSebastian Huber bintime2timespec(&bt, tsp); 186432c20357SPoul-Henning Kamp 186532c20357SPoul-Henning Kamp if (foff) { 18666040822cSAlan Somers timespecadd(tsp, osp, tsp); 186732c20357SPoul-Henning Kamp if (tsp->tv_nsec < 0) { 186832c20357SPoul-Henning Kamp tsp->tv_nsec += 1000000000; 186932c20357SPoul-Henning Kamp tsp->tv_sec -= 1; 187032c20357SPoul-Henning Kamp } 187132c20357SPoul-Henning Kamp } 187265e359a1SLawrence Stewart 187365e359a1SLawrence Stewart #ifdef FFCLOCK 187465e359a1SLawrence Stewart *ffcount = pps->capffth->tick_ffcount + tcount; 187565e359a1SLawrence Stewart bt = pps->capffth->tick_time; 187665e359a1SLawrence Stewart ffclock_convert_delta(tcount, pps->capffth->cest.period, &bt); 187765e359a1SLawrence Stewart bintime_add(&bt, &pps->capffth->tick_time); 187865e359a1SLawrence Stewart (*pseq_ffc)++; 18798a142484SSebastian Huber bintime2timespec(&bt, tsp_ffc); 188065e359a1SLawrence Stewart #endif 188165e359a1SLawrence Stewart 188232c20357SPoul-Henning Kamp #ifdef PPS_SYNC 188332c20357SPoul-Henning Kamp if (fhard) { 18841e48d9d3SSebastian Huber uint64_t delta_nsec; 1885*28ed159fSSebastian Huber uint64_t freq; 1886ce9fac00SPoul-Henning Kamp 188739acc78aSPoul-Henning Kamp /* 18886b00cf46SPoul-Henning Kamp * Feed the NTP PLL/FLL. 1889b1e7e201SJohn Hay * The FLL wants to know how many (hardware) nanoseconds 1890b1e7e201SJohn Hay * elapsed since the previous event. 18916b00cf46SPoul-Henning Kamp */ 18927bf758bfSPoul-Henning Kamp tcount = pps->capcount - pps->ppscount[2]; 18937bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 1894fd88f4e1SSebastian Huber tcount &= captc->tc_counter_mask; 18951e48d9d3SSebastian Huber delta_nsec = 1000000000; 18961e48d9d3SSebastian Huber delta_nsec *= tcount; 1897*28ed159fSSebastian Huber freq = captc->tc_frequency; 1898*28ed159fSSebastian Huber delta_nsec = (delta_nsec + freq / 2) / freq; 18991e48d9d3SSebastian Huber hardpps(tsp, (long)delta_nsec); 190032c20357SPoul-Henning Kamp } 190132c20357SPoul-Henning Kamp #endif 1902a1137de9SIan Lepore 1903a1137de9SIan Lepore /* Wakeup anyone sleeping in pps_fetch(). */ 1904a1137de9SIan Lepore wakeup(pps); 190532c20357SPoul-Henning Kamp } 19069e1b5510SPoul-Henning Kamp 190739acc78aSPoul-Henning Kamp /* 19089e1b5510SPoul-Henning Kamp * Timecounters need to be updated every so often to prevent the hardware 19099e1b5510SPoul-Henning Kamp * counter from overflowing. Updating also recalculates the cached values 19109e1b5510SPoul-Henning Kamp * used by the get*() family of functions, so their precision depends on 19119e1b5510SPoul-Henning Kamp * the update frequency. 19129e1b5510SPoul-Henning Kamp */ 19139e1b5510SPoul-Henning Kamp 19149e1b5510SPoul-Henning Kamp static int tc_tick; 1915b389be97SRebecca Cran SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, 1916b389be97SRebecca Cran "Approximate number of hardclock ticks in a millisecond"); 19179e1b5510SPoul-Henning Kamp 1918e7fa55afSPoul-Henning Kamp void 19190e189873SAlexander Motin tc_ticktock(int cnt) 19209e1b5510SPoul-Henning Kamp { 1921e7fa55afSPoul-Henning Kamp static int count; 19229e1b5510SPoul-Henning Kamp 19235760b029SKonstantin Belousov if (mtx_trylock_spin(&tc_setclock_mtx)) { 19240e189873SAlexander Motin count += cnt; 19255760b029SKonstantin Belousov if (count >= tc_tick) { 1926e7fa55afSPoul-Henning Kamp count = 0; 19275760b029SKonstantin Belousov tc_windup(NULL); 19285760b029SKonstantin Belousov } 19295760b029SKonstantin Belousov mtx_unlock_spin(&tc_setclock_mtx); 19305760b029SKonstantin Belousov } 19319e1b5510SPoul-Henning Kamp } 19329e1b5510SPoul-Henning Kamp 19335b999a6bSDavide Italiano static void __inline 19345b999a6bSDavide Italiano tc_adjprecision(void) 19355b999a6bSDavide Italiano { 19365b999a6bSDavide Italiano int t; 19375b999a6bSDavide Italiano 19385b999a6bSDavide Italiano if (tc_timepercentage > 0) { 19395b999a6bSDavide Italiano t = (99 + tc_timepercentage) / tc_timepercentage; 19405b999a6bSDavide Italiano tc_precexp = fls(t + (t >> 1)) - 1; 19415b999a6bSDavide Italiano FREQ2BT(hz / tc_tick, &bt_timethreshold); 19425b999a6bSDavide Italiano FREQ2BT(hz, &bt_tickthreshold); 19435b999a6bSDavide Italiano bintime_shift(&bt_timethreshold, tc_precexp); 19445b999a6bSDavide Italiano bintime_shift(&bt_tickthreshold, tc_precexp); 19455b999a6bSDavide Italiano } else { 19465b999a6bSDavide Italiano tc_precexp = 31; 19475b999a6bSDavide Italiano bt_timethreshold.sec = INT_MAX; 19485b999a6bSDavide Italiano bt_timethreshold.frac = ~(uint64_t)0; 19495b999a6bSDavide Italiano bt_tickthreshold = bt_timethreshold; 19505b999a6bSDavide Italiano } 19515b999a6bSDavide Italiano sbt_timethreshold = bttosbt(bt_timethreshold); 19525b999a6bSDavide Italiano sbt_tickthreshold = bttosbt(bt_tickthreshold); 19535b999a6bSDavide Italiano } 19545b999a6bSDavide Italiano 19555b999a6bSDavide Italiano static int 19565b999a6bSDavide Italiano sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS) 19575b999a6bSDavide Italiano { 19585b999a6bSDavide Italiano int error, val; 19595b999a6bSDavide Italiano 19605b999a6bSDavide Italiano val = tc_timepercentage; 19615b999a6bSDavide Italiano error = sysctl_handle_int(oidp, &val, 0, req); 19625b999a6bSDavide Italiano if (error != 0 || req->newptr == NULL) 19635b999a6bSDavide Italiano return (error); 19645b999a6bSDavide Italiano tc_timepercentage = val; 1965af3b2549SHans Petter Selasky if (cold) 1966af3b2549SHans Petter Selasky goto done; 19675b999a6bSDavide Italiano tc_adjprecision(); 1968af3b2549SHans Petter Selasky done: 19695b999a6bSDavide Italiano return (0); 19705b999a6bSDavide Italiano } 19715b999a6bSDavide Italiano 19726c46ce7eSKonstantin Belousov /* Set up the requested number of timehands. */ 19736c46ce7eSKonstantin Belousov static void 19746c46ce7eSKonstantin Belousov inittimehands(void *dummy) 19756c46ce7eSKonstantin Belousov { 19766c46ce7eSKonstantin Belousov struct timehands *thp; 19776c46ce7eSKonstantin Belousov int i; 19786c46ce7eSKonstantin Belousov 19796c46ce7eSKonstantin Belousov TUNABLE_INT_FETCH("kern.timecounter.timehands_count", 19806c46ce7eSKonstantin Belousov &timehands_count); 19816c46ce7eSKonstantin Belousov if (timehands_count < 1) 19826c46ce7eSKonstantin Belousov timehands_count = 1; 19836c46ce7eSKonstantin Belousov if (timehands_count > nitems(ths)) 19846c46ce7eSKonstantin Belousov timehands_count = nitems(ths); 19856c46ce7eSKonstantin Belousov for (i = 1, thp = &ths[0]; i < timehands_count; thp = &ths[i++]) 19866c46ce7eSKonstantin Belousov thp->th_next = &ths[i]; 19876c46ce7eSKonstantin Belousov thp->th_next = &ths[0]; 198856b9bee6SKonstantin Belousov 198956b9bee6SKonstantin Belousov TUNABLE_STR_FETCH("kern.timecounter.hardware", tc_from_tunable, 199056b9bee6SKonstantin Belousov sizeof(tc_from_tunable)); 199133399501SMark Johnston 199233399501SMark Johnston mtx_init(&tc_lock, "tc", NULL, MTX_DEF); 19936c46ce7eSKonstantin Belousov } 19946c46ce7eSKonstantin Belousov SYSINIT(timehands, SI_SUB_TUNABLES, SI_ORDER_ANY, inittimehands, NULL); 19956c46ce7eSKonstantin Belousov 19969e1b5510SPoul-Henning Kamp static void 19979e1b5510SPoul-Henning Kamp inittimecounter(void *dummy) 19989e1b5510SPoul-Henning Kamp { 19999e1b5510SPoul-Henning Kamp u_int p; 20006c46ce7eSKonstantin Belousov int tick_rate; 20019e1b5510SPoul-Henning Kamp 200239acc78aSPoul-Henning Kamp /* 200339acc78aSPoul-Henning Kamp * Set the initial timeout to 200439acc78aSPoul-Henning Kamp * max(1, <approx. number of hardclock ticks in a millisecond>). 200539acc78aSPoul-Henning Kamp * People should probably not use the sysctl to set the timeout 2006e3043798SPedro F. Giffuni * to smaller than its initial value, since that value is the 200739acc78aSPoul-Henning Kamp * smallest reasonable one. If they want better timestamps they 200839acc78aSPoul-Henning Kamp * should use the non-"get"* functions. 200939acc78aSPoul-Henning Kamp */ 20109e1b5510SPoul-Henning Kamp if (hz > 1000) 20119e1b5510SPoul-Henning Kamp tc_tick = (hz + 500) / 1000; 20129e1b5510SPoul-Henning Kamp else 20139e1b5510SPoul-Henning Kamp tc_tick = 1; 20145b999a6bSDavide Italiano tc_adjprecision(); 20155b999a6bSDavide Italiano FREQ2BT(hz, &tick_bt); 20165b999a6bSDavide Italiano tick_sbt = bttosbt(tick_bt); 20175b999a6bSDavide Italiano tick_rate = hz / tc_tick; 20185b999a6bSDavide Italiano FREQ2BT(tick_rate, &tc_tick_bt); 20195b999a6bSDavide Italiano tc_tick_sbt = bttosbt(tc_tick_bt); 20209e1b5510SPoul-Henning Kamp p = (tc_tick * 1000000) / hz; 20219e1b5510SPoul-Henning Kamp printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); 202239acc78aSPoul-Henning Kamp 2023b0fdc837SLawrence Stewart #ifdef FFCLOCK 2024b0fdc837SLawrence Stewart ffclock_init(); 2025b0fdc837SLawrence Stewart #endif 20264b23dec4SKonstantin Belousov 202748e5da55SPoul-Henning Kamp /* warm up new timecounter (again) and get rolling. */ 202839acc78aSPoul-Henning Kamp (void)timecounter->tc_get_timecount(timecounter); 20295760b029SKonstantin Belousov mtx_lock_spin(&tc_setclock_mtx); 20305760b029SKonstantin Belousov tc_windup(NULL); 20315760b029SKonstantin Belousov mtx_unlock_spin(&tc_setclock_mtx); 20329e1b5510SPoul-Henning Kamp } 20339e1b5510SPoul-Henning Kamp 2034237fdd78SRobert Watson SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL); 20355b1a8eb3SPoul-Henning Kamp 2036e8444a7eSPoul-Henning Kamp /* Cpu tick handling -------------------------------------------------*/ 2037e8444a7eSPoul-Henning Kamp 20388701571dSMitchell Horne static bool cpu_tick_variable; 2039e8444a7eSPoul-Henning Kamp static uint64_t cpu_tick_frequency; 2040e8444a7eSPoul-Henning Kamp 20412bf95012SAndrew Turner DPCPU_DEFINE_STATIC(uint64_t, tc_cpu_ticks_base); 20422bf95012SAndrew Turner DPCPU_DEFINE_STATIC(unsigned, tc_cpu_ticks_last); 2043b2557db6SKonstantin Belousov 204488ca07e7SJohn Baldwin static uint64_t 20455b1a8eb3SPoul-Henning Kamp tc_cpu_ticks(void) 20465b1a8eb3SPoul-Henning Kamp { 20475b1a8eb3SPoul-Henning Kamp struct timecounter *tc; 2048b2557db6SKonstantin Belousov uint64_t res, *base; 2049b2557db6SKonstantin Belousov unsigned u, *last; 20505b1a8eb3SPoul-Henning Kamp 2051b2557db6SKonstantin Belousov critical_enter(); 2052b2557db6SKonstantin Belousov base = DPCPU_PTR(tc_cpu_ticks_base); 2053b2557db6SKonstantin Belousov last = DPCPU_PTR(tc_cpu_ticks_last); 20545b1a8eb3SPoul-Henning Kamp tc = timehands->th_counter; 20555b1a8eb3SPoul-Henning Kamp u = tc->tc_get_timecount(tc) & tc->tc_counter_mask; 2056b2557db6SKonstantin Belousov if (u < *last) 2057b2557db6SKonstantin Belousov *base += (uint64_t)tc->tc_counter_mask + 1; 2058b2557db6SKonstantin Belousov *last = u; 2059b2557db6SKonstantin Belousov res = u + *base; 2060b2557db6SKonstantin Belousov critical_exit(); 2061b2557db6SKonstantin Belousov return (res); 20625b1a8eb3SPoul-Henning Kamp } 20635b1a8eb3SPoul-Henning Kamp 2064a157e425SAlexander Motin void 2065a157e425SAlexander Motin cpu_tick_calibration(void) 2066a157e425SAlexander Motin { 2067a157e425SAlexander Motin static time_t last_calib; 2068a157e425SAlexander Motin 2069a157e425SAlexander Motin if (time_uptime != last_calib && !(time_uptime & 0xf)) { 2070a157e425SAlexander Motin cpu_tick_calibrate(0); 2071a157e425SAlexander Motin last_calib = time_uptime; 2072a157e425SAlexander Motin } 2073a157e425SAlexander Motin } 2074a157e425SAlexander Motin 2075e8444a7eSPoul-Henning Kamp /* 20766b4d690cSWarner Losh * This function gets called every 16 seconds on only one designated 2077a157e425SAlexander Motin * CPU in the system from hardclock() via cpu_tick_calibration()(). 2078e8444a7eSPoul-Henning Kamp * 2079e8444a7eSPoul-Henning Kamp * Whenever the real time clock is stepped we get called with reset=1 2080e8444a7eSPoul-Henning Kamp * to make sure we handle suspend/resume and similar events correctly. 2081e8444a7eSPoul-Henning Kamp */ 2082e8444a7eSPoul-Henning Kamp 2083e8444a7eSPoul-Henning Kamp static void 2084e8444a7eSPoul-Henning Kamp cpu_tick_calibrate(int reset) 2085e8444a7eSPoul-Henning Kamp { 2086e8444a7eSPoul-Henning Kamp static uint64_t c_last; 2087e8444a7eSPoul-Henning Kamp uint64_t c_this, c_delta; 2088e8444a7eSPoul-Henning Kamp static struct bintime t_last; 2089e8444a7eSPoul-Henning Kamp struct bintime t_this, t_delta; 2090301af28aSPoul-Henning Kamp uint32_t divi; 2091e8444a7eSPoul-Henning Kamp 2092e8444a7eSPoul-Henning Kamp if (reset) { 2093e8444a7eSPoul-Henning Kamp /* The clock was stepped, abort & reset */ 2094e8444a7eSPoul-Henning Kamp t_last.sec = 0; 2095e8444a7eSPoul-Henning Kamp return; 2096e8444a7eSPoul-Henning Kamp } 2097e8444a7eSPoul-Henning Kamp 2098e8444a7eSPoul-Henning Kamp /* we don't calibrate fixed rate cputicks */ 2099e8444a7eSPoul-Henning Kamp if (!cpu_tick_variable) 2100e8444a7eSPoul-Henning Kamp return; 2101e8444a7eSPoul-Henning Kamp 2102e8444a7eSPoul-Henning Kamp getbinuptime(&t_this); 2103e8444a7eSPoul-Henning Kamp c_this = cpu_ticks(); 2104e8444a7eSPoul-Henning Kamp if (t_last.sec != 0) { 2105e8444a7eSPoul-Henning Kamp c_delta = c_this - c_last; 2106e8444a7eSPoul-Henning Kamp t_delta = t_this; 2107e8444a7eSPoul-Henning Kamp bintime_sub(&t_delta, &t_last); 2108e8444a7eSPoul-Henning Kamp /* 2109301af28aSPoul-Henning Kamp * Headroom: 2110301af28aSPoul-Henning Kamp * 2^(64-20) / 16[s] = 2111301af28aSPoul-Henning Kamp * 2^(44) / 16[s] = 2112301af28aSPoul-Henning Kamp * 17.592.186.044.416 / 16 = 2113301af28aSPoul-Henning Kamp * 1.099.511.627.776 [Hz] 2114301af28aSPoul-Henning Kamp */ 2115301af28aSPoul-Henning Kamp divi = t_delta.sec << 20; 2116301af28aSPoul-Henning Kamp divi |= t_delta.frac >> (64 - 20); 2117301af28aSPoul-Henning Kamp c_delta <<= 20; 2118301af28aSPoul-Henning Kamp c_delta /= divi; 2119e8444a7eSPoul-Henning Kamp if (c_delta > cpu_tick_frequency) { 212059048707SPoul-Henning Kamp if (0 && bootverbose) 2121fef527eeSPoul-Henning Kamp printf("cpu_tick increased to %ju Hz\n", 21226cda760fSPoul-Henning Kamp c_delta); 2123e8444a7eSPoul-Henning Kamp cpu_tick_frequency = c_delta; 2124e8444a7eSPoul-Henning Kamp } 2125e8444a7eSPoul-Henning Kamp } 2126e8444a7eSPoul-Henning Kamp c_last = c_this; 2127e8444a7eSPoul-Henning Kamp t_last = t_this; 2128e8444a7eSPoul-Henning Kamp } 2129e8444a7eSPoul-Henning Kamp 2130e8444a7eSPoul-Henning Kamp void 21318701571dSMitchell Horne set_cputicker(cpu_tick_f *func, uint64_t freq, bool isvariable) 2132e8444a7eSPoul-Henning Kamp { 2133e8444a7eSPoul-Henning Kamp 2134e8444a7eSPoul-Henning Kamp if (func == NULL) { 2135e8444a7eSPoul-Henning Kamp cpu_ticks = tc_cpu_ticks; 2136e8444a7eSPoul-Henning Kamp } else { 2137e8444a7eSPoul-Henning Kamp cpu_tick_frequency = freq; 21388701571dSMitchell Horne cpu_tick_variable = isvariable; 2139e8444a7eSPoul-Henning Kamp cpu_ticks = func; 2140e8444a7eSPoul-Henning Kamp } 2141e8444a7eSPoul-Henning Kamp } 2142e8444a7eSPoul-Henning Kamp 2143e8444a7eSPoul-Henning Kamp uint64_t 2144e8444a7eSPoul-Henning Kamp cpu_tickrate(void) 2145e8444a7eSPoul-Henning Kamp { 2146e8444a7eSPoul-Henning Kamp 2147e8444a7eSPoul-Henning Kamp if (cpu_ticks == tc_cpu_ticks) 2148e8444a7eSPoul-Henning Kamp return (tc_getfrequency()); 2149e8444a7eSPoul-Henning Kamp return (cpu_tick_frequency); 2150e8444a7eSPoul-Henning Kamp } 2151e8444a7eSPoul-Henning Kamp 2152e8444a7eSPoul-Henning Kamp /* 2153e8444a7eSPoul-Henning Kamp * We need to be slightly careful converting cputicks to microseconds. 2154e8444a7eSPoul-Henning Kamp * There is plenty of margin in 64 bits of microseconds (half a million 2155e8444a7eSPoul-Henning Kamp * years) and in 64 bits at 4 GHz (146 years), but if we do a multiply 2156e8444a7eSPoul-Henning Kamp * before divide conversion (to retain precision) we find that the 2157e8444a7eSPoul-Henning Kamp * margin shrinks to 1.5 hours (one millionth of 146y). 2158e8444a7eSPoul-Henning Kamp */ 2159e8444a7eSPoul-Henning Kamp 2160e8444a7eSPoul-Henning Kamp uint64_t 2161e8444a7eSPoul-Henning Kamp cputick2usec(uint64_t tick) 2162e8444a7eSPoul-Henning Kamp { 2163bb53dd56Sfirk uint64_t tr; 2164bb53dd56Sfirk tr = cpu_tickrate(); 2165bb53dd56Sfirk return ((tick / tr) * 1000000ULL) + ((tick % tr) * 1000000ULL) / tr; 2166e8444a7eSPoul-Henning Kamp } 2167e8444a7eSPoul-Henning Kamp 2168e8444a7eSPoul-Henning Kamp cpu_tick_f *cpu_ticks = tc_cpu_ticks; 2169aea81038SKonstantin Belousov 2170aea81038SKonstantin Belousov static int vdso_th_enable = 1; 2171aea81038SKonstantin Belousov static int 2172aea81038SKonstantin Belousov sysctl_fast_gettime(SYSCTL_HANDLER_ARGS) 2173aea81038SKonstantin Belousov { 2174aea81038SKonstantin Belousov int old_vdso_th_enable, error; 2175aea81038SKonstantin Belousov 2176aea81038SKonstantin Belousov old_vdso_th_enable = vdso_th_enable; 2177aea81038SKonstantin Belousov error = sysctl_handle_int(oidp, &old_vdso_th_enable, 0, req); 2178aea81038SKonstantin Belousov if (error != 0) 2179aea81038SKonstantin Belousov return (error); 2180aea81038SKonstantin Belousov vdso_th_enable = old_vdso_th_enable; 2181aea81038SKonstantin Belousov return (0); 2182aea81038SKonstantin Belousov } 2183aea81038SKonstantin Belousov SYSCTL_PROC(_kern_timecounter, OID_AUTO, fast_gettime, 2184aea81038SKonstantin Belousov CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 2185aea81038SKonstantin Belousov NULL, 0, sysctl_fast_gettime, "I", "Enable fast time of day"); 2186aea81038SKonstantin Belousov 2187aea81038SKonstantin Belousov uint32_t 2188aea81038SKonstantin Belousov tc_fill_vdso_timehands(struct vdso_timehands *vdso_th) 2189aea81038SKonstantin Belousov { 2190aea81038SKonstantin Belousov struct timehands *th; 2191aea81038SKonstantin Belousov uint32_t enabled; 2192aea81038SKonstantin Belousov 2193aea81038SKonstantin Belousov th = timehands; 2194aea81038SKonstantin Belousov vdso_th->th_scale = th->th_scale; 2195aea81038SKonstantin Belousov vdso_th->th_offset_count = th->th_offset_count; 2196aea81038SKonstantin Belousov vdso_th->th_counter_mask = th->th_counter->tc_counter_mask; 2197aea81038SKonstantin Belousov vdso_th->th_offset = th->th_offset; 21985760b029SKonstantin Belousov vdso_th->th_boottime = th->th_boottime; 219916808549SKonstantin Belousov if (th->th_counter->tc_fill_vdso_timehands != NULL) { 220016808549SKonstantin Belousov enabled = th->th_counter->tc_fill_vdso_timehands(vdso_th, 220116808549SKonstantin Belousov th->th_counter); 220216808549SKonstantin Belousov } else 220316808549SKonstantin Belousov enabled = 0; 2204aea81038SKonstantin Belousov if (!vdso_th_enable) 2205aea81038SKonstantin Belousov enabled = 0; 2206aea81038SKonstantin Belousov return (enabled); 2207aea81038SKonstantin Belousov } 2208aea81038SKonstantin Belousov 2209aea81038SKonstantin Belousov #ifdef COMPAT_FREEBSD32 2210aea81038SKonstantin Belousov uint32_t 2211aea81038SKonstantin Belousov tc_fill_vdso_timehands32(struct vdso_timehands32 *vdso_th32) 2212aea81038SKonstantin Belousov { 2213aea81038SKonstantin Belousov struct timehands *th; 2214aea81038SKonstantin Belousov uint32_t enabled; 2215aea81038SKonstantin Belousov 2216aea81038SKonstantin Belousov th = timehands; 2217aea81038SKonstantin Belousov *(uint64_t *)&vdso_th32->th_scale[0] = th->th_scale; 2218aea81038SKonstantin Belousov vdso_th32->th_offset_count = th->th_offset_count; 2219aea81038SKonstantin Belousov vdso_th32->th_counter_mask = th->th_counter->tc_counter_mask; 2220aea81038SKonstantin Belousov vdso_th32->th_offset.sec = th->th_offset.sec; 2221aea81038SKonstantin Belousov *(uint64_t *)&vdso_th32->th_offset.frac[0] = th->th_offset.frac; 22225760b029SKonstantin Belousov vdso_th32->th_boottime.sec = th->th_boottime.sec; 22235760b029SKonstantin Belousov *(uint64_t *)&vdso_th32->th_boottime.frac[0] = th->th_boottime.frac; 222416808549SKonstantin Belousov if (th->th_counter->tc_fill_vdso_timehands32 != NULL) { 222516808549SKonstantin Belousov enabled = th->th_counter->tc_fill_vdso_timehands32(vdso_th32, 222616808549SKonstantin Belousov th->th_counter); 222716808549SKonstantin Belousov } else 222816808549SKonstantin Belousov enabled = 0; 2229aea81038SKonstantin Belousov if (!vdso_th_enable) 2230aea81038SKonstantin Belousov enabled = 0; 2231aea81038SKonstantin Belousov return (enabled); 2232aea81038SKonstantin Belousov } 2233aea81038SKonstantin Belousov #endif 223436bcc44eSKonstantin Belousov 223536bcc44eSKonstantin Belousov #include "opt_ddb.h" 223636bcc44eSKonstantin Belousov #ifdef DDB 223736bcc44eSKonstantin Belousov #include <ddb/ddb.h> 223836bcc44eSKonstantin Belousov 223936bcc44eSKonstantin Belousov DB_SHOW_COMMAND(timecounter, db_show_timecounter) 224036bcc44eSKonstantin Belousov { 224136bcc44eSKonstantin Belousov struct timehands *th; 224236bcc44eSKonstantin Belousov struct timecounter *tc; 224336bcc44eSKonstantin Belousov u_int val1, val2; 224436bcc44eSKonstantin Belousov 224536bcc44eSKonstantin Belousov th = timehands; 224636bcc44eSKonstantin Belousov tc = th->th_counter; 224736bcc44eSKonstantin Belousov val1 = tc->tc_get_timecount(tc); 224836bcc44eSKonstantin Belousov __compiler_membar(); 224936bcc44eSKonstantin Belousov val2 = tc->tc_get_timecount(tc); 225036bcc44eSKonstantin Belousov 225136bcc44eSKonstantin Belousov db_printf("timecounter %p %s\n", tc, tc->tc_name); 225236bcc44eSKonstantin Belousov db_printf(" mask %#x freq %ju qual %d flags %#x priv %p\n", 225336bcc44eSKonstantin Belousov tc->tc_counter_mask, (uintmax_t)tc->tc_frequency, tc->tc_quality, 225436bcc44eSKonstantin Belousov tc->tc_flags, tc->tc_priv); 225536bcc44eSKonstantin Belousov db_printf(" val %#x %#x\n", val1, val2); 225636bcc44eSKonstantin Belousov db_printf("timehands adj %#jx scale %#jx ldelta %d off_cnt %d gen %d\n", 225736bcc44eSKonstantin Belousov (uintmax_t)th->th_adjustment, (uintmax_t)th->th_scale, 225836bcc44eSKonstantin Belousov th->th_large_delta, th->th_offset_count, th->th_generation); 225936bcc44eSKonstantin Belousov db_printf(" offset %jd %jd boottime %jd %jd\n", 226036bcc44eSKonstantin Belousov (intmax_t)th->th_offset.sec, (uintmax_t)th->th_offset.frac, 226136bcc44eSKonstantin Belousov (intmax_t)th->th_boottime.sec, (uintmax_t)th->th_boottime.frac); 226236bcc44eSKonstantin Belousov } 226336bcc44eSKonstantin Belousov #endif 2264