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> 1591266b96SPoul-Henning Kamp #include <sys/kernel.h> 1691266b96SPoul-Henning Kamp #include <sys/sysctl.h> 1791266b96SPoul-Henning Kamp #include <sys/systm.h> 1832c20357SPoul-Henning Kamp #include <sys/timepps.h> 1948e5da55SPoul-Henning Kamp #include <sys/timetc.h> 2039acc78aSPoul-Henning Kamp #include <sys/timex.h> 2139acc78aSPoul-Henning Kamp 223bac064fSPoul-Henning Kamp /* 2362efba6aSPoul-Henning Kamp * Implement a dummy timecounter which we can use until we get a real one 2462efba6aSPoul-Henning Kamp * in the air. This allows the console and other early stuff to use 2562efba6aSPoul-Henning Kamp * time services. 263bac064fSPoul-Henning Kamp */ 273bac064fSPoul-Henning Kamp 286b00cf46SPoul-Henning Kamp static u_int 2962efba6aSPoul-Henning Kamp dummy_get_timecount(struct timecounter *tc) 3062efba6aSPoul-Henning Kamp { 316b00cf46SPoul-Henning Kamp static u_int now; 3262efba6aSPoul-Henning Kamp 3362efba6aSPoul-Henning Kamp return (++now); 3462efba6aSPoul-Henning Kamp } 3562efba6aSPoul-Henning Kamp 3662efba6aSPoul-Henning Kamp static struct timecounter dummy_timecounter = { 3739acc78aSPoul-Henning Kamp dummy_get_timecount, 0, ~0u, 1000000, "dummy", 3862efba6aSPoul-Henning Kamp }; 3962efba6aSPoul-Henning Kamp 4062efba6aSPoul-Henning Kamp struct timehands { 4162efba6aSPoul-Henning Kamp /* These fields must be initialized by the driver. */ 426b00cf46SPoul-Henning Kamp struct timecounter *th_counter; 436b00cf46SPoul-Henning Kamp int64_t th_adjustment; 446b00cf46SPoul-Henning Kamp u_int64_t th_scale; 456b00cf46SPoul-Henning Kamp u_int th_offset_count; 466b00cf46SPoul-Henning Kamp struct bintime th_offset; 476b00cf46SPoul-Henning Kamp struct timeval th_microtime; 486b00cf46SPoul-Henning Kamp struct timespec th_nanotime; 4939acc78aSPoul-Henning Kamp /* Fields not to be copied in tc_windup start with th_generation. */ 506b00cf46SPoul-Henning Kamp volatile u_int th_generation; 516b00cf46SPoul-Henning Kamp struct timehands *th_next; 5262efba6aSPoul-Henning Kamp }; 5362efba6aSPoul-Henning Kamp 5462efba6aSPoul-Henning Kamp extern struct timehands th0; 5539acc78aSPoul-Henning Kamp static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; 5639acc78aSPoul-Henning Kamp static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; 5739acc78aSPoul-Henning Kamp static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th8}; 5839acc78aSPoul-Henning Kamp static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th7}; 5939acc78aSPoul-Henning Kamp static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th6}; 6039acc78aSPoul-Henning Kamp static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; 6139acc78aSPoul-Henning Kamp static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; 6239acc78aSPoul-Henning Kamp static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; 6339acc78aSPoul-Henning Kamp static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; 64f5d157fbSPoul-Henning Kamp static struct timehands th0 = { 65f5d157fbSPoul-Henning Kamp &dummy_timecounter, 66f5d157fbSPoul-Henning Kamp 0, 6739acc78aSPoul-Henning Kamp (uint64_t)-1 / 1000000, 68f5d157fbSPoul-Henning Kamp 0, 69d25917e8SPoul-Henning Kamp {1, 0}, 70f5d157fbSPoul-Henning Kamp {0, 0}, 71f5d157fbSPoul-Henning Kamp {0, 0}, 72f5d157fbSPoul-Henning Kamp 1, 73f5d157fbSPoul-Henning Kamp &th1 74f5d157fbSPoul-Henning Kamp }; 7562efba6aSPoul-Henning Kamp 7662efba6aSPoul-Henning Kamp static struct timehands *volatile timehands = &th0; 7762efba6aSPoul-Henning Kamp struct timecounter *timecounter = &dummy_timecounter; 7862efba6aSPoul-Henning Kamp static struct timecounter *timecounters = &dummy_timecounter; 793bac064fSPoul-Henning Kamp 8048e5da55SPoul-Henning Kamp time_t time_second = 1; 8138b0884cSPoul-Henning Kamp time_t time_uptime = 0; 82227ee8a1SPoul-Henning Kamp 8339acc78aSPoul-Henning Kamp static struct bintime boottimebin; 8437d38777SBruce Evans struct timeval boottime; 8537d38777SBruce Evans SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD, 8637d38777SBruce Evans &boottime, timeval, "System boottime"); 8737d38777SBruce Evans 8891266b96SPoul-Henning Kamp SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); 8991266b96SPoul-Henning Kamp 90056abcabSPoul-Henning Kamp #define TC_STATS(foo) \ 916b00cf46SPoul-Henning Kamp static u_int foo; \ 924f8cb019SMark Murray SYSCTL_UINT(_kern_timecounter, OID_AUTO, foo, CTLFLAG_RD, &foo, 0, "");\ 9339acc78aSPoul-Henning Kamp struct __hack 94056abcabSPoul-Henning Kamp 95056abcabSPoul-Henning Kamp TC_STATS(nbinuptime); TC_STATS(nnanouptime); TC_STATS(nmicrouptime); 96056abcabSPoul-Henning Kamp TC_STATS(nbintime); TC_STATS(nnanotime); TC_STATS(nmicrotime); 97056abcabSPoul-Henning Kamp TC_STATS(ngetbinuptime); TC_STATS(ngetnanouptime); TC_STATS(ngetmicrouptime); 98056abcabSPoul-Henning Kamp TC_STATS(ngetbintime); TC_STATS(ngetnanotime); TC_STATS(ngetmicrotime); 99056abcabSPoul-Henning Kamp 100056abcabSPoul-Henning Kamp #undef TC_STATS 101510eb5b9SPoul-Henning Kamp 1029e1b5510SPoul-Henning Kamp static void tc_windup(void); 1039e1b5510SPoul-Henning Kamp 10439acc78aSPoul-Henning Kamp /* 10539acc78aSPoul-Henning Kamp * Return the difference between the timehands' counter value now and what 10639acc78aSPoul-Henning Kamp * was when we copied it to the timehands' offset_count. 10739acc78aSPoul-Henning Kamp */ 1086b00cf46SPoul-Henning Kamp static __inline u_int 1096b00cf46SPoul-Henning Kamp tc_delta(struct timehands *th) 110e796e00dSPoul-Henning Kamp { 1116b00cf46SPoul-Henning Kamp struct timecounter *tc; 112e796e00dSPoul-Henning Kamp 1136b00cf46SPoul-Henning Kamp tc = th->th_counter; 1146b00cf46SPoul-Henning Kamp return ((tc->tc_get_timecount(tc) - th->th_offset_count) & 1156b00cf46SPoul-Henning Kamp tc->tc_counter_mask); 116e796e00dSPoul-Henning Kamp } 117a0502b19SPoul-Henning Kamp 11839acc78aSPoul-Henning Kamp /* 1196b00cf46SPoul-Henning Kamp * Functions for reading the time. We have to loop until we are sure that 12039acc78aSPoul-Henning Kamp * the timehands that we operated on was not updated under our feet. See 12139acc78aSPoul-Henning Kamp * the comment in <sys/time.h> for a description of these 12 functions. 1226b00cf46SPoul-Henning Kamp */ 1236b00cf46SPoul-Henning Kamp 124a0502b19SPoul-Henning Kamp void 1252028c0cdSPoul-Henning Kamp binuptime(struct bintime *bt) 1262028c0cdSPoul-Henning Kamp { 1276b00cf46SPoul-Henning Kamp struct timehands *th; 1286b00cf46SPoul-Henning Kamp u_int gen; 1292028c0cdSPoul-Henning Kamp 1305b7d8efaSPoul-Henning Kamp nbinuptime++; 1315b7d8efaSPoul-Henning Kamp do { 1326b00cf46SPoul-Henning Kamp th = timehands; 1336b00cf46SPoul-Henning Kamp gen = th->th_generation; 1346b00cf46SPoul-Henning Kamp *bt = th->th_offset; 1356b00cf46SPoul-Henning Kamp bintime_addx(bt, th->th_scale * tc_delta(th)); 1366b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 1372028c0cdSPoul-Henning Kamp } 1382028c0cdSPoul-Henning Kamp 1392028c0cdSPoul-Henning Kamp void 14039acc78aSPoul-Henning Kamp nanouptime(struct timespec *tsp) 141056abcabSPoul-Henning Kamp { 142056abcabSPoul-Henning Kamp struct bintime bt; 143056abcabSPoul-Henning Kamp 144056abcabSPoul-Henning Kamp nnanouptime++; 145056abcabSPoul-Henning Kamp binuptime(&bt); 14639acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 147056abcabSPoul-Henning Kamp } 148056abcabSPoul-Henning Kamp 149056abcabSPoul-Henning Kamp void 15039acc78aSPoul-Henning Kamp microuptime(struct timeval *tvp) 151056abcabSPoul-Henning Kamp { 152056abcabSPoul-Henning Kamp struct bintime bt; 153056abcabSPoul-Henning Kamp 154056abcabSPoul-Henning Kamp nmicrouptime++; 155056abcabSPoul-Henning Kamp binuptime(&bt); 15639acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 157056abcabSPoul-Henning Kamp } 158056abcabSPoul-Henning Kamp 159056abcabSPoul-Henning Kamp void 1602028c0cdSPoul-Henning Kamp bintime(struct bintime *bt) 1612028c0cdSPoul-Henning Kamp { 1622028c0cdSPoul-Henning Kamp 1635b7d8efaSPoul-Henning Kamp nbintime++; 1642028c0cdSPoul-Henning Kamp binuptime(bt); 1652028c0cdSPoul-Henning Kamp bintime_add(bt, &boottimebin); 1662028c0cdSPoul-Henning Kamp } 1672028c0cdSPoul-Henning Kamp 1682028c0cdSPoul-Henning Kamp void 16939acc78aSPoul-Henning Kamp nanotime(struct timespec *tsp) 17000af9731SPoul-Henning Kamp { 1712028c0cdSPoul-Henning Kamp struct bintime bt; 17200af9731SPoul-Henning Kamp 17391266b96SPoul-Henning Kamp nnanotime++; 1742028c0cdSPoul-Henning Kamp bintime(&bt); 17539acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 17648115288SPoul-Henning Kamp } 17748115288SPoul-Henning Kamp 17848115288SPoul-Henning Kamp void 17939acc78aSPoul-Henning Kamp microtime(struct timeval *tvp) 180056abcabSPoul-Henning Kamp { 181056abcabSPoul-Henning Kamp struct bintime bt; 182056abcabSPoul-Henning Kamp 183056abcabSPoul-Henning Kamp nmicrotime++; 184056abcabSPoul-Henning Kamp bintime(&bt); 18539acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 186056abcabSPoul-Henning Kamp } 187056abcabSPoul-Henning Kamp 188056abcabSPoul-Henning Kamp void 189056abcabSPoul-Henning Kamp getbinuptime(struct bintime *bt) 19000af9731SPoul-Henning Kamp { 1916b00cf46SPoul-Henning Kamp struct timehands *th; 1926b00cf46SPoul-Henning Kamp u_int gen; 19300af9731SPoul-Henning Kamp 194056abcabSPoul-Henning Kamp ngetbinuptime++; 1955b7d8efaSPoul-Henning Kamp do { 1966b00cf46SPoul-Henning Kamp th = timehands; 1976b00cf46SPoul-Henning Kamp gen = th->th_generation; 1986b00cf46SPoul-Henning Kamp *bt = th->th_offset; 1996b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 200a0502b19SPoul-Henning Kamp } 201a0502b19SPoul-Henning Kamp 202a0502b19SPoul-Henning Kamp void 203c21410e1SPoul-Henning Kamp getnanouptime(struct timespec *tsp) 204a0502b19SPoul-Henning Kamp { 2056b00cf46SPoul-Henning Kamp struct timehands *th; 2066b00cf46SPoul-Henning Kamp u_int gen; 207a0502b19SPoul-Henning Kamp 20891266b96SPoul-Henning Kamp ngetnanouptime++; 2095b7d8efaSPoul-Henning Kamp do { 2106b00cf46SPoul-Henning Kamp th = timehands; 2116b00cf46SPoul-Henning Kamp gen = th->th_generation; 2126b00cf46SPoul-Henning Kamp bintime2timespec(&th->th_offset, tsp); 2136b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 214a0502b19SPoul-Henning Kamp } 215a0502b19SPoul-Henning Kamp 216c7c9a816SPoul-Henning Kamp void 217056abcabSPoul-Henning Kamp getmicrouptime(struct timeval *tvp) 218c7c9a816SPoul-Henning Kamp { 2196b00cf46SPoul-Henning Kamp struct timehands *th; 2206b00cf46SPoul-Henning Kamp u_int gen; 2217ec73f64SPoul-Henning Kamp 222056abcabSPoul-Henning Kamp ngetmicrouptime++; 223056abcabSPoul-Henning Kamp do { 2246b00cf46SPoul-Henning Kamp th = timehands; 2256b00cf46SPoul-Henning Kamp gen = th->th_generation; 2266b00cf46SPoul-Henning Kamp bintime2timeval(&th->th_offset, tvp); 2276b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 2287ec73f64SPoul-Henning Kamp } 2297ec73f64SPoul-Henning Kamp 2307ec73f64SPoul-Henning Kamp void 231056abcabSPoul-Henning Kamp getbintime(struct bintime *bt) 2327ec73f64SPoul-Henning Kamp { 2336b00cf46SPoul-Henning Kamp struct timehands *th; 2346b00cf46SPoul-Henning Kamp u_int gen; 2357ec73f64SPoul-Henning Kamp 236056abcabSPoul-Henning Kamp ngetbintime++; 237056abcabSPoul-Henning Kamp do { 2386b00cf46SPoul-Henning Kamp th = timehands; 2396b00cf46SPoul-Henning Kamp gen = th->th_generation; 2406b00cf46SPoul-Henning Kamp *bt = th->th_offset; 2416b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 242056abcabSPoul-Henning Kamp bintime_add(bt, &boottimebin); 243056abcabSPoul-Henning Kamp } 244056abcabSPoul-Henning Kamp 245056abcabSPoul-Henning Kamp void 246056abcabSPoul-Henning Kamp getnanotime(struct timespec *tsp) 247056abcabSPoul-Henning Kamp { 2486b00cf46SPoul-Henning Kamp struct timehands *th; 2496b00cf46SPoul-Henning Kamp u_int gen; 250056abcabSPoul-Henning Kamp 251056abcabSPoul-Henning Kamp ngetnanotime++; 252056abcabSPoul-Henning Kamp do { 2536b00cf46SPoul-Henning Kamp th = timehands; 2546b00cf46SPoul-Henning Kamp gen = th->th_generation; 2556b00cf46SPoul-Henning Kamp *tsp = th->th_nanotime; 2566b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 257056abcabSPoul-Henning Kamp } 258056abcabSPoul-Henning Kamp 259056abcabSPoul-Henning Kamp void 260056abcabSPoul-Henning Kamp getmicrotime(struct timeval *tvp) 261056abcabSPoul-Henning Kamp { 2626b00cf46SPoul-Henning Kamp struct timehands *th; 2636b00cf46SPoul-Henning Kamp u_int gen; 264056abcabSPoul-Henning Kamp 265056abcabSPoul-Henning Kamp ngetmicrotime++; 266056abcabSPoul-Henning Kamp do { 2676b00cf46SPoul-Henning Kamp th = timehands; 2686b00cf46SPoul-Henning Kamp gen = th->th_generation; 2696b00cf46SPoul-Henning Kamp *tvp = th->th_microtime; 2706b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 2717ec73f64SPoul-Henning Kamp } 2727ec73f64SPoul-Henning Kamp 27339acc78aSPoul-Henning Kamp /* 2746b00cf46SPoul-Henning Kamp * Initialize a new timecounter. 2756b00cf46SPoul-Henning Kamp * We should really try to rank the timecounters and intelligently determine 2766b00cf46SPoul-Henning Kamp * if the new timecounter is better than the current one. This is subject 2776b00cf46SPoul-Henning Kamp * to further study. For now always use the new timecounter. 2784e2befc0SPoul-Henning Kamp */ 2797ec73f64SPoul-Henning Kamp void 28091266b96SPoul-Henning Kamp tc_init(struct timecounter *tc) 2817ec73f64SPoul-Henning Kamp { 282e46eeb89SPoul-Henning Kamp unsigned u; 2837ec73f64SPoul-Henning Kamp 284e46eeb89SPoul-Henning Kamp printf("Timecounter \"%s\" frequency %lu Hz", 285e46eeb89SPoul-Henning Kamp tc->tc_name, (u_long)tc->tc_frequency); 286e46eeb89SPoul-Henning Kamp 287e46eeb89SPoul-Henning Kamp u = tc->tc_frequency / tc->tc_counter_mask; 288e46eeb89SPoul-Henning Kamp if (u > hz) { 289e46eeb89SPoul-Henning Kamp printf(" -- Insufficient hz, needs at least %u\n", u); 290e46eeb89SPoul-Henning Kamp return; 291e46eeb89SPoul-Henning Kamp } 29262efba6aSPoul-Henning Kamp tc->tc_next = timecounters; 29362efba6aSPoul-Henning Kamp timecounters = tc; 294e46eeb89SPoul-Henning Kamp printf("\n"); 29539acc78aSPoul-Henning Kamp (void)tc->tc_get_timecount(tc); 29639acc78aSPoul-Henning Kamp (void)tc->tc_get_timecount(tc); 2977ec73f64SPoul-Henning Kamp timecounter = tc; 29862efba6aSPoul-Henning Kamp } 29962efba6aSPoul-Henning Kamp 30039acc78aSPoul-Henning Kamp /* Report the frequency of the current timecounter. */ 30162efba6aSPoul-Henning Kamp u_int32_t 30262efba6aSPoul-Henning Kamp tc_getfrequency(void) 30362efba6aSPoul-Henning Kamp { 30462efba6aSPoul-Henning Kamp 3056b00cf46SPoul-Henning Kamp return (timehands->th_counter->tc_frequency); 3067ec73f64SPoul-Henning Kamp } 3077ec73f64SPoul-Henning Kamp 30839acc78aSPoul-Henning Kamp /* 3096b00cf46SPoul-Henning Kamp * Step our concept of GMT. This is done by modifying our estimate of 3106b00cf46SPoul-Henning Kamp * when we booted. XXX: needs futher work. 3116b00cf46SPoul-Henning Kamp */ 3127ec73f64SPoul-Henning Kamp void 31391266b96SPoul-Henning Kamp tc_setclock(struct timespec *ts) 3147ec73f64SPoul-Henning Kamp { 31500af9731SPoul-Henning Kamp struct timespec ts2; 3167ec73f64SPoul-Henning Kamp 317c21410e1SPoul-Henning Kamp nanouptime(&ts2); 31800af9731SPoul-Henning Kamp boottime.tv_sec = ts->tv_sec - ts2.tv_sec; 31939acc78aSPoul-Henning Kamp /* XXX boottime should probably be a timespec. */ 32000af9731SPoul-Henning Kamp boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000; 32100af9731SPoul-Henning Kamp if (boottime.tv_usec < 0) { 32200af9731SPoul-Henning Kamp boottime.tv_usec += 1000000; 32300af9731SPoul-Henning Kamp boottime.tv_sec--; 32400af9731SPoul-Henning Kamp } 3252028c0cdSPoul-Henning Kamp timeval2bintime(&boottime, &boottimebin); 32639acc78aSPoul-Henning Kamp 32739acc78aSPoul-Henning Kamp /* XXX fiddle all the little crinkly bits around the fiords... */ 32891266b96SPoul-Henning Kamp tc_windup(); 3297ec73f64SPoul-Henning Kamp } 3307ec73f64SPoul-Henning Kamp 33139acc78aSPoul-Henning Kamp /* 33239acc78aSPoul-Henning Kamp * Initialize the next struct timehands in the ring and make 3336b00cf46SPoul-Henning Kamp * it the active timehands. Along the way we might switch to a different 3346b00cf46SPoul-Henning Kamp * timecounter and/or do seconds processing in NTP. Slightly magic. 3356b00cf46SPoul-Henning Kamp */ 3369e1b5510SPoul-Henning Kamp static void 33791266b96SPoul-Henning Kamp tc_windup(void) 3387ec73f64SPoul-Henning Kamp { 3392028c0cdSPoul-Henning Kamp struct bintime bt; 34039acc78aSPoul-Henning Kamp struct timehands *th, *tho; 3416b00cf46SPoul-Henning Kamp u_int64_t scale; 34239acc78aSPoul-Henning Kamp u_int delta, ncount, ogen; 34339acc78aSPoul-Henning Kamp int i; 3447ec73f64SPoul-Henning Kamp 34539acc78aSPoul-Henning Kamp /* 3466b00cf46SPoul-Henning Kamp * Make the next timehands a copy of the current one, but do not 3476b00cf46SPoul-Henning Kamp * overwrite the generation or next pointer. While we update 3486b00cf46SPoul-Henning Kamp * the contents, the generation must be zero. 3496b00cf46SPoul-Henning Kamp */ 3506b00cf46SPoul-Henning Kamp tho = timehands; 3516b00cf46SPoul-Henning Kamp th = tho->th_next; 3526b00cf46SPoul-Henning Kamp ogen = th->th_generation; 3536b00cf46SPoul-Henning Kamp th->th_generation = 0; 35439acc78aSPoul-Henning Kamp bcopy(tho, th, offsetof(struct timehands, th_generation)); 3556b00cf46SPoul-Henning Kamp 35639acc78aSPoul-Henning Kamp /* 3576b00cf46SPoul-Henning Kamp * Capture a timecounter delta on the current timecounter and if 3586b00cf46SPoul-Henning Kamp * changing timecounters, a counter value from the new timecounter. 3596b00cf46SPoul-Henning Kamp * Update the offset fields accordingly. 3606b00cf46SPoul-Henning Kamp */ 3616b00cf46SPoul-Henning Kamp delta = tc_delta(th); 3626b00cf46SPoul-Henning Kamp if (th->th_counter != timecounter) 3636b00cf46SPoul-Henning Kamp ncount = timecounter->tc_get_timecount(timecounter); 36439acc78aSPoul-Henning Kamp else 36539acc78aSPoul-Henning Kamp ncount = 0; 3666b00cf46SPoul-Henning Kamp th->th_offset_count += delta; 3676b00cf46SPoul-Henning Kamp th->th_offset_count &= th->th_counter->tc_counter_mask; 3686b00cf46SPoul-Henning Kamp bintime_addx(&th->th_offset, th->th_scale * delta); 3696b00cf46SPoul-Henning Kamp 37039acc78aSPoul-Henning Kamp /* 3716b00cf46SPoul-Henning Kamp * Hardware latching timecounters may not generate interrupts on 3726b00cf46SPoul-Henning Kamp * PPS events, so instead we poll them. There is a finite risk that 3736b00cf46SPoul-Henning Kamp * the hardware might capture a count which is later than the one we 3746b00cf46SPoul-Henning Kamp * got above, and therefore possibly in the next NTP second which might 3756b00cf46SPoul-Henning Kamp * have a different rate than the current NTP second. It doesn't 3766b00cf46SPoul-Henning Kamp * matter in practice. 3776b00cf46SPoul-Henning Kamp */ 3786b00cf46SPoul-Henning Kamp if (tho->th_counter->tc_poll_pps) 3796b00cf46SPoul-Henning Kamp tho->th_counter->tc_poll_pps(tho->th_counter); 3806b00cf46SPoul-Henning Kamp 38139acc78aSPoul-Henning Kamp /* 38239acc78aSPoul-Henning Kamp * Deal with NTP second processing. The for loop normally only 38339acc78aSPoul-Henning Kamp * iterates once, but in extreme situations it might keep NTP sane 38439acc78aSPoul-Henning Kamp * if timeouts are not run for several seconds. 3856b00cf46SPoul-Henning Kamp */ 3866b00cf46SPoul-Henning Kamp for (i = th->th_offset.sec - tho->th_offset.sec; i > 0; i--) 3876b00cf46SPoul-Henning Kamp ntp_update_second(&th->th_adjustment, &th->th_offset.sec); 3886b00cf46SPoul-Henning Kamp 3896b00cf46SPoul-Henning Kamp /* Now is a good time to change timecounters. */ 3906b00cf46SPoul-Henning Kamp if (th->th_counter != timecounter) { 3916b00cf46SPoul-Henning Kamp th->th_counter = timecounter; 3926b00cf46SPoul-Henning Kamp th->th_offset_count = ncount; 3937ec73f64SPoul-Henning Kamp } 3947ec73f64SPoul-Henning Kamp 39548e5da55SPoul-Henning Kamp /*- 3966b00cf46SPoul-Henning Kamp * Recalculate the scaling factor. We want the number of 1/2^64 3976b00cf46SPoul-Henning Kamp * fractions of a second per period of the hardware counter, taking 3986b00cf46SPoul-Henning Kamp * into account the th_adjustment factor which the NTP PLL/adjtime(2) 3996b00cf46SPoul-Henning Kamp * processing provides us with. 4006b00cf46SPoul-Henning Kamp * 4016b00cf46SPoul-Henning Kamp * The th_adjustment is nanoseconds per second with 32 bit binary 4026b00cf46SPoul-Henning Kamp * fraction and want 64 bit binary fraction of second: 4036b00cf46SPoul-Henning Kamp * 4046b00cf46SPoul-Henning Kamp * x = a * 2^32 / 10^9 = a * 4.294967296 4056b00cf46SPoul-Henning Kamp * 4066b00cf46SPoul-Henning Kamp * The range of th_adjustment is +/- 5000PPM so inside a 64bit int 4076b00cf46SPoul-Henning Kamp * we can only multiply by about 850 without overflowing, but that 4086b00cf46SPoul-Henning Kamp * leaves suitably precise fractions for multiply before divide. 4096b00cf46SPoul-Henning Kamp * 4106b00cf46SPoul-Henning Kamp * Divide before multiply with a fraction of 2199/512 results in a 4116b00cf46SPoul-Henning Kamp * systematic undercompensation of 10PPM of th_adjustment. On a 4126b00cf46SPoul-Henning Kamp * 5000PPM adjustment this is a 0.05PPM error. This is acceptable. 4136b00cf46SPoul-Henning Kamp * 4146b00cf46SPoul-Henning Kamp * We happily sacrifice the lowest of the 64 bits of our result 4156b00cf46SPoul-Henning Kamp * to the goddess of code clarity. 41639acc78aSPoul-Henning Kamp * 4176b00cf46SPoul-Henning Kamp */ 41839acc78aSPoul-Henning Kamp scale = (u_int64_t)1 << 63; 4196b00cf46SPoul-Henning Kamp scale += (th->th_adjustment / 1024) * 2199; 4206b00cf46SPoul-Henning Kamp scale /= th->th_counter->tc_frequency; 4216b00cf46SPoul-Henning Kamp th->th_scale = scale * 2; 4226b00cf46SPoul-Henning Kamp 4236b00cf46SPoul-Henning Kamp /* Update the GMT timestamps used for the get*() functions. */ 4246b00cf46SPoul-Henning Kamp bt = th->th_offset; 4256b00cf46SPoul-Henning Kamp bintime_add(&bt, &boottimebin); 4266b00cf46SPoul-Henning Kamp bintime2timeval(&bt, &th->th_microtime); 4276b00cf46SPoul-Henning Kamp bintime2timespec(&bt, &th->th_nanotime); 4286b00cf46SPoul-Henning Kamp 42939acc78aSPoul-Henning Kamp /* 43039acc78aSPoul-Henning Kamp * Now that the struct timehands is again consistent, set the new 4316b00cf46SPoul-Henning Kamp * generation number, making sure to not make it zero. 4326b00cf46SPoul-Henning Kamp */ 4336b00cf46SPoul-Henning Kamp if (++ogen == 0) 43439acc78aSPoul-Henning Kamp ogen = 1; 4356b00cf46SPoul-Henning Kamp th->th_generation = ogen; 4366b00cf46SPoul-Henning Kamp 43739acc78aSPoul-Henning Kamp /* Go live with the new struct timehands. */ 4386b00cf46SPoul-Henning Kamp time_second = th->th_microtime.tv_sec; 43938b0884cSPoul-Henning Kamp time_uptime = th->th_offset.sec; 4406b00cf46SPoul-Henning Kamp timehands = th; 4416b00cf46SPoul-Henning Kamp } 4426b00cf46SPoul-Henning Kamp 44339acc78aSPoul-Henning Kamp /* Report or change the active timecounter hardware. */ 4446b6ef746SBruce Evans static int 44582d9ae4eSPoul-Henning Kamp sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) 4466b6ef746SBruce Evans { 4476b6ef746SBruce Evans char newname[32]; 4486b6ef746SBruce Evans struct timecounter *newtc, *tc; 4496b6ef746SBruce Evans int error; 4506b6ef746SBruce Evans 45162efba6aSPoul-Henning Kamp tc = timecounter; 452e80fb434SRobert Drehmel strlcpy(newname, tc->tc_name, sizeof(newname)); 453e80fb434SRobert Drehmel 4546b6ef746SBruce Evans error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); 45539acc78aSPoul-Henning Kamp if (error != 0 || req->newptr == NULL || 45639acc78aSPoul-Henning Kamp strcmp(newname, tc->tc_name) == 0) 45762efba6aSPoul-Henning Kamp return (error); 45862efba6aSPoul-Henning Kamp for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) { 45939acc78aSPoul-Henning Kamp if (strcmp(newname, newtc->tc_name) != 0) 46062efba6aSPoul-Henning Kamp continue; 46139acc78aSPoul-Henning Kamp 4626b6ef746SBruce Evans /* Warm up new timecounter. */ 4636b6ef746SBruce Evans (void)newtc->tc_get_timecount(newtc); 46462efba6aSPoul-Henning Kamp (void)newtc->tc_get_timecount(newtc); 46539acc78aSPoul-Henning Kamp 46662efba6aSPoul-Henning Kamp timecounter = newtc; 4676b6ef746SBruce Evans return (0); 4686b6ef746SBruce Evans } 4696b6ef746SBruce Evans return (EINVAL); 4706b6ef746SBruce Evans } 4716b6ef746SBruce Evans 4726b6ef746SBruce Evans SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, 4736b6ef746SBruce Evans 0, 0, sysctl_kern_timecounter_hardware, "A", ""); 4746b6ef746SBruce Evans 47539acc78aSPoul-Henning Kamp /* 4766b00cf46SPoul-Henning Kamp * RFC 2783 PPS-API implementation. 4776b00cf46SPoul-Henning Kamp */ 4787ec73f64SPoul-Henning Kamp 47932c20357SPoul-Henning Kamp int 48032c20357SPoul-Henning Kamp pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) 48132c20357SPoul-Henning Kamp { 48232c20357SPoul-Henning Kamp pps_params_t *app; 483b7424f2dSJohn Hay struct pps_fetch_args *fapi; 484de3f8889SPeter Wemm #ifdef PPS_SYNC 485b7424f2dSJohn Hay struct pps_kcbind_args *kapi; 486de3f8889SPeter Wemm #endif 48732c20357SPoul-Henning Kamp 48832c20357SPoul-Henning Kamp switch (cmd) { 48932c20357SPoul-Henning Kamp case PPS_IOC_CREATE: 49032c20357SPoul-Henning Kamp return (0); 49132c20357SPoul-Henning Kamp case PPS_IOC_DESTROY: 49232c20357SPoul-Henning Kamp return (0); 49332c20357SPoul-Henning Kamp case PPS_IOC_SETPARAMS: 49432c20357SPoul-Henning Kamp app = (pps_params_t *)data; 49532c20357SPoul-Henning Kamp if (app->mode & ~pps->ppscap) 49632c20357SPoul-Henning Kamp return (EINVAL); 49732c20357SPoul-Henning Kamp pps->ppsparam = *app; 49832c20357SPoul-Henning Kamp return (0); 49932c20357SPoul-Henning Kamp case PPS_IOC_GETPARAMS: 50032c20357SPoul-Henning Kamp app = (pps_params_t *)data; 50132c20357SPoul-Henning Kamp *app = pps->ppsparam; 502b7424f2dSJohn Hay app->api_version = PPS_API_VERS_1; 50332c20357SPoul-Henning Kamp return (0); 50432c20357SPoul-Henning Kamp case PPS_IOC_GETCAP: 50532c20357SPoul-Henning Kamp *(int*)data = pps->ppscap; 50632c20357SPoul-Henning Kamp return (0); 50732c20357SPoul-Henning Kamp case PPS_IOC_FETCH: 508b7424f2dSJohn Hay fapi = (struct pps_fetch_args *)data; 509b7424f2dSJohn Hay if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) 510b7424f2dSJohn Hay return (EINVAL); 511b7424f2dSJohn Hay if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) 51232c20357SPoul-Henning Kamp return (EOPNOTSUPP); 513b7424f2dSJohn Hay pps->ppsinfo.current_mode = pps->ppsparam.mode; 514b7424f2dSJohn Hay fapi->pps_info_buf = pps->ppsinfo; 515b7424f2dSJohn Hay return (0); 516b7424f2dSJohn Hay case PPS_IOC_KCBIND: 517b7424f2dSJohn Hay #ifdef PPS_SYNC 518b7424f2dSJohn Hay kapi = (struct pps_kcbind_args *)data; 519b7424f2dSJohn Hay /* XXX Only root should be able to do this */ 520b7424f2dSJohn Hay if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC) 521b7424f2dSJohn Hay return (EINVAL); 522b7424f2dSJohn Hay if (kapi->kernel_consumer != PPS_KC_HARDPPS) 523b7424f2dSJohn Hay return (EINVAL); 524b7424f2dSJohn Hay if (kapi->edge & ~pps->ppscap) 525b7424f2dSJohn Hay return (EINVAL); 526b7424f2dSJohn Hay pps->kcmode = kapi->edge; 527b7424f2dSJohn Hay return (0); 528b7424f2dSJohn Hay #else 529b7424f2dSJohn Hay return (EOPNOTSUPP); 530b7424f2dSJohn Hay #endif 53132c20357SPoul-Henning Kamp default: 53232c20357SPoul-Henning Kamp return (ENOTTY); 53332c20357SPoul-Henning Kamp } 53432c20357SPoul-Henning Kamp } 53532c20357SPoul-Henning Kamp 53632c20357SPoul-Henning Kamp void 53732c20357SPoul-Henning Kamp pps_init(struct pps_state *pps) 53832c20357SPoul-Henning Kamp { 53932c20357SPoul-Henning Kamp pps->ppscap |= PPS_TSFMT_TSPEC; 54032c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTUREASSERT) 54132c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETASSERT; 54232c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTURECLEAR) 54332c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETCLEAR; 54432c20357SPoul-Henning Kamp } 54532c20357SPoul-Henning Kamp 54632c20357SPoul-Henning Kamp void 5477bf758bfSPoul-Henning Kamp pps_capture(struct pps_state *pps) 5487bf758bfSPoul-Henning Kamp { 5496b00cf46SPoul-Henning Kamp struct timehands *th; 5507bf758bfSPoul-Henning Kamp 5516b00cf46SPoul-Henning Kamp th = timehands; 5526b00cf46SPoul-Henning Kamp pps->capgen = th->th_generation; 5536b00cf46SPoul-Henning Kamp pps->capth = th; 5546b00cf46SPoul-Henning Kamp pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); 5556b00cf46SPoul-Henning Kamp if (pps->capgen != th->th_generation) 5566b00cf46SPoul-Henning Kamp pps->capgen = 0; 5577bf758bfSPoul-Henning Kamp } 5587bf758bfSPoul-Henning Kamp 5597bf758bfSPoul-Henning Kamp void 5607bf758bfSPoul-Henning Kamp pps_event(struct pps_state *pps, int event) 56132c20357SPoul-Henning Kamp { 56239acc78aSPoul-Henning Kamp struct bintime bt; 56332c20357SPoul-Henning Kamp struct timespec ts, *tsp, *osp; 5646b00cf46SPoul-Henning Kamp u_int tcount, *pcount; 56532c20357SPoul-Henning Kamp int foff, fhard; 56632c20357SPoul-Henning Kamp pps_seq_t *pseq; 56732c20357SPoul-Henning Kamp 56839acc78aSPoul-Henning Kamp /* If the timecounter was wound up underneath us, bail out. */ 56939acc78aSPoul-Henning Kamp if (pps->capgen == 0 || pps->capgen != pps->capth->th_generation) 5707bf758bfSPoul-Henning Kamp return; 5717bf758bfSPoul-Henning Kamp 57239acc78aSPoul-Henning Kamp /* Things would be easier with arrays. */ 57332c20357SPoul-Henning Kamp if (event == PPS_CAPTUREASSERT) { 57432c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.assert_timestamp; 57532c20357SPoul-Henning Kamp osp = &pps->ppsparam.assert_offset; 57632c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETASSERT; 577b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTUREASSERT; 57832c20357SPoul-Henning Kamp pcount = &pps->ppscount[0]; 57932c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.assert_sequence; 58032c20357SPoul-Henning Kamp } else { 58132c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.clear_timestamp; 58232c20357SPoul-Henning Kamp osp = &pps->ppsparam.clear_offset; 58332c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; 584b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTURECLEAR; 58532c20357SPoul-Henning Kamp pcount = &pps->ppscount[1]; 58632c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.clear_sequence; 58732c20357SPoul-Henning Kamp } 58832c20357SPoul-Henning Kamp 58939acc78aSPoul-Henning Kamp /* 5906b00cf46SPoul-Henning Kamp * If the timecounter changed, we cannot compare the count values, so 5916b00cf46SPoul-Henning Kamp * we have to drop the rest of the PPS-stuff until the next event. 5926b00cf46SPoul-Henning Kamp */ 5936b00cf46SPoul-Henning Kamp if (pps->ppstc != pps->capth->th_counter) { 5946b00cf46SPoul-Henning Kamp pps->ppstc = pps->capth->th_counter; 5957bf758bfSPoul-Henning Kamp *pcount = pps->capcount; 5967bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 59732c20357SPoul-Henning Kamp return; 59832c20357SPoul-Henning Kamp } 59932c20357SPoul-Henning Kamp 60039acc78aSPoul-Henning Kamp /* Return if nothing really happened. */ 6017bf758bfSPoul-Henning Kamp if (*pcount == pps->capcount) 60232c20357SPoul-Henning Kamp return; 60332c20357SPoul-Henning Kamp 60439acc78aSPoul-Henning Kamp /* Convert the count to a timespec. */ 6056b00cf46SPoul-Henning Kamp tcount = pps->capcount - pps->capth->th_offset_count; 6066b00cf46SPoul-Henning Kamp tcount &= pps->capth->th_counter->tc_counter_mask; 6076b00cf46SPoul-Henning Kamp bt = pps->capth->th_offset; 6086b00cf46SPoul-Henning Kamp bintime_addx(&bt, pps->capth->th_scale * tcount); 609eef633a7SPoul-Henning Kamp bintime_add(&bt, &boottimebin); 6102028c0cdSPoul-Henning Kamp bintime2timespec(&bt, &ts); 61132c20357SPoul-Henning Kamp 61239acc78aSPoul-Henning Kamp /* If the timecounter was wound up underneath us, bail out. */ 6136b00cf46SPoul-Henning Kamp if (pps->capgen != pps->capth->th_generation) 6147bf758bfSPoul-Henning Kamp return; 6157bf758bfSPoul-Henning Kamp 6167bf758bfSPoul-Henning Kamp *pcount = pps->capcount; 61732c20357SPoul-Henning Kamp (*pseq)++; 61832c20357SPoul-Henning Kamp *tsp = ts; 61932c20357SPoul-Henning Kamp 62032c20357SPoul-Henning Kamp if (foff) { 62132c20357SPoul-Henning Kamp timespecadd(tsp, osp); 62232c20357SPoul-Henning Kamp if (tsp->tv_nsec < 0) { 62332c20357SPoul-Henning Kamp tsp->tv_nsec += 1000000000; 62432c20357SPoul-Henning Kamp tsp->tv_sec -= 1; 62532c20357SPoul-Henning Kamp } 62632c20357SPoul-Henning Kamp } 62732c20357SPoul-Henning Kamp #ifdef PPS_SYNC 62832c20357SPoul-Henning Kamp if (fhard) { 62939acc78aSPoul-Henning Kamp /* 6306b00cf46SPoul-Henning Kamp * Feed the NTP PLL/FLL. 6316b00cf46SPoul-Henning Kamp * The FLL wants to know how many nanoseconds elapsed since 6326b00cf46SPoul-Henning Kamp * the previous event. 6336b00cf46SPoul-Henning Kamp * I have never been able to convince myself that this code 6346b00cf46SPoul-Henning Kamp * is actually correct: Using th_scale is bound to contain 6356b00cf46SPoul-Henning Kamp * a phase correction component from userland, when running 6366b00cf46SPoul-Henning Kamp * as FLL, so the number hardpps() gets is not meaningful IMO. 6376b00cf46SPoul-Henning Kamp */ 6387bf758bfSPoul-Henning Kamp tcount = pps->capcount - pps->ppscount[2]; 6397bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 6406b00cf46SPoul-Henning Kamp tcount &= pps->capth->th_counter->tc_counter_mask; 6412028c0cdSPoul-Henning Kamp bt.sec = 0; 6422028c0cdSPoul-Henning Kamp bt.frac = 0; 6436b00cf46SPoul-Henning Kamp bintime_addx(&bt, pps->capth->th_scale * tcount); 6442028c0cdSPoul-Henning Kamp bintime2timespec(&bt, &ts); 6452028c0cdSPoul-Henning Kamp hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec); 64632c20357SPoul-Henning Kamp } 64732c20357SPoul-Henning Kamp #endif 64832c20357SPoul-Henning Kamp } 6499e1b5510SPoul-Henning Kamp 65039acc78aSPoul-Henning Kamp /* 6519e1b5510SPoul-Henning Kamp * Timecounters need to be updated every so often to prevent the hardware 6529e1b5510SPoul-Henning Kamp * counter from overflowing. Updating also recalculates the cached values 6539e1b5510SPoul-Henning Kamp * used by the get*() family of functions, so their precision depends on 6549e1b5510SPoul-Henning Kamp * the update frequency. 6559e1b5510SPoul-Henning Kamp */ 6569e1b5510SPoul-Henning Kamp 6579e1b5510SPoul-Henning Kamp static int tc_tick; 658b3ed130cSPoul-Henning Kamp SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, ""); 6599e1b5510SPoul-Henning Kamp 660e7fa55afSPoul-Henning Kamp void 661e7fa55afSPoul-Henning Kamp tc_ticktock(void) 6629e1b5510SPoul-Henning Kamp { 663e7fa55afSPoul-Henning Kamp static int count; 6649e1b5510SPoul-Henning Kamp 665e7fa55afSPoul-Henning Kamp if (++count < tc_tick) 666e7fa55afSPoul-Henning Kamp return; 667e7fa55afSPoul-Henning Kamp count = 0; 6689e1b5510SPoul-Henning Kamp tc_windup(); 6699e1b5510SPoul-Henning Kamp } 6709e1b5510SPoul-Henning Kamp 6719e1b5510SPoul-Henning Kamp static void 6729e1b5510SPoul-Henning Kamp inittimecounter(void *dummy) 6739e1b5510SPoul-Henning Kamp { 6749e1b5510SPoul-Henning Kamp u_int p; 6759e1b5510SPoul-Henning Kamp 67639acc78aSPoul-Henning Kamp /* 67739acc78aSPoul-Henning Kamp * Set the initial timeout to 67839acc78aSPoul-Henning Kamp * max(1, <approx. number of hardclock ticks in a millisecond>). 67939acc78aSPoul-Henning Kamp * People should probably not use the sysctl to set the timeout 68039acc78aSPoul-Henning Kamp * to smaller than its inital value, since that value is the 68139acc78aSPoul-Henning Kamp * smallest reasonable one. If they want better timestamps they 68239acc78aSPoul-Henning Kamp * should use the non-"get"* functions. 68339acc78aSPoul-Henning Kamp */ 6849e1b5510SPoul-Henning Kamp if (hz > 1000) 6859e1b5510SPoul-Henning Kamp tc_tick = (hz + 500) / 1000; 6869e1b5510SPoul-Henning Kamp else 6879e1b5510SPoul-Henning Kamp tc_tick = 1; 6889e1b5510SPoul-Henning Kamp p = (tc_tick * 1000000) / hz; 6899e1b5510SPoul-Henning Kamp printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); 69039acc78aSPoul-Henning Kamp 69148e5da55SPoul-Henning Kamp /* warm up new timecounter (again) and get rolling. */ 69239acc78aSPoul-Henning Kamp (void)timecounter->tc_get_timecount(timecounter); 69339acc78aSPoul-Henning Kamp (void)timecounter->tc_get_timecount(timecounter); 6949e1b5510SPoul-Henning Kamp } 6959e1b5510SPoul-Henning Kamp 696ff292556SPeter Wemm SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL) 697