1 /* $OpenBSD: clock.c,v 1.42 2009/01/29 13:36:17 kettenis Exp $ */ 2 /* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */ 3 4 /*- 5 * Copyright (c) 1993, 1994 Charles Hannum. 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * William Jolitz and Don Ahn. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)clock.c 7.2 (Berkeley) 5/12/91 37 */ 38 /* 39 * Mach Operating System 40 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 41 * All Rights Reserved. 42 * 43 * Permission to use, copy, modify and distribute this software and its 44 * documentation is hereby granted, provided that both the copyright 45 * notice and this permission notice appear in all copies of the 46 * software, derivative works or modified versions, and any portions 47 * thereof, and that both notices appear in supporting documentation. 48 * 49 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 50 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 51 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 52 * 53 * Carnegie Mellon requests users of this software to return to 54 * 55 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 56 * School of Computer Science 57 * Carnegie Mellon University 58 * Pittsburgh PA 15213-3890 59 * 60 * any improvements or extensions that they make and grant Carnegie Mellon 61 * the rights to redistribute these changes. 62 */ 63 /* 64 Copyright 1988, 1989 by Intel Corporation, Santa Clara, California. 65 66 All Rights Reserved 67 68 Permission to use, copy, modify, and distribute this software and 69 its documentation for any purpose and without fee is hereby 70 granted, provided that the above copyright notice appears in all 71 copies and that both the copyright notice and this permission notice 72 appear in supporting documentation, and that the name of Intel 73 not be used in advertising or publicity pertaining to distribution 74 of the software without specific, written prior permission. 75 76 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 77 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, 78 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 79 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 80 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 81 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 82 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 83 */ 84 85 /* 86 * Primitive clock interrupt routines. 87 */ 88 #include <sys/types.h> 89 #include <sys/param.h> 90 #include <sys/systm.h> 91 #include <sys/time.h> 92 #include <sys/kernel.h> 93 #include <sys/device.h> 94 #include <sys/timeout.h> 95 #include <sys/timetc.h> 96 #include <sys/mutex.h> 97 98 #include <machine/cpu.h> 99 #include <machine/intr.h> 100 #include <machine/pio.h> 101 #include <machine/cpufunc.h> 102 103 #include <dev/isa/isareg.h> 104 #include <dev/isa/isavar.h> 105 #include <dev/ic/mc146818reg.h> 106 #include <dev/ic/i8253reg.h> 107 #include <i386/isa/nvram.h> 108 109 void spinwait(int); 110 int clockintr(void *); 111 int gettick(void); 112 int rtcget(mc_todregs *); 113 void rtcput(mc_todregs *); 114 int hexdectodec(int); 115 int dectohexdec(int); 116 int rtcintr(void *); 117 void rtcdrain(void *); 118 119 u_int mc146818_read(void *, u_int); 120 void mc146818_write(void *, u_int, u_int); 121 122 int cpuspeed; 123 int clock_broken_latch; 124 125 /* Timecounter on the i8254 */ 126 uint32_t i8254_lastcount; 127 uint32_t i8254_offset; 128 int i8254_ticked; 129 u_int i8254_get_timecount(struct timecounter *tc); 130 u_int i8254_simple_get_timecount(struct timecounter *tc); 131 132 static struct timecounter i8254_timecounter = { 133 i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL 134 }; 135 struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH); 136 u_long rtclock_tval; 137 138 #define SECMIN ((unsigned)60) /* seconds per minute */ 139 #define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ 140 141 u_int 142 mc146818_read(void *sc, u_int reg) 143 { 144 int s; 145 u_char v; 146 147 s = splhigh(); 148 outb(IO_RTC, reg); 149 DELAY(1); 150 v = inb(IO_RTC+1); 151 DELAY(1); 152 splx(s); 153 return (v); 154 } 155 156 void 157 mc146818_write(void *sc, u_int reg, u_int datum) 158 { 159 int s; 160 161 s = splhigh(); 162 outb(IO_RTC, reg); 163 DELAY(1); 164 outb(IO_RTC+1, datum); 165 DELAY(1); 166 splx(s); 167 } 168 169 void 170 startrtclock(void) 171 { 172 int s; 173 174 initrtclock(); 175 176 /* Check diagnostic status */ 177 if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) /* XXX softc */ 178 printf("RTC BIOS diagnostic error %b\n", (unsigned int) s, 179 NVRAM_DIAG_BITS); 180 } 181 182 void 183 rtcdrain(void *v) 184 { 185 struct timeout *to = (struct timeout *)v; 186 187 if (to != NULL) 188 timeout_del(to); 189 190 /* 191 * Drain any un-acknowledged RTC interrupts. 192 * See comment in cpu_initclocks(). 193 */ 194 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) 195 ; /* Nothing. */ 196 } 197 198 void 199 initrtclock(void) 200 { 201 mtx_enter(&timer_mutex); 202 203 /* initialize 8253 clock */ 204 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT); 205 206 /* Correct rounding will buy us a better precision in timekeeping */ 207 outb(IO_TIMER1, TIMER_DIV(hz) % 256); 208 outb(IO_TIMER1, TIMER_DIV(hz) / 256); 209 210 rtclock_tval = TIMER_DIV(hz); 211 mtx_leave(&timer_mutex); 212 } 213 214 int 215 clockintr(void *arg) 216 { 217 struct clockframe *frame = arg; /* not strictly necessary */ 218 219 if (timecounter->tc_get_timecount == i8254_get_timecount) { 220 if (i8254_ticked) { 221 i8254_ticked = 0; 222 } else { 223 i8254_offset += rtclock_tval; 224 i8254_lastcount = 0; 225 } 226 } 227 228 hardclock(frame); 229 return (1); 230 } 231 232 int 233 rtcintr(void *arg) 234 { 235 struct clockframe *frame = arg; /* not strictly necessary */ 236 u_int stat = 0; 237 238 if (stathz == 0) { 239 extern int psratio; 240 241 stathz = 128; 242 profhz = 1024; 243 psratio = profhz / stathz; 244 } 245 246 /* 247 * If rtcintr is 'late', next intr may happen immediately. 248 * Get them all. (Also, see comment in cpu_initclocks().) 249 */ 250 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) { 251 statclock(frame); 252 stat = 1; 253 } 254 return (stat); 255 } 256 257 int 258 gettick(void) 259 { 260 261 if (clock_broken_latch) { 262 int v1, v2, v3; 263 int w1, w2, w3; 264 265 /* 266 * Don't lock the mutex in this case, clock_broken_latch 267 * CPUs don't do MP anyway. 268 */ 269 270 disable_intr(); 271 272 v1 = inb(IO_TIMER1 + TIMER_CNTR0); 273 v1 |= inb(IO_TIMER1 + TIMER_CNTR0) << 8; 274 v2 = inb(IO_TIMER1 + TIMER_CNTR0); 275 v2 |= inb(IO_TIMER1 + TIMER_CNTR0) << 8; 276 v3 = inb(IO_TIMER1 + TIMER_CNTR0); 277 v3 |= inb(IO_TIMER1 + TIMER_CNTR0) << 8; 278 279 enable_intr(); 280 281 if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200) 282 return (v2); 283 284 #define _swap_val(a, b) do { \ 285 int c = a; \ 286 a = b; \ 287 b = c; \ 288 } while (0) 289 290 /* sort v1 v2 v3 */ 291 if (v1 < v2) 292 _swap_val(v1, v2); 293 if (v2 < v3) 294 _swap_val(v2, v3); 295 if (v1 < v2) 296 _swap_val(v1, v2); 297 298 /* compute the middle value */ 299 if (v1 - v3 < 0x200) 300 return (v2); 301 w1 = v2 - v3; 302 w2 = v3 - v1 + TIMER_DIV(hz); 303 w3 = v1 - v2; 304 if (w1 >= w2) { 305 if (w1 >= w3) 306 return (v1); 307 } else { 308 if (w2 >= w3) 309 return (v2); 310 } 311 return (v3); 312 } else { 313 u_char lo, hi; 314 u_long ef; 315 316 mtx_enter(&timer_mutex); 317 ef = read_eflags(); 318 disable_intr(); 319 /* Select counter 0 and latch it. */ 320 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 321 lo = inb(IO_TIMER1 + TIMER_CNTR0); 322 hi = inb(IO_TIMER1 + TIMER_CNTR0); 323 324 write_eflags(ef); 325 mtx_leave(&timer_mutex); 326 return ((hi << 8) | lo); 327 } 328 } 329 330 /* 331 * Wait "n" microseconds. 332 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. 333 * Note: timer had better have been programmed before this is first used! 334 * (Note that we use `rate generator' mode, which counts at 1:1; `square 335 * wave' mode counts at 2:1). 336 */ 337 void 338 i8254_delay(int n) 339 { 340 int limit, tick, otick; 341 342 /* 343 * Read the counter first, so that the rest of the setup overhead is 344 * counted. 345 */ 346 otick = gettick(); 347 348 #ifdef __GNUC__ 349 /* 350 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so 351 * we can take advantage of the intermediate 64-bit quantity to prevent 352 * loss of significance. 353 */ 354 n -= 5; 355 if (n < 0) 356 return; 357 __asm __volatile("mul %2\n\tdiv %3" 358 : "=a" (n) 359 : "0" (n), "r" (TIMER_FREQ), "r" (1000000) 360 : "%edx", "cc"); 361 #else 362 /* 363 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and 364 * without any avoidable overflows. 365 */ 366 n -= 20; 367 { 368 int sec = n / 1000000, 369 usec = n % 1000000; 370 n = sec * TIMER_FREQ + 371 usec * (TIMER_FREQ / 1000000) + 372 usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 + 373 usec * (TIMER_FREQ % 1000) / 1000000; 374 } 375 #endif 376 377 limit = TIMER_FREQ / hz; 378 379 while (n > 0) { 380 tick = gettick(); 381 if (tick > otick) 382 n -= limit - (tick - otick); 383 else 384 n -= otick - tick; 385 otick = tick; 386 } 387 } 388 389 void 390 calibrate_cyclecounter(void) 391 { 392 unsigned long long count, last_count; 393 394 __asm __volatile("rdtsc" : "=A" (last_count)); 395 delay(1000000); 396 __asm __volatile("rdtsc" : "=A" (count)); 397 cpuspeed = ((count - last_count) + 999999) / 1000000; 398 } 399 400 void 401 i8254_initclocks(void) 402 { 403 static struct timeout rtcdrain_timeout; 404 405 /* 406 * XXX If you're doing strange things with multiple clocks, you might 407 * want to keep track of clock handlers. 408 */ 409 (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr, 410 0, "clock"); 411 (void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr, 412 0, "rtc"); 413 414 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); 415 mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE); 416 417 /* 418 * On a number of i386 systems, the rtc will fail to start when booting 419 * the system. This is due to us missing to acknowledge an interrupt 420 * during early stages of the boot process. If we do not acknowledge 421 * the interrupt, the rtc clock will not generate further interrupts. 422 * To solve this, once interrupts are enabled, use a timeout (once) 423 * to drain any un-acknowledged rtc interrupt(s). 424 */ 425 426 timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout); 427 timeout_add(&rtcdrain_timeout, 1); 428 } 429 430 int 431 rtcget(mc_todregs *regs) 432 { 433 if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */ 434 return (-1); 435 MC146818_GETTOD(NULL, regs); /* XXX softc */ 436 return (0); 437 } 438 439 void 440 rtcput(mc_todregs *regs) 441 { 442 MC146818_PUTTOD(NULL, regs); /* XXX softc */ 443 } 444 445 int 446 hexdectodec(int n) 447 { 448 449 return (((n >> 4) & 0x0f) * 10 + (n & 0x0f)); 450 } 451 452 int 453 dectohexdec(int n) 454 { 455 456 return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f)); 457 } 458 459 static int timeset; 460 461 /* 462 * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), 463 * to be called at splclock() 464 */ 465 int cmoscheck(void); 466 int 467 cmoscheck(void) 468 { 469 int i; 470 unsigned short cksum = 0; 471 472 for (i = 0x10; i <= 0x2d; i++) 473 cksum += mc146818_read(NULL, i); /* XXX softc */ 474 475 return (cksum == (mc146818_read(NULL, 0x2e) << 8) 476 + mc146818_read(NULL, 0x2f)); 477 } 478 479 /* 480 * patchable to control century byte handling: 481 * 1: always update 482 * -1: never touch 483 * 0: try to figure out itself 484 */ 485 int rtc_update_century = 0; 486 487 /* 488 * Expand a two-digit year as read from the clock chip 489 * into full width. 490 * Being here, deal with the CMOS century byte. 491 */ 492 int clock_expandyear(int); 493 int 494 clock_expandyear(int clockyear) 495 { 496 int s, clockcentury, cmoscentury; 497 498 clockcentury = (clockyear < 70) ? 20 : 19; 499 clockyear += 100 * clockcentury; 500 501 if (rtc_update_century < 0) 502 return (clockyear); 503 504 s = splclock(); 505 if (cmoscheck()) 506 cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); 507 else 508 cmoscentury = 0; 509 splx(s); 510 if (!cmoscentury) { 511 #ifdef DIAGNOSTIC 512 printf("clock: unknown CMOS layout\n"); 513 #endif 514 return (clockyear); 515 } 516 cmoscentury = hexdectodec(cmoscentury); 517 518 if (cmoscentury != clockcentury) { 519 /* XXX note: saying "century is 20" might confuse the naive. */ 520 printf("WARNING: NVRAM century is %d but RTC year is %d\n", 521 cmoscentury, clockyear); 522 523 /* Kludge to roll over century. */ 524 if ((rtc_update_century > 0) || 525 ((cmoscentury == 19) && (clockcentury == 20) && 526 (clockyear == 2000))) { 527 printf("WARNING: Setting NVRAM century to %d\n", 528 clockcentury); 529 s = splclock(); 530 mc146818_write(NULL, NVRAM_CENTURY, 531 dectohexdec(clockcentury)); 532 splx(s); 533 } 534 } else if (cmoscentury == 19 && rtc_update_century == 0) 535 rtc_update_century = 1; /* will update later in resettodr() */ 536 537 return (clockyear); 538 } 539 540 /* 541 * Initialize the time of day register, based on the time base which is, e.g. 542 * from a filesystem. 543 */ 544 void 545 inittodr(time_t base) 546 { 547 struct timespec ts; 548 mc_todregs rtclk; 549 struct clock_ymdhms dt; 550 int s; 551 552 553 ts.tv_nsec = 0; 554 555 /* 556 * We mostly ignore the suggested time and go for the RTC clock time 557 * stored in the CMOS RAM. If the time can't be obtained from the 558 * CMOS, or if the time obtained from the CMOS is 5 or more years 559 * less than the suggested time, we used the suggested time. (In 560 * the latter case, it's likely that the CMOS battery has died.) 561 */ 562 563 if (base < 15*SECYR) { /* if before 1985, something's odd... */ 564 printf("WARNING: preposterous time in file system\n"); 565 /* read the system clock anyway */ 566 base = 17*SECYR + 186*SECDAY + SECDAY/2; 567 } 568 569 s = splclock(); 570 if (rtcget(&rtclk)) { 571 splx(s); 572 printf("WARNING: invalid time in clock chip\n"); 573 goto fstime; 574 } 575 splx(s); 576 577 dt.dt_sec = hexdectodec(rtclk[MC_SEC]); 578 dt.dt_min = hexdectodec(rtclk[MC_MIN]); 579 dt.dt_hour = hexdectodec(rtclk[MC_HOUR]); 580 dt.dt_day = hexdectodec(rtclk[MC_DOM]); 581 dt.dt_mon = hexdectodec(rtclk[MC_MONTH]); 582 dt.dt_year = clock_expandyear(hexdectodec(rtclk[MC_YEAR])); 583 584 585 /* 586 * If time_t is 32 bits, then the "End of Time" is 587 * Mon Jan 18 22:14:07 2038 (US/Eastern) 588 * This code copes with RTC's past the end of time if time_t 589 * is an int32 or less. Needed because sometimes RTCs screw 590 * up or are badly set, and that would cause the time to go 591 * negative in the calculation below, which causes Very Bad 592 * Mojo. This at least lets the user boot and fix the problem. 593 * Note the code is self eliminating once time_t goes to 64 bits. 594 */ 595 if (sizeof(time_t) <= sizeof(int32_t)) { 596 if (dt.dt_year >= 2038) { 597 printf("WARNING: RTC time at or beyond 2038.\n"); 598 dt.dt_year = 2037; 599 printf("WARNING: year set back to 2037.\n"); 600 printf("WARNING: CHECK AND RESET THE DATE!\n"); 601 } 602 } 603 604 ts.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60; 605 if (tz.tz_dsttime) 606 ts.tv_sec -= 3600; 607 608 if (base < ts.tv_sec - 5*SECYR) 609 printf("WARNING: file system time much less than clock time\n"); 610 else if (base > ts.tv_sec + 5*SECYR) { 611 printf("WARNING: clock time much less than file system time\n"); 612 printf("WARNING: using file system time\n"); 613 goto fstime; 614 } 615 616 tc_setclock(&ts); 617 timeset = 1; 618 return; 619 620 fstime: 621 ts.tv_sec = base; 622 tc_setclock(&ts); 623 timeset = 1; 624 printf("WARNING: CHECK AND RESET THE DATE!\n"); 625 } 626 627 /* 628 * Reset the clock. 629 */ 630 void 631 resettodr(void) 632 { 633 mc_todregs rtclk; 634 struct clock_ymdhms dt; 635 int diff; 636 int century; 637 int s; 638 639 /* 640 * We might have been called by boot() due to a crash early 641 * on. Don't reset the clock chip in this case. 642 */ 643 if (!timeset) 644 return; 645 646 s = splclock(); 647 if (rtcget(&rtclk)) 648 bzero(&rtclk, sizeof(rtclk)); 649 splx(s); 650 651 diff = tz.tz_minuteswest * 60; 652 if (tz.tz_dsttime) 653 diff -= 3600; 654 clock_secs_to_ymdhms(time_second - diff, &dt); 655 656 rtclk[MC_SEC] = dectohexdec(dt.dt_sec); 657 rtclk[MC_MIN] = dectohexdec(dt.dt_min); 658 rtclk[MC_HOUR] = dectohexdec(dt.dt_hour); 659 rtclk[MC_DOW] = dt.dt_wday; 660 rtclk[MC_YEAR] = dectohexdec(dt.dt_year % 100); 661 rtclk[MC_MONTH] = dectohexdec(dt.dt_mon); 662 rtclk[MC_DOM] = dectohexdec(dt.dt_day); 663 s = splclock(); 664 rtcput(&rtclk); 665 if (rtc_update_century > 0) { 666 century = dectohexdec(dt.dt_year / 100); 667 mc146818_write(NULL, NVRAM_CENTURY, century); /* XXX softc */ 668 } 669 splx(s); 670 } 671 672 void 673 setstatclockrate(int arg) 674 { 675 if (arg == stathz) 676 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); 677 else 678 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz); 679 } 680 681 void 682 i8254_inittimecounter(void) 683 { 684 tc_init(&i8254_timecounter); 685 } 686 687 /* 688 * If we're using lapic to drive hardclock, we can use a simpler 689 * algorithm for the i8254 timecounters. 690 */ 691 void 692 i8254_inittimecounter_simple(void) 693 { 694 u_long tval = 0x8000; 695 696 i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount; 697 i8254_timecounter.tc_counter_mask = 0x7fff; 698 699 i8254_timecounter.tc_frequency = TIMER_FREQ; 700 701 mtx_enter(&timer_mutex); 702 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 703 outb(IO_TIMER1, tval & 0xff); 704 outb(IO_TIMER1, tval >> 8); 705 706 rtclock_tval = tval; 707 mtx_leave(&timer_mutex); 708 709 tc_init(&i8254_timecounter); 710 } 711 712 u_int 713 i8254_simple_get_timecount(struct timecounter *tc) 714 { 715 return (rtclock_tval - gettick()); 716 } 717 718 u_int 719 i8254_get_timecount(struct timecounter *tc) 720 { 721 u_char hi, lo; 722 u_int count; 723 u_long ef; 724 725 ef = read_eflags(); 726 disable_intr(); 727 728 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 729 lo = inb(IO_TIMER1 + TIMER_CNTR0); 730 hi = inb(IO_TIMER1 + TIMER_CNTR0); 731 732 count = rtclock_tval - ((hi << 8) | lo); 733 734 if (count < i8254_lastcount) { 735 i8254_ticked = 1; 736 i8254_offset += rtclock_tval; 737 } 738 i8254_lastcount = count; 739 count += i8254_offset; 740 write_eflags(ef); 741 742 return (count); 743 } 744