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 */ 9df8bae1dSRodney W. Grimes 10677b542eSDavid E. O'Brien #include <sys/cdefs.h> 11677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 12677b542eSDavid E. O'Brien 1332c20357SPoul-Henning Kamp #include "opt_ntp.h" 1432c20357SPoul-Henning Kamp 15df8bae1dSRodney W. Grimes #include <sys/param.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 /* 244f2073fbSWarner Losh * a large step happens on boot. This constant detects such 254f2073fbSWarner Losh * a steps. It is relatively small so that ntp_update_second gets called 264f2073fbSWarner Losh * enough in the typical 'missed a couple of seconds' case, but doesn't 274f2073fbSWarner Losh * loop forever when the time step is large. 284f2073fbSWarner Losh */ 294f2073fbSWarner Losh #define LARGE_STEP 200 304f2073fbSWarner Losh 314f2073fbSWarner Losh /* 3262efba6aSPoul-Henning Kamp * Implement a dummy timecounter which we can use until we get a real one 3362efba6aSPoul-Henning Kamp * in the air. This allows the console and other early stuff to use 3462efba6aSPoul-Henning Kamp * time services. 353bac064fSPoul-Henning Kamp */ 363bac064fSPoul-Henning Kamp 376b00cf46SPoul-Henning Kamp static u_int 3862efba6aSPoul-Henning Kamp dummy_get_timecount(struct timecounter *tc) 3962efba6aSPoul-Henning Kamp { 406b00cf46SPoul-Henning Kamp static u_int now; 4162efba6aSPoul-Henning Kamp 4262efba6aSPoul-Henning Kamp return (++now); 4362efba6aSPoul-Henning Kamp } 4462efba6aSPoul-Henning Kamp 4562efba6aSPoul-Henning Kamp static struct timecounter dummy_timecounter = { 4639acc78aSPoul-Henning Kamp dummy_get_timecount, 0, ~0u, 1000000, "dummy", 4762efba6aSPoul-Henning Kamp }; 4862efba6aSPoul-Henning Kamp 4962efba6aSPoul-Henning Kamp struct timehands { 5062efba6aSPoul-Henning Kamp /* These fields must be initialized by the driver. */ 516b00cf46SPoul-Henning Kamp struct timecounter *th_counter; 526b00cf46SPoul-Henning Kamp int64_t th_adjustment; 536b00cf46SPoul-Henning Kamp u_int64_t th_scale; 546b00cf46SPoul-Henning Kamp u_int th_offset_count; 556b00cf46SPoul-Henning Kamp struct bintime th_offset; 566b00cf46SPoul-Henning Kamp struct timeval th_microtime; 576b00cf46SPoul-Henning Kamp struct timespec th_nanotime; 5839acc78aSPoul-Henning Kamp /* Fields not to be copied in tc_windup start with th_generation. */ 596b00cf46SPoul-Henning Kamp volatile u_int th_generation; 606b00cf46SPoul-Henning Kamp struct timehands *th_next; 6162efba6aSPoul-Henning Kamp }; 6262efba6aSPoul-Henning Kamp 6362efba6aSPoul-Henning Kamp extern struct timehands th0; 6439acc78aSPoul-Henning Kamp static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; 6539acc78aSPoul-Henning Kamp static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; 6639acc78aSPoul-Henning Kamp static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th8}; 6739acc78aSPoul-Henning Kamp static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th7}; 6839acc78aSPoul-Henning Kamp static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th6}; 6939acc78aSPoul-Henning Kamp static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; 7039acc78aSPoul-Henning Kamp static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; 7139acc78aSPoul-Henning Kamp static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; 7239acc78aSPoul-Henning Kamp static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; 73f5d157fbSPoul-Henning Kamp static struct timehands th0 = { 74f5d157fbSPoul-Henning Kamp &dummy_timecounter, 75f5d157fbSPoul-Henning Kamp 0, 7639acc78aSPoul-Henning Kamp (uint64_t)-1 / 1000000, 77f5d157fbSPoul-Henning Kamp 0, 78d25917e8SPoul-Henning Kamp {1, 0}, 79f5d157fbSPoul-Henning Kamp {0, 0}, 80f5d157fbSPoul-Henning Kamp {0, 0}, 81f5d157fbSPoul-Henning Kamp 1, 82f5d157fbSPoul-Henning Kamp &th1 83f5d157fbSPoul-Henning Kamp }; 8462efba6aSPoul-Henning Kamp 8562efba6aSPoul-Henning Kamp static struct timehands *volatile timehands = &th0; 8662efba6aSPoul-Henning Kamp struct timecounter *timecounter = &dummy_timecounter; 8762efba6aSPoul-Henning Kamp static struct timecounter *timecounters = &dummy_timecounter; 883bac064fSPoul-Henning Kamp 8948e5da55SPoul-Henning Kamp time_t time_second = 1; 9038b0884cSPoul-Henning Kamp time_t time_uptime = 0; 91227ee8a1SPoul-Henning Kamp 9239acc78aSPoul-Henning Kamp static struct bintime boottimebin; 9337d38777SBruce Evans struct timeval boottime; 9437d38777SBruce Evans SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD, 9537d38777SBruce Evans &boottime, timeval, "System boottime"); 9637d38777SBruce Evans 9791266b96SPoul-Henning Kamp SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); 9891266b96SPoul-Henning Kamp 99056abcabSPoul-Henning Kamp #define TC_STATS(foo) \ 1006b00cf46SPoul-Henning Kamp static u_int foo; \ 1014f8cb019SMark Murray SYSCTL_UINT(_kern_timecounter, OID_AUTO, foo, CTLFLAG_RD, &foo, 0, "");\ 10239acc78aSPoul-Henning Kamp struct __hack 103056abcabSPoul-Henning Kamp 104056abcabSPoul-Henning Kamp TC_STATS(nbinuptime); TC_STATS(nnanouptime); TC_STATS(nmicrouptime); 105056abcabSPoul-Henning Kamp TC_STATS(nbintime); TC_STATS(nnanotime); TC_STATS(nmicrotime); 106056abcabSPoul-Henning Kamp TC_STATS(ngetbinuptime); TC_STATS(ngetnanouptime); TC_STATS(ngetmicrouptime); 107056abcabSPoul-Henning Kamp TC_STATS(ngetbintime); TC_STATS(ngetnanotime); TC_STATS(ngetmicrotime); 1084394f476SPoul-Henning Kamp TC_STATS(nsetclock); 109056abcabSPoul-Henning Kamp 110056abcabSPoul-Henning Kamp #undef TC_STATS 111510eb5b9SPoul-Henning Kamp 1129e1b5510SPoul-Henning Kamp static void tc_windup(void); 1139e1b5510SPoul-Henning Kamp 11439acc78aSPoul-Henning Kamp /* 11539acc78aSPoul-Henning Kamp * Return the difference between the timehands' counter value now and what 11639acc78aSPoul-Henning Kamp * was when we copied it to the timehands' offset_count. 11739acc78aSPoul-Henning Kamp */ 1186b00cf46SPoul-Henning Kamp static __inline u_int 1196b00cf46SPoul-Henning Kamp tc_delta(struct timehands *th) 120e796e00dSPoul-Henning Kamp { 1216b00cf46SPoul-Henning Kamp struct timecounter *tc; 122e796e00dSPoul-Henning Kamp 1236b00cf46SPoul-Henning Kamp tc = th->th_counter; 1246b00cf46SPoul-Henning Kamp return ((tc->tc_get_timecount(tc) - th->th_offset_count) & 1256b00cf46SPoul-Henning Kamp tc->tc_counter_mask); 126e796e00dSPoul-Henning Kamp } 127a0502b19SPoul-Henning Kamp 12839acc78aSPoul-Henning Kamp /* 1296b00cf46SPoul-Henning Kamp * Functions for reading the time. We have to loop until we are sure that 13039acc78aSPoul-Henning Kamp * the timehands that we operated on was not updated under our feet. See 13139acc78aSPoul-Henning Kamp * the comment in <sys/time.h> for a description of these 12 functions. 1326b00cf46SPoul-Henning Kamp */ 1336b00cf46SPoul-Henning Kamp 134a0502b19SPoul-Henning Kamp void 1352028c0cdSPoul-Henning Kamp binuptime(struct bintime *bt) 1362028c0cdSPoul-Henning Kamp { 1376b00cf46SPoul-Henning Kamp struct timehands *th; 1386b00cf46SPoul-Henning Kamp u_int gen; 1392028c0cdSPoul-Henning Kamp 1405b7d8efaSPoul-Henning Kamp nbinuptime++; 1415b7d8efaSPoul-Henning Kamp do { 1426b00cf46SPoul-Henning Kamp th = timehands; 1436b00cf46SPoul-Henning Kamp gen = th->th_generation; 1446b00cf46SPoul-Henning Kamp *bt = th->th_offset; 1456b00cf46SPoul-Henning Kamp bintime_addx(bt, th->th_scale * tc_delta(th)); 1466b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 1472028c0cdSPoul-Henning Kamp } 1482028c0cdSPoul-Henning Kamp 1492028c0cdSPoul-Henning Kamp void 15039acc78aSPoul-Henning Kamp nanouptime(struct timespec *tsp) 151056abcabSPoul-Henning Kamp { 152056abcabSPoul-Henning Kamp struct bintime bt; 153056abcabSPoul-Henning Kamp 154056abcabSPoul-Henning Kamp nnanouptime++; 155056abcabSPoul-Henning Kamp binuptime(&bt); 15639acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 157056abcabSPoul-Henning Kamp } 158056abcabSPoul-Henning Kamp 159056abcabSPoul-Henning Kamp void 16039acc78aSPoul-Henning Kamp microuptime(struct timeval *tvp) 161056abcabSPoul-Henning Kamp { 162056abcabSPoul-Henning Kamp struct bintime bt; 163056abcabSPoul-Henning Kamp 164056abcabSPoul-Henning Kamp nmicrouptime++; 165056abcabSPoul-Henning Kamp binuptime(&bt); 16639acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 167056abcabSPoul-Henning Kamp } 168056abcabSPoul-Henning Kamp 169056abcabSPoul-Henning Kamp void 1702028c0cdSPoul-Henning Kamp bintime(struct bintime *bt) 1712028c0cdSPoul-Henning Kamp { 1722028c0cdSPoul-Henning Kamp 1735b7d8efaSPoul-Henning Kamp nbintime++; 1742028c0cdSPoul-Henning Kamp binuptime(bt); 1752028c0cdSPoul-Henning Kamp bintime_add(bt, &boottimebin); 1762028c0cdSPoul-Henning Kamp } 1772028c0cdSPoul-Henning Kamp 1782028c0cdSPoul-Henning Kamp void 17939acc78aSPoul-Henning Kamp nanotime(struct timespec *tsp) 18000af9731SPoul-Henning Kamp { 1812028c0cdSPoul-Henning Kamp struct bintime bt; 18200af9731SPoul-Henning Kamp 18391266b96SPoul-Henning Kamp nnanotime++; 1842028c0cdSPoul-Henning Kamp bintime(&bt); 18539acc78aSPoul-Henning Kamp bintime2timespec(&bt, tsp); 18648115288SPoul-Henning Kamp } 18748115288SPoul-Henning Kamp 18848115288SPoul-Henning Kamp void 18939acc78aSPoul-Henning Kamp microtime(struct timeval *tvp) 190056abcabSPoul-Henning Kamp { 191056abcabSPoul-Henning Kamp struct bintime bt; 192056abcabSPoul-Henning Kamp 193056abcabSPoul-Henning Kamp nmicrotime++; 194056abcabSPoul-Henning Kamp bintime(&bt); 19539acc78aSPoul-Henning Kamp bintime2timeval(&bt, tvp); 196056abcabSPoul-Henning Kamp } 197056abcabSPoul-Henning Kamp 198056abcabSPoul-Henning Kamp void 199056abcabSPoul-Henning Kamp getbinuptime(struct bintime *bt) 20000af9731SPoul-Henning Kamp { 2016b00cf46SPoul-Henning Kamp struct timehands *th; 2026b00cf46SPoul-Henning Kamp u_int gen; 20300af9731SPoul-Henning Kamp 204056abcabSPoul-Henning Kamp ngetbinuptime++; 2055b7d8efaSPoul-Henning Kamp do { 2066b00cf46SPoul-Henning Kamp th = timehands; 2076b00cf46SPoul-Henning Kamp gen = th->th_generation; 2086b00cf46SPoul-Henning Kamp *bt = th->th_offset; 2096b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 210a0502b19SPoul-Henning Kamp } 211a0502b19SPoul-Henning Kamp 212a0502b19SPoul-Henning Kamp void 213c21410e1SPoul-Henning Kamp getnanouptime(struct timespec *tsp) 214a0502b19SPoul-Henning Kamp { 2156b00cf46SPoul-Henning Kamp struct timehands *th; 2166b00cf46SPoul-Henning Kamp u_int gen; 217a0502b19SPoul-Henning Kamp 21891266b96SPoul-Henning Kamp ngetnanouptime++; 2195b7d8efaSPoul-Henning Kamp do { 2206b00cf46SPoul-Henning Kamp th = timehands; 2216b00cf46SPoul-Henning Kamp gen = th->th_generation; 2226b00cf46SPoul-Henning Kamp bintime2timespec(&th->th_offset, tsp); 2236b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 224a0502b19SPoul-Henning Kamp } 225a0502b19SPoul-Henning Kamp 226c7c9a816SPoul-Henning Kamp void 227056abcabSPoul-Henning Kamp getmicrouptime(struct timeval *tvp) 228c7c9a816SPoul-Henning Kamp { 2296b00cf46SPoul-Henning Kamp struct timehands *th; 2306b00cf46SPoul-Henning Kamp u_int gen; 2317ec73f64SPoul-Henning Kamp 232056abcabSPoul-Henning Kamp ngetmicrouptime++; 233056abcabSPoul-Henning Kamp do { 2346b00cf46SPoul-Henning Kamp th = timehands; 2356b00cf46SPoul-Henning Kamp gen = th->th_generation; 2366b00cf46SPoul-Henning Kamp bintime2timeval(&th->th_offset, tvp); 2376b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 2387ec73f64SPoul-Henning Kamp } 2397ec73f64SPoul-Henning Kamp 2407ec73f64SPoul-Henning Kamp void 241056abcabSPoul-Henning Kamp getbintime(struct bintime *bt) 2427ec73f64SPoul-Henning Kamp { 2436b00cf46SPoul-Henning Kamp struct timehands *th; 2446b00cf46SPoul-Henning Kamp u_int gen; 2457ec73f64SPoul-Henning Kamp 246056abcabSPoul-Henning Kamp ngetbintime++; 247056abcabSPoul-Henning Kamp do { 2486b00cf46SPoul-Henning Kamp th = timehands; 2496b00cf46SPoul-Henning Kamp gen = th->th_generation; 2506b00cf46SPoul-Henning Kamp *bt = th->th_offset; 2516b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 252056abcabSPoul-Henning Kamp bintime_add(bt, &boottimebin); 253056abcabSPoul-Henning Kamp } 254056abcabSPoul-Henning Kamp 255056abcabSPoul-Henning Kamp void 256056abcabSPoul-Henning Kamp getnanotime(struct timespec *tsp) 257056abcabSPoul-Henning Kamp { 2586b00cf46SPoul-Henning Kamp struct timehands *th; 2596b00cf46SPoul-Henning Kamp u_int gen; 260056abcabSPoul-Henning Kamp 261056abcabSPoul-Henning Kamp ngetnanotime++; 262056abcabSPoul-Henning Kamp do { 2636b00cf46SPoul-Henning Kamp th = timehands; 2646b00cf46SPoul-Henning Kamp gen = th->th_generation; 2656b00cf46SPoul-Henning Kamp *tsp = th->th_nanotime; 2666b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 267056abcabSPoul-Henning Kamp } 268056abcabSPoul-Henning Kamp 269056abcabSPoul-Henning Kamp void 270056abcabSPoul-Henning Kamp getmicrotime(struct timeval *tvp) 271056abcabSPoul-Henning Kamp { 2726b00cf46SPoul-Henning Kamp struct timehands *th; 2736b00cf46SPoul-Henning Kamp u_int gen; 274056abcabSPoul-Henning Kamp 275056abcabSPoul-Henning Kamp ngetmicrotime++; 276056abcabSPoul-Henning Kamp do { 2776b00cf46SPoul-Henning Kamp th = timehands; 2786b00cf46SPoul-Henning Kamp gen = th->th_generation; 2796b00cf46SPoul-Henning Kamp *tvp = th->th_microtime; 2806b00cf46SPoul-Henning Kamp } while (gen == 0 || gen != th->th_generation); 2817ec73f64SPoul-Henning Kamp } 2827ec73f64SPoul-Henning Kamp 28339acc78aSPoul-Henning Kamp /* 2846b00cf46SPoul-Henning Kamp * Initialize a new timecounter. 2856b00cf46SPoul-Henning Kamp * We should really try to rank the timecounters and intelligently determine 2866b00cf46SPoul-Henning Kamp * if the new timecounter is better than the current one. This is subject 2876b00cf46SPoul-Henning Kamp * to further study. For now always use the new timecounter. 2884e2befc0SPoul-Henning Kamp */ 2897ec73f64SPoul-Henning Kamp void 29091266b96SPoul-Henning Kamp tc_init(struct timecounter *tc) 2917ec73f64SPoul-Henning Kamp { 292e46eeb89SPoul-Henning Kamp unsigned u; 2937ec73f64SPoul-Henning Kamp 29460ca3996SPoul-Henning Kamp printf("Timecounter \"%s\" frequency %ju Hz", 29560ca3996SPoul-Henning Kamp tc->tc_name, (intmax_t)tc->tc_frequency); 296e46eeb89SPoul-Henning Kamp 297e46eeb89SPoul-Henning Kamp u = tc->tc_frequency / tc->tc_counter_mask; 298e46eeb89SPoul-Henning Kamp if (u > hz) { 299e46eeb89SPoul-Henning Kamp printf(" -- Insufficient hz, needs at least %u\n", u); 300e46eeb89SPoul-Henning Kamp return; 301e46eeb89SPoul-Henning Kamp } 30262efba6aSPoul-Henning Kamp tc->tc_next = timecounters; 30362efba6aSPoul-Henning Kamp timecounters = tc; 304e46eeb89SPoul-Henning Kamp printf("\n"); 30539acc78aSPoul-Henning Kamp (void)tc->tc_get_timecount(tc); 30639acc78aSPoul-Henning Kamp (void)tc->tc_get_timecount(tc); 3077ec73f64SPoul-Henning Kamp timecounter = tc; 30862efba6aSPoul-Henning Kamp } 30962efba6aSPoul-Henning Kamp 31039acc78aSPoul-Henning Kamp /* Report the frequency of the current timecounter. */ 31160ca3996SPoul-Henning Kamp u_int64_t 31262efba6aSPoul-Henning Kamp tc_getfrequency(void) 31362efba6aSPoul-Henning Kamp { 31462efba6aSPoul-Henning Kamp 3156b00cf46SPoul-Henning Kamp return (timehands->th_counter->tc_frequency); 3167ec73f64SPoul-Henning Kamp } 3177ec73f64SPoul-Henning Kamp 31839acc78aSPoul-Henning Kamp /* 3194e82e5f6SWarner Losh * Step our concept of UTC. This is done by modifying our estimate of 3206b00cf46SPoul-Henning Kamp * when we booted. XXX: needs futher work. 3216b00cf46SPoul-Henning Kamp */ 3227ec73f64SPoul-Henning Kamp void 32391266b96SPoul-Henning Kamp tc_setclock(struct timespec *ts) 3247ec73f64SPoul-Henning Kamp { 32500af9731SPoul-Henning Kamp struct timespec ts2; 3267ec73f64SPoul-Henning Kamp 3274394f476SPoul-Henning Kamp nsetclock++; 328c21410e1SPoul-Henning Kamp nanouptime(&ts2); 32900af9731SPoul-Henning Kamp boottime.tv_sec = ts->tv_sec - ts2.tv_sec; 33039acc78aSPoul-Henning Kamp /* XXX boottime should probably be a timespec. */ 33100af9731SPoul-Henning Kamp boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000; 33200af9731SPoul-Henning Kamp if (boottime.tv_usec < 0) { 33300af9731SPoul-Henning Kamp boottime.tv_usec += 1000000; 33400af9731SPoul-Henning Kamp boottime.tv_sec--; 33500af9731SPoul-Henning Kamp } 3362028c0cdSPoul-Henning Kamp timeval2bintime(&boottime, &boottimebin); 33739acc78aSPoul-Henning Kamp 33839acc78aSPoul-Henning Kamp /* XXX fiddle all the little crinkly bits around the fiords... */ 33991266b96SPoul-Henning Kamp tc_windup(); 3407ec73f64SPoul-Henning Kamp } 3417ec73f64SPoul-Henning Kamp 34239acc78aSPoul-Henning Kamp /* 34339acc78aSPoul-Henning Kamp * Initialize the next struct timehands in the ring and make 3446b00cf46SPoul-Henning Kamp * it the active timehands. Along the way we might switch to a different 3456b00cf46SPoul-Henning Kamp * timecounter and/or do seconds processing in NTP. Slightly magic. 3466b00cf46SPoul-Henning Kamp */ 3479e1b5510SPoul-Henning Kamp static void 34891266b96SPoul-Henning Kamp tc_windup(void) 3497ec73f64SPoul-Henning Kamp { 3502028c0cdSPoul-Henning Kamp struct bintime bt; 35139acc78aSPoul-Henning Kamp struct timehands *th, *tho; 3526b00cf46SPoul-Henning Kamp u_int64_t scale; 35339acc78aSPoul-Henning Kamp u_int delta, ncount, ogen; 35439acc78aSPoul-Henning Kamp int i; 3554f2073fbSWarner Losh time_t t; 3567ec73f64SPoul-Henning Kamp 35739acc78aSPoul-Henning Kamp /* 3586b00cf46SPoul-Henning Kamp * Make the next timehands a copy of the current one, but do not 3596b00cf46SPoul-Henning Kamp * overwrite the generation or next pointer. While we update 3606b00cf46SPoul-Henning Kamp * the contents, the generation must be zero. 3616b00cf46SPoul-Henning Kamp */ 3626b00cf46SPoul-Henning Kamp tho = timehands; 3636b00cf46SPoul-Henning Kamp th = tho->th_next; 3646b00cf46SPoul-Henning Kamp ogen = th->th_generation; 3656b00cf46SPoul-Henning Kamp th->th_generation = 0; 36639acc78aSPoul-Henning Kamp bcopy(tho, th, offsetof(struct timehands, th_generation)); 3676b00cf46SPoul-Henning Kamp 36839acc78aSPoul-Henning Kamp /* 3696b00cf46SPoul-Henning Kamp * Capture a timecounter delta on the current timecounter and if 3706b00cf46SPoul-Henning Kamp * changing timecounters, a counter value from the new timecounter. 3716b00cf46SPoul-Henning Kamp * Update the offset fields accordingly. 3726b00cf46SPoul-Henning Kamp */ 3736b00cf46SPoul-Henning Kamp delta = tc_delta(th); 3746b00cf46SPoul-Henning Kamp if (th->th_counter != timecounter) 3756b00cf46SPoul-Henning Kamp ncount = timecounter->tc_get_timecount(timecounter); 37639acc78aSPoul-Henning Kamp else 37739acc78aSPoul-Henning Kamp ncount = 0; 3786b00cf46SPoul-Henning Kamp th->th_offset_count += delta; 3796b00cf46SPoul-Henning Kamp th->th_offset_count &= th->th_counter->tc_counter_mask; 3806b00cf46SPoul-Henning Kamp bintime_addx(&th->th_offset, th->th_scale * delta); 3816b00cf46SPoul-Henning Kamp 38239acc78aSPoul-Henning Kamp /* 3836b00cf46SPoul-Henning Kamp * Hardware latching timecounters may not generate interrupts on 3846b00cf46SPoul-Henning Kamp * PPS events, so instead we poll them. There is a finite risk that 3856b00cf46SPoul-Henning Kamp * the hardware might capture a count which is later than the one we 3866b00cf46SPoul-Henning Kamp * got above, and therefore possibly in the next NTP second which might 3876b00cf46SPoul-Henning Kamp * have a different rate than the current NTP second. It doesn't 3886b00cf46SPoul-Henning Kamp * matter in practice. 3896b00cf46SPoul-Henning Kamp */ 3906b00cf46SPoul-Henning Kamp if (tho->th_counter->tc_poll_pps) 3916b00cf46SPoul-Henning Kamp tho->th_counter->tc_poll_pps(tho->th_counter); 3926b00cf46SPoul-Henning Kamp 39339acc78aSPoul-Henning Kamp /* 3944f2073fbSWarner Losh * Compute the UTC time, before any leapsecond adjustments, are 3954f2073fbSWarner Losh * made. 3964f2073fbSWarner Losh */ 3974f2073fbSWarner Losh bt = th->th_offset; 3984f2073fbSWarner Losh bintime_add(&bt, &boottimebin); 3994f2073fbSWarner Losh 4004f2073fbSWarner Losh /* 40139acc78aSPoul-Henning Kamp * Deal with NTP second processing. The for loop normally only 40239acc78aSPoul-Henning Kamp * iterates once, but in extreme situations it might keep NTP sane 4034f2073fbSWarner Losh * if timeouts are not run for several seconds. At boot, the 4044f2073fbSWarner Losh * time step can be large when the TOD hardware has been read, so 4054f2073fbSWarner Losh * on really large steps, we call ntp_update_second only once. 4066b00cf46SPoul-Henning Kamp */ 4074f2073fbSWarner Losh for (i = bt.sec - tho->th_microtime.tv_sec; i > 0; i--) { 4084f2073fbSWarner Losh t = bt.sec; 4094f2073fbSWarner Losh ntp_update_second(&th->th_adjustment, &bt.sec); 4104f2073fbSWarner Losh if (bt.sec != t) 4114f2073fbSWarner Losh boottimebin.sec += bt.sec - t; 4124f2073fbSWarner Losh if (i > LARGE_STEP) 4134f2073fbSWarner Losh break; 4144f2073fbSWarner Losh } 4156b00cf46SPoul-Henning Kamp 4166b00cf46SPoul-Henning Kamp /* Now is a good time to change timecounters. */ 4176b00cf46SPoul-Henning Kamp if (th->th_counter != timecounter) { 4186b00cf46SPoul-Henning Kamp th->th_counter = timecounter; 4196b00cf46SPoul-Henning Kamp th->th_offset_count = ncount; 4207ec73f64SPoul-Henning Kamp } 4217ec73f64SPoul-Henning Kamp 42248e5da55SPoul-Henning Kamp /*- 4236b00cf46SPoul-Henning Kamp * Recalculate the scaling factor. We want the number of 1/2^64 4246b00cf46SPoul-Henning Kamp * fractions of a second per period of the hardware counter, taking 4256b00cf46SPoul-Henning Kamp * into account the th_adjustment factor which the NTP PLL/adjtime(2) 4266b00cf46SPoul-Henning Kamp * processing provides us with. 4276b00cf46SPoul-Henning Kamp * 4286b00cf46SPoul-Henning Kamp * The th_adjustment is nanoseconds per second with 32 bit binary 429d94e3652SPoul-Henning Kamp * fraction and we want 64 bit binary fraction of second: 4306b00cf46SPoul-Henning Kamp * 4316b00cf46SPoul-Henning Kamp * x = a * 2^32 / 10^9 = a * 4.294967296 4326b00cf46SPoul-Henning Kamp * 4336b00cf46SPoul-Henning Kamp * The range of th_adjustment is +/- 5000PPM so inside a 64bit int 4346b00cf46SPoul-Henning Kamp * we can only multiply by about 850 without overflowing, but that 4356b00cf46SPoul-Henning Kamp * leaves suitably precise fractions for multiply before divide. 4366b00cf46SPoul-Henning Kamp * 4376b00cf46SPoul-Henning Kamp * Divide before multiply with a fraction of 2199/512 results in a 4386b00cf46SPoul-Henning Kamp * systematic undercompensation of 10PPM of th_adjustment. On a 4396b00cf46SPoul-Henning Kamp * 5000PPM adjustment this is a 0.05PPM error. This is acceptable. 4406b00cf46SPoul-Henning Kamp * 4416b00cf46SPoul-Henning Kamp * We happily sacrifice the lowest of the 64 bits of our result 4426b00cf46SPoul-Henning Kamp * to the goddess of code clarity. 44339acc78aSPoul-Henning Kamp * 4446b00cf46SPoul-Henning Kamp */ 44539acc78aSPoul-Henning Kamp scale = (u_int64_t)1 << 63; 4466b00cf46SPoul-Henning Kamp scale += (th->th_adjustment / 1024) * 2199; 4476b00cf46SPoul-Henning Kamp scale /= th->th_counter->tc_frequency; 4486b00cf46SPoul-Henning Kamp th->th_scale = scale * 2; 4496b00cf46SPoul-Henning Kamp 4506b00cf46SPoul-Henning Kamp bintime2timeval(&bt, &th->th_microtime); 4516b00cf46SPoul-Henning Kamp bintime2timespec(&bt, &th->th_nanotime); 4526b00cf46SPoul-Henning Kamp 45339acc78aSPoul-Henning Kamp /* 45439acc78aSPoul-Henning Kamp * Now that the struct timehands is again consistent, set the new 4556b00cf46SPoul-Henning Kamp * generation number, making sure to not make it zero. 4566b00cf46SPoul-Henning Kamp */ 4576b00cf46SPoul-Henning Kamp if (++ogen == 0) 45839acc78aSPoul-Henning Kamp ogen = 1; 4596b00cf46SPoul-Henning Kamp th->th_generation = ogen; 4606b00cf46SPoul-Henning Kamp 46139acc78aSPoul-Henning Kamp /* Go live with the new struct timehands. */ 4626b00cf46SPoul-Henning Kamp time_second = th->th_microtime.tv_sec; 46338b0884cSPoul-Henning Kamp time_uptime = th->th_offset.sec; 4646b00cf46SPoul-Henning Kamp timehands = th; 4656b00cf46SPoul-Henning Kamp } 4666b00cf46SPoul-Henning Kamp 46739acc78aSPoul-Henning Kamp /* Report or change the active timecounter hardware. */ 4686b6ef746SBruce Evans static int 46982d9ae4eSPoul-Henning Kamp sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) 4706b6ef746SBruce Evans { 4716b6ef746SBruce Evans char newname[32]; 4726b6ef746SBruce Evans struct timecounter *newtc, *tc; 4736b6ef746SBruce Evans int error; 4746b6ef746SBruce Evans 47562efba6aSPoul-Henning Kamp tc = timecounter; 476e80fb434SRobert Drehmel strlcpy(newname, tc->tc_name, sizeof(newname)); 477e80fb434SRobert Drehmel 4786b6ef746SBruce Evans error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); 47939acc78aSPoul-Henning Kamp if (error != 0 || req->newptr == NULL || 48039acc78aSPoul-Henning Kamp strcmp(newname, tc->tc_name) == 0) 48162efba6aSPoul-Henning Kamp return (error); 48262efba6aSPoul-Henning Kamp for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) { 48339acc78aSPoul-Henning Kamp if (strcmp(newname, newtc->tc_name) != 0) 48462efba6aSPoul-Henning Kamp continue; 48539acc78aSPoul-Henning Kamp 4866b6ef746SBruce Evans /* Warm up new timecounter. */ 4876b6ef746SBruce Evans (void)newtc->tc_get_timecount(newtc); 48862efba6aSPoul-Henning Kamp (void)newtc->tc_get_timecount(newtc); 48939acc78aSPoul-Henning Kamp 49062efba6aSPoul-Henning Kamp timecounter = newtc; 4916b6ef746SBruce Evans return (0); 4926b6ef746SBruce Evans } 4936b6ef746SBruce Evans return (EINVAL); 4946b6ef746SBruce Evans } 4956b6ef746SBruce Evans 4966b6ef746SBruce Evans SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, 4976b6ef746SBruce Evans 0, 0, sysctl_kern_timecounter_hardware, "A", ""); 4986b6ef746SBruce Evans 49939acc78aSPoul-Henning Kamp /* 5006b00cf46SPoul-Henning Kamp * RFC 2783 PPS-API implementation. 5016b00cf46SPoul-Henning Kamp */ 5027ec73f64SPoul-Henning Kamp 50332c20357SPoul-Henning Kamp int 50432c20357SPoul-Henning Kamp pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) 50532c20357SPoul-Henning Kamp { 50632c20357SPoul-Henning Kamp pps_params_t *app; 507b7424f2dSJohn Hay struct pps_fetch_args *fapi; 508de3f8889SPeter Wemm #ifdef PPS_SYNC 509b7424f2dSJohn Hay struct pps_kcbind_args *kapi; 510de3f8889SPeter Wemm #endif 51132c20357SPoul-Henning Kamp 51232c20357SPoul-Henning Kamp switch (cmd) { 51332c20357SPoul-Henning Kamp case PPS_IOC_CREATE: 51432c20357SPoul-Henning Kamp return (0); 51532c20357SPoul-Henning Kamp case PPS_IOC_DESTROY: 51632c20357SPoul-Henning Kamp return (0); 51732c20357SPoul-Henning Kamp case PPS_IOC_SETPARAMS: 51832c20357SPoul-Henning Kamp app = (pps_params_t *)data; 51932c20357SPoul-Henning Kamp if (app->mode & ~pps->ppscap) 52032c20357SPoul-Henning Kamp return (EINVAL); 52132c20357SPoul-Henning Kamp pps->ppsparam = *app; 52232c20357SPoul-Henning Kamp return (0); 52332c20357SPoul-Henning Kamp case PPS_IOC_GETPARAMS: 52432c20357SPoul-Henning Kamp app = (pps_params_t *)data; 52532c20357SPoul-Henning Kamp *app = pps->ppsparam; 526b7424f2dSJohn Hay app->api_version = PPS_API_VERS_1; 52732c20357SPoul-Henning Kamp return (0); 52832c20357SPoul-Henning Kamp case PPS_IOC_GETCAP: 52932c20357SPoul-Henning Kamp *(int*)data = pps->ppscap; 53032c20357SPoul-Henning Kamp return (0); 53132c20357SPoul-Henning Kamp case PPS_IOC_FETCH: 532b7424f2dSJohn Hay fapi = (struct pps_fetch_args *)data; 533b7424f2dSJohn Hay if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) 534b7424f2dSJohn Hay return (EINVAL); 535b7424f2dSJohn Hay if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) 53632c20357SPoul-Henning Kamp return (EOPNOTSUPP); 537b7424f2dSJohn Hay pps->ppsinfo.current_mode = pps->ppsparam.mode; 538b7424f2dSJohn Hay fapi->pps_info_buf = pps->ppsinfo; 539b7424f2dSJohn Hay return (0); 540b7424f2dSJohn Hay case PPS_IOC_KCBIND: 541b7424f2dSJohn Hay #ifdef PPS_SYNC 542b7424f2dSJohn Hay kapi = (struct pps_kcbind_args *)data; 543b7424f2dSJohn Hay /* XXX Only root should be able to do this */ 544b7424f2dSJohn Hay if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC) 545b7424f2dSJohn Hay return (EINVAL); 546b7424f2dSJohn Hay if (kapi->kernel_consumer != PPS_KC_HARDPPS) 547b7424f2dSJohn Hay return (EINVAL); 548b7424f2dSJohn Hay if (kapi->edge & ~pps->ppscap) 549b7424f2dSJohn Hay return (EINVAL); 550b7424f2dSJohn Hay pps->kcmode = kapi->edge; 551b7424f2dSJohn Hay return (0); 552b7424f2dSJohn Hay #else 553b7424f2dSJohn Hay return (EOPNOTSUPP); 554b7424f2dSJohn Hay #endif 55532c20357SPoul-Henning Kamp default: 55632c20357SPoul-Henning Kamp return (ENOTTY); 55732c20357SPoul-Henning Kamp } 55832c20357SPoul-Henning Kamp } 55932c20357SPoul-Henning Kamp 56032c20357SPoul-Henning Kamp void 56132c20357SPoul-Henning Kamp pps_init(struct pps_state *pps) 56232c20357SPoul-Henning Kamp { 56332c20357SPoul-Henning Kamp pps->ppscap |= PPS_TSFMT_TSPEC; 56432c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTUREASSERT) 56532c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETASSERT; 56632c20357SPoul-Henning Kamp if (pps->ppscap & PPS_CAPTURECLEAR) 56732c20357SPoul-Henning Kamp pps->ppscap |= PPS_OFFSETCLEAR; 56832c20357SPoul-Henning Kamp } 56932c20357SPoul-Henning Kamp 57032c20357SPoul-Henning Kamp void 5717bf758bfSPoul-Henning Kamp pps_capture(struct pps_state *pps) 5727bf758bfSPoul-Henning Kamp { 5736b00cf46SPoul-Henning Kamp struct timehands *th; 5747bf758bfSPoul-Henning Kamp 5756b00cf46SPoul-Henning Kamp th = timehands; 5766b00cf46SPoul-Henning Kamp pps->capgen = th->th_generation; 5776b00cf46SPoul-Henning Kamp pps->capth = th; 5786b00cf46SPoul-Henning Kamp pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); 5796b00cf46SPoul-Henning Kamp if (pps->capgen != th->th_generation) 5806b00cf46SPoul-Henning Kamp pps->capgen = 0; 5817bf758bfSPoul-Henning Kamp } 5827bf758bfSPoul-Henning Kamp 5837bf758bfSPoul-Henning Kamp void 5847bf758bfSPoul-Henning Kamp pps_event(struct pps_state *pps, int event) 58532c20357SPoul-Henning Kamp { 58639acc78aSPoul-Henning Kamp struct bintime bt; 58732c20357SPoul-Henning Kamp struct timespec ts, *tsp, *osp; 5886b00cf46SPoul-Henning Kamp u_int tcount, *pcount; 58932c20357SPoul-Henning Kamp int foff, fhard; 59032c20357SPoul-Henning Kamp pps_seq_t *pseq; 59132c20357SPoul-Henning Kamp 59239acc78aSPoul-Henning Kamp /* If the timecounter was wound up underneath us, bail out. */ 59339acc78aSPoul-Henning Kamp if (pps->capgen == 0 || pps->capgen != pps->capth->th_generation) 5947bf758bfSPoul-Henning Kamp return; 5957bf758bfSPoul-Henning Kamp 59639acc78aSPoul-Henning Kamp /* Things would be easier with arrays. */ 59732c20357SPoul-Henning Kamp if (event == PPS_CAPTUREASSERT) { 59832c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.assert_timestamp; 59932c20357SPoul-Henning Kamp osp = &pps->ppsparam.assert_offset; 60032c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETASSERT; 601b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTUREASSERT; 60232c20357SPoul-Henning Kamp pcount = &pps->ppscount[0]; 60332c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.assert_sequence; 60432c20357SPoul-Henning Kamp } else { 60532c20357SPoul-Henning Kamp tsp = &pps->ppsinfo.clear_timestamp; 60632c20357SPoul-Henning Kamp osp = &pps->ppsparam.clear_offset; 60732c20357SPoul-Henning Kamp foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; 608b7424f2dSJohn Hay fhard = pps->kcmode & PPS_CAPTURECLEAR; 60932c20357SPoul-Henning Kamp pcount = &pps->ppscount[1]; 61032c20357SPoul-Henning Kamp pseq = &pps->ppsinfo.clear_sequence; 61132c20357SPoul-Henning Kamp } 61232c20357SPoul-Henning Kamp 61339acc78aSPoul-Henning Kamp /* 6146b00cf46SPoul-Henning Kamp * If the timecounter changed, we cannot compare the count values, so 6156b00cf46SPoul-Henning Kamp * we have to drop the rest of the PPS-stuff until the next event. 6166b00cf46SPoul-Henning Kamp */ 6176b00cf46SPoul-Henning Kamp if (pps->ppstc != pps->capth->th_counter) { 6186b00cf46SPoul-Henning Kamp pps->ppstc = pps->capth->th_counter; 6197bf758bfSPoul-Henning Kamp *pcount = pps->capcount; 6207bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 62132c20357SPoul-Henning Kamp return; 62232c20357SPoul-Henning Kamp } 62332c20357SPoul-Henning Kamp 62439acc78aSPoul-Henning Kamp /* Return if nothing really happened. */ 6257bf758bfSPoul-Henning Kamp if (*pcount == pps->capcount) 62632c20357SPoul-Henning Kamp return; 62732c20357SPoul-Henning Kamp 62839acc78aSPoul-Henning Kamp /* Convert the count to a timespec. */ 6296b00cf46SPoul-Henning Kamp tcount = pps->capcount - pps->capth->th_offset_count; 6306b00cf46SPoul-Henning Kamp tcount &= pps->capth->th_counter->tc_counter_mask; 6316b00cf46SPoul-Henning Kamp bt = pps->capth->th_offset; 6326b00cf46SPoul-Henning Kamp bintime_addx(&bt, pps->capth->th_scale * tcount); 633eef633a7SPoul-Henning Kamp bintime_add(&bt, &boottimebin); 6342028c0cdSPoul-Henning Kamp bintime2timespec(&bt, &ts); 63532c20357SPoul-Henning Kamp 63639acc78aSPoul-Henning Kamp /* If the timecounter was wound up underneath us, bail out. */ 6376b00cf46SPoul-Henning Kamp if (pps->capgen != pps->capth->th_generation) 6387bf758bfSPoul-Henning Kamp return; 6397bf758bfSPoul-Henning Kamp 6407bf758bfSPoul-Henning Kamp *pcount = pps->capcount; 64132c20357SPoul-Henning Kamp (*pseq)++; 64232c20357SPoul-Henning Kamp *tsp = ts; 64332c20357SPoul-Henning Kamp 64432c20357SPoul-Henning Kamp if (foff) { 64532c20357SPoul-Henning Kamp timespecadd(tsp, osp); 64632c20357SPoul-Henning Kamp if (tsp->tv_nsec < 0) { 64732c20357SPoul-Henning Kamp tsp->tv_nsec += 1000000000; 64832c20357SPoul-Henning Kamp tsp->tv_sec -= 1; 64932c20357SPoul-Henning Kamp } 65032c20357SPoul-Henning Kamp } 65132c20357SPoul-Henning Kamp #ifdef PPS_SYNC 65232c20357SPoul-Henning Kamp if (fhard) { 653ce9fac00SPoul-Henning Kamp u_int64_t scale; 654ce9fac00SPoul-Henning Kamp 65539acc78aSPoul-Henning Kamp /* 6566b00cf46SPoul-Henning Kamp * Feed the NTP PLL/FLL. 657b1e7e201SJohn Hay * The FLL wants to know how many (hardware) nanoseconds 658b1e7e201SJohn Hay * elapsed since the previous event. 6596b00cf46SPoul-Henning Kamp */ 6607bf758bfSPoul-Henning Kamp tcount = pps->capcount - pps->ppscount[2]; 6617bf758bfSPoul-Henning Kamp pps->ppscount[2] = pps->capcount; 6626b00cf46SPoul-Henning Kamp tcount &= pps->capth->th_counter->tc_counter_mask; 663b1e7e201SJohn Hay scale = (u_int64_t)1 << 63; 664b1e7e201SJohn Hay scale /= pps->capth->th_counter->tc_frequency; 665b1e7e201SJohn Hay scale *= 2; 6662028c0cdSPoul-Henning Kamp bt.sec = 0; 6672028c0cdSPoul-Henning Kamp bt.frac = 0; 668b1e7e201SJohn Hay bintime_addx(&bt, scale * tcount); 6692028c0cdSPoul-Henning Kamp bintime2timespec(&bt, &ts); 6702028c0cdSPoul-Henning Kamp hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec); 67132c20357SPoul-Henning Kamp } 67232c20357SPoul-Henning Kamp #endif 67332c20357SPoul-Henning Kamp } 6749e1b5510SPoul-Henning Kamp 67539acc78aSPoul-Henning Kamp /* 6769e1b5510SPoul-Henning Kamp * Timecounters need to be updated every so often to prevent the hardware 6779e1b5510SPoul-Henning Kamp * counter from overflowing. Updating also recalculates the cached values 6789e1b5510SPoul-Henning Kamp * used by the get*() family of functions, so their precision depends on 6799e1b5510SPoul-Henning Kamp * the update frequency. 6809e1b5510SPoul-Henning Kamp */ 6819e1b5510SPoul-Henning Kamp 6829e1b5510SPoul-Henning Kamp static int tc_tick; 683b3ed130cSPoul-Henning Kamp SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, ""); 6849e1b5510SPoul-Henning Kamp 685e7fa55afSPoul-Henning Kamp void 686e7fa55afSPoul-Henning Kamp tc_ticktock(void) 6879e1b5510SPoul-Henning Kamp { 688e7fa55afSPoul-Henning Kamp static int count; 6899e1b5510SPoul-Henning Kamp 690e7fa55afSPoul-Henning Kamp if (++count < tc_tick) 691e7fa55afSPoul-Henning Kamp return; 692e7fa55afSPoul-Henning Kamp count = 0; 6939e1b5510SPoul-Henning Kamp tc_windup(); 6949e1b5510SPoul-Henning Kamp } 6959e1b5510SPoul-Henning Kamp 6969e1b5510SPoul-Henning Kamp static void 6979e1b5510SPoul-Henning Kamp inittimecounter(void *dummy) 6989e1b5510SPoul-Henning Kamp { 6999e1b5510SPoul-Henning Kamp u_int p; 7009e1b5510SPoul-Henning Kamp 70139acc78aSPoul-Henning Kamp /* 70239acc78aSPoul-Henning Kamp * Set the initial timeout to 70339acc78aSPoul-Henning Kamp * max(1, <approx. number of hardclock ticks in a millisecond>). 70439acc78aSPoul-Henning Kamp * People should probably not use the sysctl to set the timeout 70539acc78aSPoul-Henning Kamp * to smaller than its inital value, since that value is the 70639acc78aSPoul-Henning Kamp * smallest reasonable one. If they want better timestamps they 70739acc78aSPoul-Henning Kamp * should use the non-"get"* functions. 70839acc78aSPoul-Henning Kamp */ 7099e1b5510SPoul-Henning Kamp if (hz > 1000) 7109e1b5510SPoul-Henning Kamp tc_tick = (hz + 500) / 1000; 7119e1b5510SPoul-Henning Kamp else 7129e1b5510SPoul-Henning Kamp tc_tick = 1; 7139e1b5510SPoul-Henning Kamp p = (tc_tick * 1000000) / hz; 7149e1b5510SPoul-Henning Kamp printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); 71539acc78aSPoul-Henning Kamp 71648e5da55SPoul-Henning Kamp /* warm up new timecounter (again) and get rolling. */ 71739acc78aSPoul-Henning Kamp (void)timecounter->tc_get_timecount(timecounter); 71839acc78aSPoul-Henning Kamp (void)timecounter->tc_get_timecount(timecounter); 7199e1b5510SPoul-Henning Kamp } 7209e1b5510SPoul-Henning Kamp 721ff292556SPeter Wemm SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL) 722