kern_tc.c revision 95549
1/* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 * 9 * $FreeBSD: head/sys/kern/kern_tc.c 95549 2002-04-27 07:06:52Z phk $ 10 */ 11 12#include "opt_ntp.h" 13 14#include <sys/param.h> 15#include <sys/timetc.h> 16#include <sys/kernel.h> 17#include <sys/sysctl.h> 18#include <sys/systm.h> 19#include <sys/timex.h> 20#include <sys/timepps.h> 21 22/* 23 * Implement a dummy timecounter which we can use until we get a real one 24 * in the air. This allows the console and other early stuff to use 25 * timeservices. 26 */ 27 28static unsigned 29dummy_get_timecount(struct timecounter *tc) 30{ 31 static unsigned now; 32 33 return (++now); 34} 35 36static struct timecounter dummy_timecounter = { 37 dummy_get_timecount, 38 0, 39 ~0u, 40 1000000, 41 "dummy" 42}; 43 44struct timehands { 45 /* These fields must be initialized by the driver. */ 46 struct timecounter *tc_counter; 47 int64_t tc_adjustment; 48 u_int64_t tc_scale; 49 unsigned tc_offset_count; 50 struct bintime tc_offset; 51 struct timeval tc_microtime; 52 struct timespec tc_nanotime; 53 /* Fields not to be copied in tc_windup start with tc_generation */ 54 volatile unsigned tc_generation; 55 struct timehands *tc_next; 56}; 57 58 59extern struct timehands th0; 60static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th0}; 61static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th9}; 62static struct timehands th7 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th8}; 63static struct timehands th6 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th7}; 64static struct timehands th5 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th6}; 65static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th5}; 66static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th4}; 67static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th3}; 68static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 1, &th2}; 69static struct timehands th0 = 70 { &dummy_timecounter, 0, 18446744073709ULL, 0, {1, 0}, {0, 0}, {0, 0}, 1, &th1}; 71 72static struct timehands *volatile timehands = &th0; 73struct timecounter *timecounter = &dummy_timecounter; 74static struct timecounter *timecounters = &dummy_timecounter; 75 76time_t time_second; 77 78struct bintime boottimebin; 79struct timeval boottime; 80SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD, 81 &boottime, timeval, "System boottime"); 82 83SYSCTL_NODE(_kern, OID_AUTO, timecounter, CTLFLAG_RW, 0, ""); 84 85#define TC_STATS(foo) \ 86 static unsigned foo; \ 87 SYSCTL_INT(_kern_timecounter, OID_AUTO, foo, CTLFLAG_RD, & foo, 0, "") 88 89TC_STATS(nbinuptime); TC_STATS(nnanouptime); TC_STATS(nmicrouptime); 90TC_STATS(nbintime); TC_STATS(nnanotime); TC_STATS(nmicrotime); 91TC_STATS(ngetbinuptime); TC_STATS(ngetnanouptime); TC_STATS(ngetmicrouptime); 92TC_STATS(ngetbintime); TC_STATS(ngetnanotime); TC_STATS(ngetmicrotime); 93 94#undef TC_STATS 95 96static void tc_windup(void); 97 98 99static __inline unsigned 100tc_delta(struct timehands *tc) 101{ 102 103 return ((tc->tc_counter->tc_get_timecount(tc->tc_counter) - 104 tc->tc_offset_count) & tc->tc_counter->tc_counter_mask); 105} 106 107void 108binuptime(struct bintime *bt) 109{ 110 struct timehands *tc; 111 unsigned gen; 112 113 nbinuptime++; 114 do { 115 tc = timehands; 116 gen = tc->tc_generation; 117 *bt = tc->tc_offset; 118 bintime_addx(bt, tc->tc_scale * tc_delta(tc)); 119 } while (gen == 0 || gen != tc->tc_generation); 120} 121 122void 123nanouptime(struct timespec *ts) 124{ 125 struct bintime bt; 126 127 nnanouptime++; 128 binuptime(&bt); 129 bintime2timespec(&bt, ts); 130} 131 132void 133microuptime(struct timeval *tv) 134{ 135 struct bintime bt; 136 137 nmicrouptime++; 138 binuptime(&bt); 139 bintime2timeval(&bt, tv); 140} 141 142void 143bintime(struct bintime *bt) 144{ 145 146 nbintime++; 147 binuptime(bt); 148 bintime_add(bt, &boottimebin); 149} 150 151void 152nanotime(struct timespec *ts) 153{ 154 struct bintime bt; 155 156 nnanotime++; 157 bintime(&bt); 158 bintime2timespec(&bt, ts); 159} 160 161void 162microtime(struct timeval *tv) 163{ 164 struct bintime bt; 165 166 nmicrotime++; 167 bintime(&bt); 168 bintime2timeval(&bt, tv); 169} 170 171void 172getbinuptime(struct bintime *bt) 173{ 174 struct timehands *tc; 175 unsigned gen; 176 177 ngetbinuptime++; 178 do { 179 tc = timehands; 180 gen = tc->tc_generation; 181 *bt = tc->tc_offset; 182 } while (gen == 0 || gen != tc->tc_generation); 183} 184 185void 186getnanouptime(struct timespec *tsp) 187{ 188 struct timehands *tc; 189 unsigned gen; 190 191 ngetnanouptime++; 192 do { 193 tc = timehands; 194 gen = tc->tc_generation; 195 bintime2timespec(&tc->tc_offset, tsp); 196 } while (gen == 0 || gen != tc->tc_generation); 197} 198 199void 200getmicrouptime(struct timeval *tvp) 201{ 202 struct timehands *tc; 203 unsigned gen; 204 205 ngetmicrouptime++; 206 do { 207 tc = timehands; 208 gen = tc->tc_generation; 209 bintime2timeval(&tc->tc_offset, tvp); 210 } while (gen == 0 || gen != tc->tc_generation); 211} 212 213void 214getbintime(struct bintime *bt) 215{ 216 struct timehands *tc; 217 unsigned gen; 218 219 ngetbintime++; 220 do { 221 tc = timehands; 222 gen = tc->tc_generation; 223 *bt = tc->tc_offset; 224 } while (gen == 0 || gen != tc->tc_generation); 225 bintime_add(bt, &boottimebin); 226} 227 228void 229getnanotime(struct timespec *tsp) 230{ 231 struct timehands *tc; 232 unsigned gen; 233 234 ngetnanotime++; 235 do { 236 tc = timehands; 237 gen = tc->tc_generation; 238 *tsp = tc->tc_nanotime; 239 } while (gen == 0 || gen != tc->tc_generation); 240} 241 242void 243getmicrotime(struct timeval *tvp) 244{ 245 struct timehands *tc; 246 unsigned gen; 247 248 ngetmicrotime++; 249 do { 250 tc = timehands; 251 gen = tc->tc_generation; 252 *tvp = tc->tc_microtime; 253 } while (gen == 0 || gen != tc->tc_generation); 254} 255 256static void 257tc_setscales(struct timehands *tc) 258{ 259 u_int64_t scale; 260 261 /* Sacrifice the lower bit to the deity for code clarity */ 262 scale = 1ULL << 63; 263 /* 264 * We get nanoseconds with 32 bit binary fraction and want 265 * 64 bit binary fraction: x = a * 2^32 / 10^9 = a * 4.294967296 266 * The range is +/- 5000PPM so we can only multiply by about 850 267 * without overflowing. The best suitable fraction is 2199/512. 268 * Divide by 2 times 512 to match the temporary lower precision. 269 */ 270 scale += (tc->tc_adjustment / 1024) * 2199; 271 scale /= tc->tc_counter->tc_frequency; 272 tc->tc_scale = scale * 2; 273} 274 275void 276tc_init(struct timecounter *tc) 277{ 278 279 tc->tc_next = timecounters; 280 timecounters = tc; 281 printf("Timecounter \"%s\" frequency %lu Hz\n", 282 tc->tc_name, (u_long)tc->tc_frequency); 283 timecounter = tc; 284} 285 286u_int32_t 287tc_getfrequency(void) 288{ 289 290 return (timehands->tc_counter->tc_frequency); 291} 292 293void 294tc_setclock(struct timespec *ts) 295{ 296 struct timespec ts2; 297 298 nanouptime(&ts2); 299 boottime.tv_sec = ts->tv_sec - ts2.tv_sec; 300 boottime.tv_usec = (ts->tv_nsec - ts2.tv_nsec) / 1000; 301 if (boottime.tv_usec < 0) { 302 boottime.tv_usec += 1000000; 303 boottime.tv_sec--; 304 } 305 timeval2bintime(&boottime, &boottimebin); 306 /* fiddle all the little crinkly bits around the fiords... */ 307 tc_windup(); 308} 309 310static void 311tc_windup(void) 312{ 313 struct timehands *tc, *tco; 314 struct bintime bt; 315 unsigned ogen, delta, ncount; 316 int i; 317 318 ncount = 0; /* GCC is lame */ 319 tco = timehands; 320 tc = tco->tc_next; 321 ogen = tc->tc_generation; 322 tc->tc_generation = 0; 323 bcopy(tco, tc, __offsetof(struct timehands, tc_generation)); 324 delta = tc_delta(tc); 325 if (tc->tc_counter != timecounter) 326 ncount = timecounter->tc_get_timecount(timecounter); 327 tc->tc_offset_count += delta; 328 tc->tc_offset_count &= tc->tc_counter->tc_counter_mask; 329 bintime_addx(&tc->tc_offset, tc->tc_scale * delta); 330 /* 331 * We may be inducing a tiny error here, the tc_poll_pps() may 332 * process a latched count which happens after the tc_delta() 333 * in sync_other_counter(), which would extend the previous 334 * counters parameters into the domain of this new one. 335 * Since the timewindow is very small for this, the error is 336 * going to be only a few weenieseconds (as Dave Mills would 337 * say), so lets just not talk more about it, OK ? 338 */ 339 if (tco->tc_counter->tc_poll_pps) 340 tco->tc_counter->tc_poll_pps(tco->tc_counter); 341 for (i = tc->tc_offset.sec - tco->tc_offset.sec; i > 0; i--) 342 ntp_update_second(&tc->tc_adjustment, &tc->tc_offset.sec); 343 tc_setscales(tc); 344 345 bt = tc->tc_offset; 346 bintime_add(&bt, &boottimebin); 347 bintime2timeval(&bt, &tc->tc_microtime); 348 bintime2timespec(&bt, &tc->tc_nanotime); 349 ogen++; 350 if (ogen == 0) 351 ogen++; 352 tc->tc_generation = ogen; 353 time_second = tc->tc_microtime.tv_sec; 354 timehands = tc; 355} 356 357static int 358sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) 359{ 360 char newname[32]; 361 struct timecounter *newtc, *tc; 362 int error; 363 364 tc = timecounter; 365 strncpy(newname, tc->tc_name, sizeof(newname)); 366 error = sysctl_handle_string(oidp, &newname[0], sizeof(newname), req); 367 if (error != 0 && req->newptr == NULL && !strcmp(newname, tc->tc_name)) 368 return(error); 369 for (newtc = timecounters; newtc != NULL; newtc = newtc->tc_next) { 370 if (strcmp(newname, newtc->tc_name)) 371 continue; 372 /* Warm up new timecounter. */ 373 (void)newtc->tc_get_timecount(newtc); 374 (void)newtc->tc_get_timecount(newtc); 375 timecounter = newtc; 376 return (0); 377 } 378 return (EINVAL); 379} 380 381SYSCTL_PROC(_kern_timecounter, OID_AUTO, hardware, CTLTYPE_STRING | CTLFLAG_RW, 382 0, 0, sysctl_kern_timecounter_hardware, "A", ""); 383 384 385int 386pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) 387{ 388 pps_params_t *app; 389 struct pps_fetch_args *fapi; 390#ifdef PPS_SYNC 391 struct pps_kcbind_args *kapi; 392#endif 393 394 switch (cmd) { 395 case PPS_IOC_CREATE: 396 return (0); 397 case PPS_IOC_DESTROY: 398 return (0); 399 case PPS_IOC_SETPARAMS: 400 app = (pps_params_t *)data; 401 if (app->mode & ~pps->ppscap) 402 return (EINVAL); 403 pps->ppsparam = *app; 404 return (0); 405 case PPS_IOC_GETPARAMS: 406 app = (pps_params_t *)data; 407 *app = pps->ppsparam; 408 app->api_version = PPS_API_VERS_1; 409 return (0); 410 case PPS_IOC_GETCAP: 411 *(int*)data = pps->ppscap; 412 return (0); 413 case PPS_IOC_FETCH: 414 fapi = (struct pps_fetch_args *)data; 415 if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) 416 return (EINVAL); 417 if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) 418 return (EOPNOTSUPP); 419 pps->ppsinfo.current_mode = pps->ppsparam.mode; 420 fapi->pps_info_buf = pps->ppsinfo; 421 return (0); 422 case PPS_IOC_KCBIND: 423#ifdef PPS_SYNC 424 kapi = (struct pps_kcbind_args *)data; 425 /* XXX Only root should be able to do this */ 426 if (kapi->tsformat && kapi->tsformat != PPS_TSFMT_TSPEC) 427 return (EINVAL); 428 if (kapi->kernel_consumer != PPS_KC_HARDPPS) 429 return (EINVAL); 430 if (kapi->edge & ~pps->ppscap) 431 return (EINVAL); 432 pps->kcmode = kapi->edge; 433 return (0); 434#else 435 return (EOPNOTSUPP); 436#endif 437 default: 438 return (ENOTTY); 439 } 440} 441 442void 443pps_init(struct pps_state *pps) 444{ 445 pps->ppscap |= PPS_TSFMT_TSPEC; 446 if (pps->ppscap & PPS_CAPTUREASSERT) 447 pps->ppscap |= PPS_OFFSETASSERT; 448 if (pps->ppscap & PPS_CAPTURECLEAR) 449 pps->ppscap |= PPS_OFFSETCLEAR; 450} 451 452void 453pps_capture(struct pps_state *pps) 454{ 455 struct timehands *tc; 456 457 tc = timehands; 458 pps->captc = tc; 459 pps->capgen = tc->tc_generation; 460 pps->capcount = tc->tc_counter->tc_get_timecount(tc->tc_counter); 461} 462 463void 464pps_event(struct pps_state *pps, int event) 465{ 466 struct timespec ts, *tsp, *osp; 467 unsigned tcount, *pcount; 468 struct bintime bt; 469 int foff, fhard; 470 pps_seq_t *pseq; 471 472 /* If the timecounter were wound up, bail. */ 473 if (pps->capgen != pps->capgen) 474 return; 475 476 /* Things would be easier with arrays... */ 477 if (event == PPS_CAPTUREASSERT) { 478 tsp = &pps->ppsinfo.assert_timestamp; 479 osp = &pps->ppsparam.assert_offset; 480 foff = pps->ppsparam.mode & PPS_OFFSETASSERT; 481 fhard = pps->kcmode & PPS_CAPTUREASSERT; 482 pcount = &pps->ppscount[0]; 483 pseq = &pps->ppsinfo.assert_sequence; 484 } else { 485 tsp = &pps->ppsinfo.clear_timestamp; 486 osp = &pps->ppsparam.clear_offset; 487 foff = pps->ppsparam.mode & PPS_OFFSETCLEAR; 488 fhard = pps->kcmode & PPS_CAPTURECLEAR; 489 pcount = &pps->ppscount[1]; 490 pseq = &pps->ppsinfo.clear_sequence; 491 } 492 493 /* The timecounter changed: bail */ 494 if (!pps->ppstc || 495 pps->ppstc != pps->captc->tc_counter || 496 pps->captc->tc_counter != timehands->tc_counter) { 497 pps->ppstc = pps->captc->tc_counter; 498 *pcount = pps->capcount; 499#ifdef PPS_SYNC 500 pps->ppscount[2] = pps->capcount; 501#endif 502 return; 503 } 504 505 /* Nothing really happened */ 506 if (*pcount == pps->capcount) 507 return; 508 509 /* Convert the count to timespec */ 510 tcount = pps->capcount - pps->captc->tc_offset_count; 511 tcount &= pps->captc->tc_counter->tc_counter_mask; 512 bt = pps->captc->tc_offset; 513 bintime_addx(&bt, pps->captc->tc_scale * tcount); 514 bintime2timespec(&bt, &ts); 515 516 /* If the timecounter were wound up, bail. */ 517 if (pps->capgen != pps->capgen) 518 return; 519 520 *pcount = pps->capcount; 521 (*pseq)++; 522 *tsp = ts; 523 524 if (foff) { 525 timespecadd(tsp, osp); 526 if (tsp->tv_nsec < 0) { 527 tsp->tv_nsec += 1000000000; 528 tsp->tv_sec -= 1; 529 } 530 } 531#ifdef PPS_SYNC 532 if (fhard) { 533 /* magic, at its best... */ 534 tcount = pps->capcount - pps->ppscount[2]; 535 pps->ppscount[2] = pps->capcount; 536 tcount &= pps->captc->tc_counter->tc_counter_mask; 537 bt.sec = 0; 538 bt.frac = 0; 539 bintime_addx(&bt, pps->captc->tc_scale * tcount); 540 bintime2timespec(&bt, &ts); 541 hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec); 542 } 543#endif 544} 545 546/*- 547 * Timecounters need to be updated every so often to prevent the hardware 548 * counter from overflowing. Updating also recalculates the cached values 549 * used by the get*() family of functions, so their precision depends on 550 * the update frequency. 551 * Don't update faster than approx once per millisecond, if people want 552 * better timestamps they should use the non-"get" functions. 553 */ 554 555static int tc_tick; 556SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tick, 0, ""); 557 558static void 559tc_ticktock(void *dummy) 560{ 561 562 tc_windup(); 563 timeout(tc_ticktock, NULL, tc_tick); 564} 565 566static void 567inittimecounter(void *dummy) 568{ 569 u_int p; 570 571 if (hz > 1000) 572 tc_tick = (hz + 500) / 1000; 573 else 574 tc_tick = 1; 575 p = (tc_tick * 1000000) / hz; 576 printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); 577 tc_ticktock(NULL); 578} 579 580SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_FIRST, inittimecounter, NULL) 581