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