139acc78aSPoul-Henning Kamp /*- 291266b96SPoul-Henning Kamp * ---------------------------------------------------------------------------- 391266b96SPoul-Henning Kamp * "THE BEER-WARE LICENSE" (Revision 42): 491266b96SPoul-Henning Kamp * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 591266b96SPoul-Henning Kamp * can do whatever you want with this stuff. If we meet some day, and you think 691266b96SPoul-Henning Kamp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 791266b96SPoul-Henning Kamp * ---------------------------------------------------------------------------- 8df8bae1dSRodney W. Grimes * 9c3aac50fSPeter Wemm * $FreeBSD$ 10df8bae1dSRodney W. Grimes */ 11df8bae1dSRodney W. Grimes 1232c20357SPoul-Henning Kamp #include "opt_ntp.h" 1332c20357SPoul-Henning Kamp 14df8bae1dSRodney W. Grimes #include <sys/param.h> 1560ca3996SPoul-Henning Kamp #include <sys/stdint.h> 1691266b96SPoul-Henning Kamp #include <sys/kernel.h> 1791266b96SPoul-Henning Kamp #include <sys/sysctl.h> 1891266b96SPoul-Henning Kamp #include <sys/systm.h> 1932c20357SPoul-Henning Kamp #include <sys/timepps.h> 2048e5da55SPoul-Henning Kamp #include <sys/timetc.h> 2139acc78aSPoul-Henning Kamp #include <sys/timex.h> 2239acc78aSPoul-Henning Kamp 233bac064fSPoul-Henning Kamp /* 2462efba6aSPoul-Henning Kamp * Implement a dummy timecounter which we can use until we get a real one 2562efba6aSPoul-Henning Kamp * in the air. This allows the console and other early stuff to use 2662efba6aSPoul-Henning Kamp * time services. 273bac064fSPoul-Henning Kamp */ 283bac064fSPoul-Henning Kamp 296b00cf46SPoul-Henning Kamp static u_int 3062efba6aSPoul-Henning Kamp dummy_get_timecount(struct timecounter *tc) 3162efba6aSPoul-Henning Kamp { 326b00cf46SPoul-Henning Kamp static u_int now; 3362efba6aSPoul-Henning Kamp 3462efba6aSPoul-Henning Kamp return (++now); 3562efba6aSPoul-Henning Kamp } 3662efba6aSPoul-Henning Kamp 3762efba6aSPoul-Henning Kamp static struct timecounter dummy_timecounter = { 3839acc78aSPoul-Henning Kamp dummy_get_timecount, 0, ~0u, 1000000, "dummy", 3962efba6aSPoul-Henning Kamp }; 4062efba6aSPoul-Henning Kamp 4162efba6aSPoul-Henning Kamp struct timehands { 4262efba6aSPoul-Henning Kamp /* These fields must be initialized by the driver. */ 436b00cf46SPoul-Henning Kamp struct timecounter *th_counter; 446b00cf46SPoul-Henning Kamp int64_t th_adjustment; 456b00cf46SPoul-Henning Kamp u_int64_t th_scale; 466b00cf46SPoul-Henning Kamp u_int th_offset_count; 476b00cf46SPoul-Henning Kamp struct bintime th_offset; 486b00cf46SPoul-Henning Kamp struct timeval th_microtime; 496b00cf46SPoul-Henning Kamp struct timespec th_nanotime; 5039acc78aSPoul-Henning Kamp /* Fields not to be copied in tc_windup start with th_generation. */ 516b00cf46SPoul-Henning Kamp volatile u_int th_generation; 526b00cf46SPoul-Henning Kamp struct timehands *th_next; 5362efba6aSPoul-Henning Kamp }; 5462efba6aSPoul-Henning Kamp 5562efba6aSPoul-Henning Kamp extern struct timehands th0; 5639acc78aSPoul-Henning Kamp static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; 5739acc78aSPoul-Henning Kamp static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; 5839acc78aSPoul-Henning Kamp static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th8}; 5939acc78aSPoul-Henning Kamp static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th7}; 6039acc78aSPoul-Henning Kamp static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th6}; 6139acc78aSPoul-Henning Kamp static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; 6239acc78aSPoul-Henning Kamp static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; 6339acc78aSPoul-Henning Kamp static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; 6439acc78aSPoul-Henning Kamp static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; 65f5d157fbSPoul-Henning Kamp static struct timehands th0 = { 66f5d157fbSPoul-Henning Kamp &dummy_timecounter, 67f5d157fbSPoul-Henning Kamp 0, 6839acc78aSPoul-Henning Kamp (uint64_t)-1 / 1000000, 69f5d157fbSPoul-Henning Kamp 0, 70d25917e8SPoul-Henning Kamp {1, 0}, 71f5d157fbSPoul-Henning Kamp {0, 0}, 72f5d157fbSPoul-Henning Kamp {0, 0}, 73f5d157fbSPoul-Henning Kamp 1, 74f5d157fbSPoul-Henning Kamp &th1 75f5d157fbSPoul-Henning Kamp }; 7662efba6aSPoul-Henning Kamp 7762efba6aSPoul-Henning Kamp static struct timehands *volatile timehands = &th0; 7862efba6aSPoul-Henning Kamp struct timecounter *timecounter = &dummy_timecounter; 7962efba6aSPoul-Henning Kamp static struct timecounter *timecounters = &dummy_timecounter; 803bac064fSPoul-Henning Kamp 8148e5da55SPoul-Henning Kamp time_t time_second = 1; 8238b0884cSPoul-Henning Kamp time_t time_uptime = 0; 83227ee8a1SPoul-Henning Kamp 8439acc78aSPoul-Henning Kamp static struct bintime boottimebin; 8537d38777SBruce Evans struct timeval boottime; 8637d38777SBruce Evans SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD, 8737d38777SBruce Evans &boottime, timeval, "System boottime"); 8837d38777SBruce Evans 8991266b96SPoul-Henning Kamp SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); 9091266b96SPoul-Henning Kamp 91056abcabSPoul-Henning Kamp #define TC_STATS(foo) \ 926b00cf46SPoul-Henning Kamp static u_int foo; \ 934f8cb019SMark Murray SYSCTL_UINT(_kern_timecounter, OID_AUTO, foo, CTLFLAG_RD, &foo, 0, "");\ 9439acc78aSPoul-Henning Kamp struct __hack 95056abcabSPoul-Henning Kamp 96056abcabSPoul-Henning Kamp TC_STATS(nbinuptime); TC_STATS(nnanouptime); TC_STATS(nmicrouptime); 97056abcabSPoul-Henning Kamp TC_STATS(nbintime); TC_STATS(nnanotime); TC_STATS(nmicrotime); 98056abcabSPoul-Henning Kamp TC_STATS(ngetbinuptime); TC_STATS(ngetnanouptime); TC_STATS(ngetmicrouptime); 99056abcabSPoul-Henning Kamp TC_STATS(ngetbintime); TC_STATS(ngetnanotime); TC_STATS(ngetmicrotime); 1004394f476SPoul-Henning Kamp TC_STATS(nsetclock); 101056abcabSPoul-Henning Kamp 102056abcabSPoul-Henning Kamp #undef TC_STATS 103510eb5b9SPoul-Henning Kamp 1049e1b5510SPoul-Henning Kamp static void tc_windup(void); 1059e1b5510SPoul-Henning Kamp 10639acc78aSPoul-Henning Kamp /* 10739acc78aSPoul-Henning Kamp * Return the difference between the timehands' counter value now and what 10839acc78aSPoul-Henning Kamp * was when we copied it to the timehands' offset_count. 10939acc78aSPoul-Henning Kamp */ 1106b00cf46SPoul-Henning Kamp static __inline u_int 1116b00cf46SPoul-Henning Kamp tc_delta(struct timehands *th) 112e796e00dSPoul-Henning Kamp { 1136b00cf46SPoul-Henning Kamp struct timecounter *tc; 114e796e00dSPoul-Henning Kamp 1156b00cf46SPoul-Henning Kamp tc = th->th_counter; 1166b00cf46SPoul-Henning Kamp return ((tc->tc_get_timecount(tc) - th->th_offset_count) & 1176b00cf46SPoul-Henning Kamp tc->tc_counter_mask); 118e796e00dSPoul-Henning Kamp } 119a0502b19SPoul-Henning Kamp 12039acc78aSPoul-Henning Kamp /* 1216b00cf46SPoul-Henning Kamp * Functions for reading the time. We have to loop until we are sure that 12239acc78aSPoul-Henning Kamp * the timehands that we operated on was not updated under our feet. See 12339acc78aSPoul-Henning Kamp * the comment in <sys/time.h> for a description of these 12 functions. 1246b00cf46SPoul-Henning Kamp */ 1256b00cf46SPoul-Henning Kamp 126a0502b19SPoul-Henning Kamp void 1272028c0cdSPoul-Henning Kamp binuptime(struct bintime *bt) 1282028c0cdSPoul-Henning Kamp { 1296b00cf46SPoul-Henning Kamp struct timehands *th; 1306b00cf46SPoul-Henning Kamp u_int gen; 1312028c0cdSPoul-Henning Kamp 1325b7d8efaSPoul-Henning Kamp nbinuptime++; 1335b7d8efaSPoul-Henning Kamp do { 1346b00cf46SPoul-Henning Kamp th = timehands; 1356b00cf46SPoul-Henning Kamp gen = th->th_generation; 1366b00cf46SPoul-Henning Kamp *bt = th->th_offset; 1376b00cf46SPoul-Henning Kamp bintime_addx(bt, th->th_scale * tc_delta(th)); 1386b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 1392028c0cdSPoul-Henning Kamp } 1402028c0cdSPoul-Henning Kamp 1412028c0cdSPoul-Henning Kamp void 14239acc78aSPoul-Henning Kamp nanouptime(struct timespec *tsp) 143056abcabSPoul-Henning Kamp { 144056abcabSPoul-Henning Kamp struct bintime bt; 145056abcabSPoul-Henning Kamp 146056abcabSPoul-Henning Kamp nnanouptime++; 147056abcabSPoul-Henning Kamp binuptime(&bt); 14839acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 149056abcabSPoul-Henning Kamp } 150056abcabSPoul-Henning Kamp 151056abcabSPoul-Henning Kamp void 15239acc78aSPoul-Henning Kamp microuptime(struct timeval *tvp) 153056abcabSPoul-Henning Kamp { 154056abcabSPoul-Henning Kamp struct bintime bt; 155056abcabSPoul-Henning Kamp 156056abcabSPoul-Henning Kamp nmicrouptime++; 157056abcabSPoul-Henning Kamp binuptime(&bt); 15839acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 159056abcabSPoul-Henning Kamp } 160056abcabSPoul-Henning Kamp 161056abcabSPoul-Henning Kamp void 1622028c0cdSPoul-Henning Kamp bintime(struct bintime *bt) 1632028c0cdSPoul-Henning Kamp { 1642028c0cdSPoul-Henning Kamp 1655b7d8efaSPoul-Henning Kamp nbintime++; 1662028c0cdSPoul-Henning Kamp binuptime(bt); 1672028c0cdSPoul-Henning Kamp bintime_add(bt, &boottimebin); 1682028c0cdSPoul-Henning Kamp } 1692028c0cdSPoul-Henning Kamp 1702028c0cdSPoul-Henning Kamp void 17139acc78aSPoul-Henning Kamp nanotime(struct timespec *tsp) 17200af9731SPoul-Henning Kamp { 1732028c0cdSPoul-Henning Kamp struct bintime bt; 17400af9731SPoul-Henning Kamp 17591266b96SPoul-Henning Kamp nnanotime++; 1762028c0cdSPoul-Henning Kamp bintime(&bt); 17739acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 17848115288SPoul-Henning Kamp } 17948115288SPoul-Henning Kamp 18048115288SPoul-Henning Kamp void 18139acc78aSPoul-Henning Kamp microtime(struct timeval *tvp) 182056abcabSPoul-Henning Kamp { 183056abcabSPoul-Henning Kamp struct bintime bt; 184056abcabSPoul-Henning Kamp 185056abcabSPoul-Henning Kamp nmicrotime++; 186056abcabSPoul-Henning Kamp bintime(&bt); 18739acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 188056abcabSPoul-Henning Kamp } 189056abcabSPoul-Henning Kamp 190056abcabSPoul-Henning Kamp void 191056abcabSPoul-Henning Kamp getbinuptime(struct bintime *bt) 19200af9731SPoul-Henning Kamp { 1936b00cf46SPoul-Henning Kamp struct timehands *th; 1946b00cf46SPoul-Henning Kamp u_int gen; 19500af9731SPoul-Henning Kamp 196056abcabSPoul-Henning Kamp ngetbinuptime++; 1975b7d8efaSPoul-Henning Kamp do { 1986b00cf46SPoul-Henning Kamp th = timehands; 1996b00cf46SPoul-Henning Kamp gen = th->th_generation; 2006b00cf46SPoul-Henning Kamp *bt = th->th_offset; 2016b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 202a0502b19SPoul-Henning Kamp } 203a0502b19SPoul-Henning Kamp 204a0502b19SPoul-Henning Kamp void 205c21410e1SPoul-Henning Kamp getnanouptime(struct timespec *tsp) 206a0502b19SPoul-Henning Kamp { 2076b00cf46SPoul-Henning Kamp struct timehands *th; 2086b00cf46SPoul-Henning Kamp u_int gen; 209a0502b19SPoul-Henning Kamp 21091266b96SPoul-Henning Kamp ngetnanouptime++; 2115b7d8efaSPoul-Henning Kamp do { 2126b00cf46SPoul-Henning Kamp th = timehands; 2136b00cf46SPoul-Henning Kamp gen = th->th_generation; 2146b00cf46SPoul-Henning Kamp bintime2timespec(&th->th_offset, tsp); 2156b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 216a0502b19SPoul-Henning Kamp } 217a0502b19SPoul-Henning Kamp 218c7c9a816SPoul-Henning Kamp void 219056abcabSPoul-Henning Kamp getmicrouptime(struct timeval *tvp) 220c7c9a816SPoul-Henning Kamp { 2216b00cf46SPoul-Henning Kamp struct timehands *th; 2226b00cf46SPoul-Henning Kamp u_int gen; 2237ec73f64SPoul-Henning Kamp 224056abcabSPoul-Henning Kamp ngetmicrouptime++; 225056abcabSPoul-Henning Kamp do { 2266b00cf46SPoul-Henning Kamp th = timehands; 2276b00cf46SPoul-Henning Kamp gen = th->th_generation; 2286b00cf46SPoul-Henning Kamp bintime2timeval(&th->th_offset, tvp); 2296b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 2307ec73f64SPoul-Henning Kamp } 2317ec73f64SPoul-Henning Kamp 2327ec73f64SPoul-Henning Kamp void 233056abcabSPoul-Henning Kamp getbintime(struct bintime *bt) 2347ec73f64SPoul-Henning Kamp { 2356b00cf46SPoul-Henning Kamp struct timehands *th; 2366b00cf46SPoul-Henning Kamp u_int gen; 2377ec73f64SPoul-Henning Kamp 238056abcabSPoul-Henning Kamp ngetbintime++; 239056abcabSPoul-Henning Kamp do { 2406b00cf46SPoul-Henning Kamp th = timehands; 2416b00cf46SPoul-Henning Kamp gen = th->th_generation; 2426b00cf46SPoul-Henning Kamp *bt = th->th_offset; 2436b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 244056abcabSPoul-Henning Kamp bintime_add(bt, &boottimebin); 245056abcabSPoul-Henning Kamp } 246056abcabSPoul-Henning Kamp 247056abcabSPoul-Henning Kamp void 248056abcabSPoul-Henning Kamp getnanotime(struct timespec *tsp) 249056abcabSPoul-Henning Kamp { 2506b00cf46SPoul-Henning Kamp struct timehands *th; 2516b00cf46SPoul-Henning Kamp u_int gen; 252056abcabSPoul-Henning Kamp 253056abcabSPoul-Henning Kamp ngetnanotime++; 254056abcabSPoul-Henning Kamp do { 2556b00cf46SPoul-Henning Kamp th = timehands; 2566b00cf46SPoul-Henning Kamp gen = th->th_generation; 2576b00cf46SPoul-Henning Kamp *tsp = th->th_nanotime; 2586b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 259056abcabSPoul-Henning Kamp } 260056abcabSPoul-Henning Kamp 261056abcabSPoul-Henning Kamp void 262056abcabSPoul-Henning Kamp getmicrotime(struct timeval *tvp) 263056abcabSPoul-Henning Kamp { 2646b00cf46SPoul-Henning Kamp struct timehands *th; 2656b00cf46SPoul-Henning Kamp u_int gen; 266056abcabSPoul-Henning Kamp 267056abcabSPoul-Henning Kamp ngetmicrotime++; 268056abcabSPoul-Henning Kamp do { 2696b00cf46SPoul-Henning Kamp th = timehands; 2706b00cf46SPoul-Henning Kamp gen = th->th_generation; 2716b00cf46SPoul-Henning Kamp *tvp = th->th_microtime; 2726b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 2737ec73f64SPoul-Henning Kamp } 2747ec73f64SPoul-Henning Kamp 27539acc78aSPoul-Henning Kamp /* 2766b00cf46SPoul-Henning Kamp * Initialize a new timecounter. 2776b00cf46SPoul-Henning Kamp * We should really try to rank the timecounters and intelligently determine 2786b00cf46SPoul-Henning Kamp * if the new timecounter is better than the current one. This is subject 2796b00cf46SPoul-Henning Kamp * to further study. For now always use the new timecounter. 2804e2befc0SPoul-Henning Kamp */ 2817ec73f64SPoul-Henning Kamp void 28291266b96SPoul-Henning Kamp tc_init(struct timecounter *tc) 2837ec73f64SPoul-Henning Kamp { 284e46eeb89SPoul-Henning Kamp unsigned u; 2857ec73f64SPoul-Henning Kamp 28660ca3996SPoul-Henning Kamp printf("Timecounter \"%s\" frequency %ju Hz", 28760ca3996SPoul-Henning Kamp tc->tc_name, (intmax_t)tc->tc_frequency); 288e46eeb89SPoul-Henning Kamp 289e46eeb89SPoul-Henning Kamp u = tc->tc_frequency / tc->tc_counter_mask; 290e46eeb89SPoul-Henning Kamp if (u > hz) { 291e46eeb89SPoul-Henning Kamp printf(" -- Insufficient hz, needs at least %u\n", u); 292e46eeb89SPoul-Henning Kamp return; 293e46eeb89SPoul-Henning Kamp } 29462efba6aSPoul-Henning Kamp tc->tc_next = timecounters; 29562efba6aSPoul-Henning Kamp timecounters = tc; 296e46eeb89SPoul-Henning Kamp printf("\n"); 29739acc78aSPoul-Henning Kamp (void)tc->tc_get_timecount(tc); 29839acc78aSPoul-Henning Kamp (void)tc->tc_get_timecount(tc); 2997ec73f64SPoul-Henning Kamp timecounter = tc; 30062efba6aSPoul-Henning Kamp } 30162efba6aSPoul-Henning Kamp 30239acc78aSPoul-Henning Kamp /* Report the frequency of the current timecounter. */ 30360ca3996SPoul-Henning Kamp u_int64_t 30462efba6aSPoul-Henning Kamp tc_getfrequency(void) 30562efba6aSPoul-Henning Kamp { 30662efba6aSPoul-Henning Kamp 3076b00cf46SPoul-Henning Kamp return (timehands->th_counter->tc_frequency); 3087ec73f64SPoul-Henning Kamp } 3097ec73f64SPoul-Henning Kamp 31039acc78aSPoul-Henning Kamp /* 3116b00cf46SPoul-Henning Kamp * Step our concept of GMT. This is done by modifying our estimate of 3126b00cf46SPoul-Henning Kamp * when we booted. XXX: needs futher work. 3136b00cf46SPoul-Henning Kamp */ 3147ec73f64SPoul-Henning Kamp void 31591266b96SPoul-Henning Kamp tc_setclock(struct timespec *ts) 3167ec73f64SPoul-Henning Kamp { 31700af9731SPoul-Henning Kamp struct timespec ts2; 3187ec73f64SPoul-Henning Kamp 3194394f476SPoul-Henning Kamp nsetclock++; 320c21410e1SPoul-Henning Kamp nanouptime(&ts2); 32100af9731SPoul-Henning Kamp boottime.tv_sec = ts->tv_sec - ts2.tv_sec; 32239acc78aSPoul-Henning Kamp /* XXX boottime should probably be a timespec. */ 32300af9731SPoul-Henning Kamp boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000; 32400af9731SPoul-Henning Kamp if (boottime.tv_usec < 0) { 32500af9731SPoul-Henning Kamp boottime.tv_usec += 1000000; 32600af9731SPoul-Henning Kamp boottime.tv_sec--; 32700af9731SPoul-Henning Kamp } 3282028c0cdSPoul-Henning Kamp timeval2bintime(&boottime, &boottimebin); 32939acc78aSPoul-Henning Kamp 33039acc78aSPoul-Henning Kamp /* XXX fiddle all the little crinkly bits around the fiords... */ 33191266b96SPoul-Henning Kamp tc_windup(); 3327ec73f64SPoul-Henning Kamp } 3337ec73f64SPoul-Henning Kamp 33439acc78aSPoul-Henning Kamp /* 33539acc78aSPoul-Henning Kamp * Initialize the next struct timehands in the ring and make 3366b00cf46SPoul-Henning Kamp * it the active timehands. Along the way we might switch to a different 3376b00cf46SPoul-Henning Kamp * timecounter and/or do seconds processing in NTP. Slightly magic. 3386b00cf46SPoul-Henning Kamp */ 3399e1b5510SPoul-Henning Kamp static void 34091266b96SPoul-Henning Kamp tc_windup(void) 3417ec73f64SPoul-Henning Kamp { 3422028c0cdSPoul-Henning Kamp struct bintime bt; 34339acc78aSPoul-Henning Kamp struct timehands *th, *tho; 3446b00cf46SPoul-Henning Kamp u_int64_t scale; 34539acc78aSPoul-Henning Kamp u_int delta, ncount, ogen; 34639acc78aSPoul-Henning Kamp int i; 3477ec73f64SPoul-Henning Kamp 34839acc78aSPoul-Henning Kamp /* 3496b00cf46SPoul-Henning Kamp * Make the next timehands a copy of the current one, but do not 3506b00cf46SPoul-Henning Kamp * overwrite the generation or next pointer. While we update 3516b00cf46SPoul-Henning Kamp * the contents, the generation must be zero. 3526b00cf46SPoul-Henning Kamp */ 3536b00cf46SPoul-Henning Kamp tho = timehands; 3546b00cf46SPoul-Henning Kamp th = tho->th_next; 3556b00cf46SPoul-Henning Kamp ogen = th->th_generation; 3566b00cf46SPoul-Henning Kamp th->th_generation = 0; 35739acc78aSPoul-Henning Kamp bcopy(tho, th, offsetof(struct timehands, th_generation)); 3586b00cf46SPoul-Henning Kamp 35939acc78aSPoul-Henning Kamp /* 3606b00cf46SPoul-Henning Kamp * Capture a timecounter delta on the current timecounter and if 3616b00cf46SPoul-Henning Kamp * changing timecounters, a counter value from the new timecounter. 3626b00cf46SPoul-Henning Kamp * Update the offset fields accordingly. 3636b00cf46SPoul-Henning Kamp */ 3646b00cf46SPoul-Henning Kamp delta = tc_delta(th); 3656b00cf46SPoul-Henning Kamp if (th->th_counter != timecounter) 3666b00cf46SPoul-Henning Kamp ncount = timecounter->tc_get_timecount(timecounter); 36739acc78aSPoul-Henning Kamp else 36839acc78aSPoul-Henning Kamp ncount = 0; 3696b00cf46SPoul-Henning Kamp th->th_offset_count += delta; 3706b00cf46SPoul-Henning Kamp th->th_offset_count &= th->th_counter->tc_counter_mask; 3716b00cf46SPoul-Henning Kamp bintime_addx(&th->th_offset, th->th_scale * delta); 3726b00cf46SPoul-Henning Kamp 37339acc78aSPoul-Henning Kamp /* 3746b00cf46SPoul-Henning Kamp * Hardware latching timecounters may not generate interrupts on 3756b00cf46SPoul-Henning Kamp * PPS events, so instead we poll them. There is a finite risk that 3766b00cf46SPoul-Henning Kamp * the hardware might capture a count which is later than the one we 3776b00cf46SPoul-Henning Kamp * got above, and therefore possibly in the next NTP second which might 3786b00cf46SPoul-Henning Kamp * have a different rate than the current NTP second. It doesn't 3796b00cf46SPoul-Henning Kamp * matter in practice. 3806b00cf46SPoul-Henning Kamp */ 3816b00cf46SPoul-Henning Kamp if (tho->th_counter->tc_poll_pps) 3826b00cf46SPoul-Henning Kamp tho->th_counter->tc_poll_pps(tho->th_counter); 3836b00cf46SPoul-Henning Kamp 38439acc78aSPoul-Henning Kamp /* 38539acc78aSPoul-Henning Kamp * Deal with NTP second processing. The for loop normally only 38639acc78aSPoul-Henning Kamp * iterates once, but in extreme situations it might keep NTP sane 38739acc78aSPoul-Henning Kamp * if timeouts are not run for several seconds. 3886b00cf46SPoul-Henning Kamp */ 3896b00cf46SPoul-Henning Kamp for (i = th->th_offset.sec - tho->th_offset.sec; i > 0; i--) 3906b00cf46SPoul-Henning Kamp ntp_update_second(&th->th_adjustment, &th->th_offset.sec); 3916b00cf46SPoul-Henning Kamp 3926b00cf46SPoul-Henning Kamp /* Now is a good time to change timecounters. */ 3936b00cf46SPoul-Henning Kamp if (th->th_counter != timecounter) { 3946b00cf46SPoul-Henning Kamp th->th_counter = timecounter; 3956b00cf46SPoul-Henning Kamp th->th_offset_count = ncount; 3967ec73f64SPoul-Henning Kamp } 3977ec73f64SPoul-Henning Kamp 39848e5da55SPoul-Henning Kamp /*- 3996b00cf46SPoul-Henning Kamp * Recalculate the scaling factor. We want the number of 1/2^64 4006b00cf46SPoul-Henning Kamp * fractions of a second per period of the hardware counter, taking 4016b00cf46SPoul-Henning Kamp * into account the th_adjustment factor which the NTP PLL/adjtime(2) 4026b00cf46SPoul-Henning Kamp * processing provides us with. 4036b00cf46SPoul-Henning Kamp * 4046b00cf46SPoul-Henning Kamp * The th_adjustment is nanoseconds per second with 32 bit binary 4056b00cf46SPoul-Henning Kamp * fraction and want 64 bit binary fraction of second: 4066b00cf46SPoul-Henning Kamp * 4076b00cf46SPoul-Henning Kamp * x = a * 2^32 / 10^9 = a * 4.294967296 4086b00cf46SPoul-Henning Kamp * 4096b00cf46SPoul-Henning Kamp * The range of th_adjustment is +/- 5000PPM so inside a 64bit int 4106b00cf46SPoul-Henning Kamp * we can only multiply by about 850 without overflowing, but that 4116b00cf46SPoul-Henning Kamp * leaves suitably precise fractions for multiply before divide. 4126b00cf46SPoul-Henning Kamp * 4136b00cf46SPoul-Henning Kamp * Divide before multiply with a fraction of 2199/512 results in a 4146b00cf46SPoul-Henning Kamp * systematic undercompensation of 10PPM of th_adjustment. On a 4156b00cf46SPoul-Henning Kamp * 5000PPM adjustment this is a 0.05PPM error. This is acceptable. 4166b00cf46SPoul-Henning Kamp * 4176b00cf46SPoul-Henning Kamp * We happily sacrifice the lowest of the 64 bits of our result 4186b00cf46SPoul-Henning Kamp * to the goddess of code clarity. 41939acc78aSPoul-Henning Kamp * 4206b00cf46SPoul-Henning Kamp */ 42139acc78aSPoul-Henning Kamp scale = (u_int64_t)1 << 63; 4226b00cf46SPoul-Henning Kamp scale += (th->th_adjustment / 1024) * 2199; 4236b00cf46SPoul-Henning Kamp scale /= th->th_counter->tc_frequency; 4246b00cf46SPoul-Henning Kamp th->th_scale = scale * 2; 4256b00cf46SPoul-Henning Kamp 4266b00cf46SPoul-Henning Kamp /* Update the GMT timestamps used for the get*() functions. */ 4276b00cf46SPoul-Henning Kamp bt = th->th_offset; 4286b00cf46SPoul-Henning Kamp bintime_add(&bt, &boottimebin); 4296b00cf46SPoul-Henning Kamp bintime2timeval(&bt, &th->th_microtime); 4306b00cf46SPoul-Henning Kamp bintime2timespec(&bt, &th->th_nanotime); 4316b00cf46SPoul-Henning Kamp 43239acc78aSPoul-Henning Kamp /* 43339acc78aSPoul-Henning Kamp * Now that the struct timehands is again consistent, set the new 4346b00cf46SPoul-Henning Kamp * generation number, making sure to not make it zero. 4356b00cf46SPoul-Henning Kamp */ 4366b00cf46SPoul-Henning Kamp if (++ogen == 0) 43739acc78aSPoul-Henning Kamp ogen = 1; 4386b00cf46SPoul-Henning Kamp th->th_generation = ogen; 4396b00cf46SPoul-Henning Kamp 44039acc78aSPoul-Henning Kamp /* Go live with the new struct timehands. */ 4416b00cf46SPoul-Henning Kamp time_second = th->th_microtime.tv_sec; 44238b0884cSPoul-Henning Kamp time_uptime = th->th_offset.sec; 4436b00cf46SPoul-Henning Kamp timehands = th; 4446b00cf46SPoul-Henning Kamp } 4456b00cf46SPoul-Henning Kamp 44639acc78aSPoul-Henning Kamp /* Report or change the active timecounter hardware. */ 4476b6ef746SBruce Evans static int 44882d9ae4eSPoul-Henning Kamp sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) 4496b6ef746SBruce Evans { 4506b6ef746SBruce Evans char newname[32]; 4516b6ef746SBruce Evans struct timecounter *newtc, *tc; 4526b6ef746SBruce Evans int error; 4536b6ef746SBruce Evans 45462efba6aSPoul-Henning Kamp tc = timecounter; 455e80fb434SRobert Drehmel strlcpy(newname, tc->tc_name, sizeof(newname)); 456e80fb434SRobert Drehmel 4576b6ef746SBruce Evans error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); 45839acc78aSPoul-Henning Kamp if (error != 0 || req->newptr == NULL || 45939acc78aSPoul-Henning Kamp strcmp(newname, tc->tc_name) == 0) 46062efba6aSPoul-Henning Kamp return (error); 46162efba6aSPoul-Henning Kamp for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) { 46239acc78aSPoul-Henning Kamp if (strcmp(newname, newtc->tc_name) != 0) 46362efba6aSPoul-Henning Kamp continue; 46439acc78aSPoul-Henning Kamp 4656b6ef746SBruce Evans /* Warm up new timecounter. */ 4666b6ef746SBruce Evans (void)newtc->tc_get_timecount(newtc); 46762efba6aSPoul-Henning Kamp (void)newtc->tc_get_timecount(newtc); 46839acc78aSPoul-Henning Kamp 46962efba6aSPoul-Henning Kamp timecounter = newtc; 4706b6ef746SBruce Evans return (0); 4716b6ef746SBruce Evans } 4726b6ef746SBruce Evans return (EINVAL); 4736b6ef746SBruce Evans } 4746b6ef746SBruce Evans 4756b6ef746SBruce Evans SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, 4766b6ef746SBruce Evans 0, 0, sysctl_kern_timecounter_hardware, "A", ""); 4776b6ef746SBruce Evans 47839acc78aSPoul-Henning Kamp /* 4796b00cf46SPoul-Henning Kamp * RFC 2783 PPS-API implementation. 4806b00cf46SPoul-Henning Kamp */ 4817ec73f64SPoul-Henning Kamp 48232c20357SPoul-Henning Kamp int 48332c20357SPoul-Henning Kamp pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) 48432c20357SPoul-Henning Kamp { 48532c20357SPoul-Henning Kamp pps_params_t *app; 486b7424f2dSJohn Hay struct pps_fetch_args *fapi; 487de3f8889SPeter Wemm #ifdef PPS_SYNC 488b7424f2dSJohn Hay struct pps_kcbind_args *kapi; 489de3f8889SPeter Wemm #endif 49032c20357SPoul-Henning Kamp 49132c20357SPoul-Henning Kamp switch (cmd) { 49232c20357SPoul-Henning Kamp case PPS_IOC_CREATE: 49332c20357SPoul-Henning Kamp return (0); 49432c20357SPoul-Henning Kamp case PPS_IOC_DESTROY: 49532c20357SPoul-Henning Kamp return (0); 49632c20357SPoul-Henning Kamp case PPS_IOC_SETPARAMS: 49732c20357SPoul-Henning Kamp app = (pps_params_t *)data; 49832c20357SPoul-Henning Kamp if (app->mode & ~pps->ppscap) 49932c20357SPoul-Henning Kamp return (EINVAL); 50032c20357SPoul-Henning Kamp pps->ppsparam = *app; 50132c20357SPoul-Henning Kamp return (0); 50232c20357SPoul-Henning Kamp case PPS_IOC_GETPARAMS: 50332c20357SPoul-Henning Kamp app = (pps_params_t *)data; 50432c20357SPoul-Henning Kamp *app = pps->ppsparam; 505b7424f2dSJohn Hay app->api_version = PPS_API_VERS_1; 50632c20357SPoul-Henning Kamp return (0); 50732c20357SPoul-Henning Kamp case PPS_IOC_GETCAP: 50832c20357SPoul-Henning Kamp *(int*)data = pps->ppscap; 50932c20357SPoul-Henning Kamp return (0); 51032c20357SPoul-Henning Kamp case PPS_IOC_FETCH: 511b7424f2dSJohn Hay fapi = (struct pps_fetch_args *)data; 512b7424f2dSJohn Hay if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) 513b7424f2dSJohn Hay return (EINVAL); 514b7424f2dSJohn Hay if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) 51532c20357SPoul-Henning Kamp return (EOPNOTSUPP); 516b7424f2dSJohn Hay pps->ppsinfo.current_mode = pps->ppsparam.mode; 517b7424f2dSJohn Hay fapi->pps_info_buf = pps->ppsinfo; 518b7424f2dSJohn Hay return (0); 519b7424f2dSJohn Hay case PPS_IOC_KCBIND: 520b7424f2dSJohn Hay #ifdef PPS_SYNC 521b7424f2dSJohn Hay kapi = (struct pps_kcbind_args *)data; 522b7424f2dSJohn Hay /* XXX Only root should be able to do this */ 523b7424f2dSJohn Hay if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC) 524b7424f2dSJohn Hay return (EINVAL); 525b7424f2dSJohn Hay if (kapi->kernel_consumer != PPS_KC_HARDPPS) 526b7424f2dSJohn Hay return (EINVAL); 527b7424f2dSJohn Hay if (kapi->edge & ~pps->ppscap) 528b7424f2dSJohn Hay return (EINVAL); 529b7424f2dSJohn Hay pps->kcmode = kapi->edge; 530b7424f2dSJohn Hay return (0); 531b7424f2dSJohn Hay #else 532b7424f2dSJohn Hay return (EOPNOTSUPP); 533b7424f2dSJohn Hay #endif 53432c20357SPoul-Henning Kamp default: 53532c20357SPoul-Henning Kamp return (ENOTTY); 53632c20357SPoul-Henning Kamp } 53732c20357SPoul-Henning Kamp } 53832c20357SPoul-Henning Kamp 53932c20357SPoul-Henning Kamp void 54032c20357SPoul-Henning Kamp pps_init(struct pps_state *pps) 54132c20357SPoul-Henning Kamp { 54232c20357SPoul-Henning Kamp pps->ppscap |= PPS_TSFMT_TSPEC; 54332c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTUREASSERT) 54432c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETASSERT; 54532c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTURECLEAR) 54632c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETCLEAR; 54732c20357SPoul-Henning Kamp } 54832c20357SPoul-Henning Kamp 54932c20357SPoul-Henning Kamp void 5507bf758bfSPoul-Henning Kamp pps_capture(struct pps_state *pps) 5517bf758bfSPoul-Henning Kamp { 5526b00cf46SPoul-Henning Kamp struct timehands *th; 5537bf758bfSPoul-Henning Kamp 5546b00cf46SPoul-Henning Kamp th = timehands; 5556b00cf46SPoul-Henning Kamp pps->capgen = th->th_generation; 5566b00cf46SPoul-Henning Kamp pps->capth = th; 5576b00cf46SPoul-Henning Kamp pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); 5586b00cf46SPoul-Henning Kamp if (pps->capgen != th->th_generation) 5596b00cf46SPoul-Henning Kamp pps->capgen = 0; 5607bf758bfSPoul-Henning Kamp } 5617bf758bfSPoul-Henning Kamp 5627bf758bfSPoul-Henning Kamp void 5637bf758bfSPoul-Henning Kamp pps_event(struct pps_state *pps, int event) 56432c20357SPoul-Henning Kamp { 56539acc78aSPoul-Henning Kamp struct bintime bt; 56632c20357SPoul-Henning Kamp struct timespec ts, *tsp, *osp; 5676b00cf46SPoul-Henning Kamp u_int tcount, *pcount; 56832c20357SPoul-Henning Kamp int foff, fhard; 56932c20357SPoul-Henning Kamp pps_seq_t *pseq; 57032c20357SPoul-Henning Kamp 57139acc78aSPoul-Henning Kamp /* If the timecounter was wound up underneath us, bail out. */ 57239acc78aSPoul-Henning Kamp if (pps->capgen == 0 || pps->capgen != pps->capth->th_generation) 5737bf758bfSPoul-Henning Kamp return; 5747bf758bfSPoul-Henning Kamp 57539acc78aSPoul-Henning Kamp /* Things would be easier with arrays. */ 57632c20357SPoul-Henning Kamp if (event == PPS_CAPTUREASSERT) { 57732c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.assert_timestamp; 57832c20357SPoul-Henning Kamp osp = &pps->ppsparam.assert_offset; 57932c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETASSERT; 580b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTUREASSERT; 58132c20357SPoul-Henning Kamp pcount = &pps->ppscount[0]; 58232c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.assert_sequence; 58332c20357SPoul-Henning Kamp } else { 58432c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.clear_timestamp; 58532c20357SPoul-Henning Kamp osp = &pps->ppsparam.clear_offset; 58632c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; 587b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTURECLEAR; 58832c20357SPoul-Henning Kamp pcount = &pps->ppscount[1]; 58932c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.clear_sequence; 59032c20357SPoul-Henning Kamp } 59132c20357SPoul-Henning Kamp 59239acc78aSPoul-Henning Kamp /* 5936b00cf46SPoul-Henning Kamp * If the timecounter changed, we cannot compare the count values, so 5946b00cf46SPoul-Henning Kamp * we have to drop the rest of the PPS-stuff until the next event. 5956b00cf46SPoul-Henning Kamp */ 5966b00cf46SPoul-Henning Kamp if (pps->ppstc != pps->capth->th_counter) { 5976b00cf46SPoul-Henning Kamp pps->ppstc = pps->capth->th_counter; 5987bf758bfSPoul-Henning Kamp *pcount = pps->capcount; 5997bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 60032c20357SPoul-Henning Kamp return; 60132c20357SPoul-Henning Kamp } 60232c20357SPoul-Henning Kamp 60339acc78aSPoul-Henning Kamp /* Return if nothing really happened. */ 6047bf758bfSPoul-Henning Kamp if (*pcount == pps->capcount) 60532c20357SPoul-Henning Kamp return; 60632c20357SPoul-Henning Kamp 60739acc78aSPoul-Henning Kamp /* Convert the count to a timespec. */ 6086b00cf46SPoul-Henning Kamp tcount = pps->capcount - pps->capth->th_offset_count; 6096b00cf46SPoul-Henning Kamp tcount &= pps->capth->th_counter->tc_counter_mask; 6106b00cf46SPoul-Henning Kamp bt = pps->capth->th_offset; 6116b00cf46SPoul-Henning Kamp bintime_addx(&bt, pps->capth->th_scale * tcount); 612eef633a7SPoul-Henning Kamp bintime_add(&bt, &boottimebin); 6132028c0cdSPoul-Henning Kamp bintime2timespec(&bt, &ts); 61432c20357SPoul-Henning Kamp 61539acc78aSPoul-Henning Kamp /* If the timecounter was wound up underneath us, bail out. */ 6166b00cf46SPoul-Henning Kamp if (pps->capgen != pps->capth->th_generation) 6177bf758bfSPoul-Henning Kamp return; 6187bf758bfSPoul-Henning Kamp 6197bf758bfSPoul-Henning Kamp *pcount = pps->capcount; 62032c20357SPoul-Henning Kamp (*pseq)++; 62132c20357SPoul-Henning Kamp *tsp = ts; 62232c20357SPoul-Henning Kamp 62332c20357SPoul-Henning Kamp if (foff) { 62432c20357SPoul-Henning Kamp timespecadd(tsp, osp); 62532c20357SPoul-Henning Kamp if (tsp->tv_nsec < 0) { 62632c20357SPoul-Henning Kamp tsp->tv_nsec += 1000000000; 62732c20357SPoul-Henning Kamp tsp->tv_sec -= 1; 62832c20357SPoul-Henning Kamp } 62932c20357SPoul-Henning Kamp } 63032c20357SPoul-Henning Kamp #ifdef PPS_SYNC 63132c20357SPoul-Henning Kamp if (fhard) { 632ce9fac00SPoul-Henning Kamp u_int64_t scale; 633ce9fac00SPoul-Henning Kamp 63439acc78aSPoul-Henning Kamp /* 6356b00cf46SPoul-Henning Kamp * Feed the NTP PLL/FLL. 636b1e7e201SJohn Hay * The FLL wants to know how many (hardware) nanoseconds 637b1e7e201SJohn Hay * elapsed since the previous event. 6386b00cf46SPoul-Henning Kamp */ 6397bf758bfSPoul-Henning Kamp tcount = pps->capcount - pps->ppscount[2]; 6407bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 6416b00cf46SPoul-Henning Kamp tcount &= pps->capth->th_counter->tc_counter_mask; 642b1e7e201SJohn Hay scale = (u_int64_t)1 << 63; 643b1e7e201SJohn Hay scale /= pps->capth->th_counter->tc_frequency; 644b1e7e201SJohn Hay scale *= 2; 6452028c0cdSPoul-Henning Kamp bt.sec = 0; 6462028c0cdSPoul-Henning Kamp bt.frac = 0; 647b1e7e201SJohn Hay bintime_addx(&bt, scale * tcount); 6482028c0cdSPoul-Henning Kamp bintime2timespec(&bt, &ts); 6492028c0cdSPoul-Henning Kamp hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec); 65032c20357SPoul-Henning Kamp } 65132c20357SPoul-Henning Kamp #endif 65232c20357SPoul-Henning Kamp } 6539e1b5510SPoul-Henning Kamp 65439acc78aSPoul-Henning Kamp /* 6559e1b5510SPoul-Henning Kamp * Timecounters need to be updated every so often to prevent the hardware 6569e1b5510SPoul-Henning Kamp * counter from overflowing. Updating also recalculates the cached values 6579e1b5510SPoul-Henning Kamp * used by the get*() family of functions, so their precision depends on 6589e1b5510SPoul-Henning Kamp * the update frequency. 6599e1b5510SPoul-Henning Kamp */ 6609e1b5510SPoul-Henning Kamp 6619e1b5510SPoul-Henning Kamp static int tc_tick; 662b3ed130cSPoul-Henning Kamp SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, ""); 6639e1b5510SPoul-Henning Kamp 664e7fa55afSPoul-Henning Kamp void 665e7fa55afSPoul-Henning Kamp tc_ticktock(void) 6669e1b5510SPoul-Henning Kamp { 667e7fa55afSPoul-Henning Kamp static int count; 6689e1b5510SPoul-Henning Kamp 669e7fa55afSPoul-Henning Kamp if (++count < tc_tick) 670e7fa55afSPoul-Henning Kamp return; 671e7fa55afSPoul-Henning Kamp count = 0; 6729e1b5510SPoul-Henning Kamp tc_windup(); 6739e1b5510SPoul-Henning Kamp } 6749e1b5510SPoul-Henning Kamp 6759e1b5510SPoul-Henning Kamp static void 6769e1b5510SPoul-Henning Kamp inittimecounter(void *dummy) 6779e1b5510SPoul-Henning Kamp { 6789e1b5510SPoul-Henning Kamp u_int p; 6799e1b5510SPoul-Henning Kamp 68039acc78aSPoul-Henning Kamp /* 68139acc78aSPoul-Henning Kamp * Set the initial timeout to 68239acc78aSPoul-Henning Kamp * max(1, <approx. number of hardclock ticks in a millisecond>). 68339acc78aSPoul-Henning Kamp * People should probably not use the sysctl to set the timeout 68439acc78aSPoul-Henning Kamp * to smaller than its inital value, since that value is the 68539acc78aSPoul-Henning Kamp * smallest reasonable one. If they want better timestamps they 68639acc78aSPoul-Henning Kamp * should use the non-"get"* functions. 68739acc78aSPoul-Henning Kamp */ 6889e1b5510SPoul-Henning Kamp if (hz > 1000) 6899e1b5510SPoul-Henning Kamp tc_tick = (hz + 500) / 1000; 6909e1b5510SPoul-Henning Kamp else 6919e1b5510SPoul-Henning Kamp tc_tick = 1; 6929e1b5510SPoul-Henning Kamp p = (tc_tick * 1000000) / hz; 6939e1b5510SPoul-Henning Kamp printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); 69439acc78aSPoul-Henning Kamp 69548e5da55SPoul-Henning Kamp /* warm up new timecounter (again) and get rolling. */ 69639acc78aSPoul-Henning Kamp (void)timecounter->tc_get_timecount(timecounter); 69739acc78aSPoul-Henning Kamp (void)timecounter->tc_get_timecount(timecounter); 6989e1b5510SPoul-Henning Kamp } 6999e1b5510SPoul-Henning Kamp 700ff292556SPeter Wemm SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL) 701