1 /* $OpenBSD: clock.c,v 1.21 2014/03/29 18:09:28 guenther Exp $ */ 2 /* $NetBSD: clock.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */ 3 4 /*- 5 * Copyright (c) 1993, 1994 Charles M. 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 89 /* #define CLOCKDEBUG */ 90 /* #define CLOCK_PARANOIA */ 91 92 #include <sys/param.h> 93 #include <sys/systm.h> 94 #include <sys/time.h> 95 #include <sys/kernel.h> 96 #include <sys/device.h> 97 #include <sys/timeout.h> 98 #include <sys/timetc.h> 99 100 #include <machine/cpu.h> 101 #include <machine/intr.h> 102 #include <machine/pio.h> 103 #include <machine/cpufunc.h> 104 105 #include <dev/isa/isareg.h> 106 #include <dev/isa/isavar.h> 107 #include <dev/ic/mc146818reg.h> 108 #include <dev/ic/i8253reg.h> 109 #include <amd64/isa/nvram.h> 110 #include <dev/clock_subr.h> 111 #include <machine/specialreg.h> 112 113 /* Timecounter on the i8254 */ 114 u_int32_t i8254_lastcount; 115 u_int32_t i8254_offset; 116 int i8254_ticked; 117 u_int i8254_get_timecount(struct timecounter *tc); 118 119 u_int i8254_simple_get_timecount(struct timecounter *tc); 120 121 static struct timecounter i8254_timecounter = { 122 i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL 123 }; 124 125 int clockintr(void *); 126 int rtcintr(void *); 127 int gettick(void); 128 void rtcdrain(void *v); 129 int rtcget(mc_todregs *); 130 void rtcput(mc_todregs *); 131 int bcdtobin(int); 132 int bintobcd(int); 133 134 u_int mc146818_read(void *, u_int); 135 void mc146818_write(void *, u_int, u_int); 136 137 u_int 138 mc146818_read(void *sc, u_int reg) 139 { 140 outb(IO_RTC, reg); 141 DELAY(1); 142 return (inb(IO_RTC+1)); 143 } 144 145 void 146 mc146818_write(void *sc, u_int reg, u_int datum) 147 { 148 outb(IO_RTC, reg); 149 DELAY(1); 150 outb(IO_RTC+1, datum); 151 DELAY(1); 152 } 153 154 struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH); 155 156 u_long rtclock_tval; 157 158 void 159 startclocks(void) 160 { 161 int s; 162 163 mtx_enter(&timer_mutex); 164 rtclock_tval = TIMER_DIV(hz); 165 i8254_startclock(); 166 mtx_leave(&timer_mutex); 167 168 /* Check diagnostic status */ 169 if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0) /* XXX softc */ 170 printf("RTC BIOS diagnostic error %b\n", s, NVRAM_DIAG_BITS); 171 } 172 173 int 174 clockintr(void *arg) 175 { 176 struct clockframe *frame = arg; 177 178 if (timecounter->tc_get_timecount == i8254_get_timecount) { 179 if (i8254_ticked) { 180 i8254_ticked = 0; 181 } else { 182 i8254_offset += rtclock_tval; 183 i8254_lastcount = 0; 184 } 185 } 186 187 hardclock(frame); 188 189 return 1; 190 } 191 192 int 193 rtcintr(void *arg) 194 { 195 struct clockframe *frame = arg; 196 u_int stat = 0; 197 198 /* 199 * If rtcintr is 'late', next intr may happen immediately. 200 * Get them all. (Also, see comment in cpu_initclocks().) 201 */ 202 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) { 203 statclock(frame); 204 stat = 1; 205 } 206 207 return (stat); 208 } 209 210 int 211 gettick(void) 212 { 213 u_long ef; 214 u_char lo, hi; 215 216 /* Don't want someone screwing with the counter while we're here. */ 217 mtx_enter(&timer_mutex); 218 ef = read_rflags(); 219 disable_intr(); 220 /* Select counter 0 and latch it. */ 221 outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 222 lo = inb(IO_TIMER1+TIMER_CNTR0); 223 hi = inb(IO_TIMER1+TIMER_CNTR0); 224 write_rflags(ef); 225 mtx_leave(&timer_mutex); 226 return ((hi << 8) | lo); 227 } 228 229 /* 230 * Wait "n" microseconds. 231 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz. 232 * Note: timer had better have been programmed before this is first used! 233 * (Note that we use `rate generator' mode, which counts at 1:1; `square 234 * wave' mode counts at 2:1). 235 */ 236 void 237 i8254_delay(int n) 238 { 239 int limit, tick, otick; 240 static const int delaytab[26] = { 241 0, 2, 3, 4, 5, 6, 7, 9, 10, 11, 242 12, 13, 15, 16, 17, 18, 19, 21, 22, 23, 243 24, 25, 27, 28, 29, 30, 244 }; 245 246 /* 247 * Read the counter first, so that the rest of the setup overhead is 248 * counted. 249 */ 250 otick = gettick(); 251 252 if (n <= 25) 253 n = delaytab[n]; 254 else { 255 #ifdef __GNUC__ 256 /* 257 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler 258 * code so we can take advantage of the intermediate 64-bit 259 * quantity to prevent loss of significance. 260 */ 261 int m; 262 __asm volatile("mul %3" 263 : "=a" (n), "=d" (m) 264 : "0" (n), "r" (TIMER_FREQ)); 265 __asm volatile("div %4" 266 : "=a" (n), "=d" (m) 267 : "0" (n), "1" (m), "r" (1000000)); 268 #else 269 /* 270 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating 271 * point and without any avoidable overflows. 272 */ 273 int sec = n / 1000000, 274 usec = n % 1000000; 275 n = sec * TIMER_FREQ + 276 usec * (TIMER_FREQ / 1000000) + 277 usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 + 278 usec * (TIMER_FREQ % 1000) / 1000000; 279 #endif 280 } 281 282 limit = TIMER_FREQ / hz; 283 284 while (n > 0) { 285 tick = gettick(); 286 if (tick > otick) 287 n -= limit - (tick - otick); 288 else 289 n -= otick - tick; 290 otick = tick; 291 } 292 } 293 294 void 295 rtcdrain(void *v) 296 { 297 struct timeout *to = (struct timeout *)v; 298 299 if (to != NULL) 300 timeout_del(to); 301 302 /* 303 * Drain any un-acknowledged RTC interrupts. 304 * See comment in cpu_initclocks(). 305 */ 306 while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) 307 ; /* Nothing. */ 308 } 309 310 void 311 i8254_initclocks(void) 312 { 313 stathz = 128; 314 profhz = 1024; 315 316 isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr, 317 0, "clock"); 318 isa_intr_establish(NULL, 8, IST_PULSE, IPL_STATCLOCK, rtcintr, 319 0, "rtc"); 320 321 rtcstart(); /* start the mc146818 clock */ 322 323 i8254_inittimecounter(); /* hook the interrupt-based i8254 tc */ 324 } 325 326 void 327 rtcstart(void) 328 { 329 static struct timeout rtcdrain_timeout; 330 331 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz); 332 mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE); 333 334 /* 335 * On a number of i386 systems, the rtc will fail to start when booting 336 * the system. This is due to us missing to acknowledge an interrupt 337 * during early stages of the boot process. If we do not acknowledge 338 * the interrupt, the rtc clock will not generate further interrupts. 339 * To solve this, once interrupts are enabled, use a timeout (once) 340 * to drain any un-acknowledged rtc interrupt(s). 341 */ 342 timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout); 343 timeout_add(&rtcdrain_timeout, 1); 344 } 345 346 void 347 rtcstop(void) 348 { 349 mc146818_write(NULL, MC_REGB, MC_REGB_24HR); 350 } 351 352 int 353 rtcget(mc_todregs *regs) 354 { 355 if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */ 356 return (-1); 357 MC146818_GETTOD(NULL, regs); /* XXX softc */ 358 return (0); 359 } 360 361 void 362 rtcput(mc_todregs *regs) 363 { 364 MC146818_PUTTOD(NULL, regs); /* XXX softc */ 365 } 366 367 int 368 bcdtobin(int n) 369 { 370 return (((n >> 4) & 0x0f) * 10 + (n & 0x0f)); 371 } 372 373 int 374 bintobcd(int n) 375 { 376 return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f)); 377 } 378 379 static int timeset; 380 381 /* 382 * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), 383 * to be called at splclock() 384 */ 385 static int cmoscheck(void); 386 static int 387 cmoscheck(void) 388 { 389 int i; 390 unsigned short cksum = 0; 391 392 for (i = 0x10; i <= 0x2d; i++) 393 cksum += mc146818_read(NULL, i); /* XXX softc */ 394 395 return (cksum == (mc146818_read(NULL, 0x2e) << 8) 396 + mc146818_read(NULL, 0x2f)); 397 } 398 399 /* 400 * patchable to control century byte handling: 401 * 1: always update 402 * -1: never touch 403 * 0: try to figure out itself 404 */ 405 int rtc_update_century = 0; 406 407 /* 408 * Expand a two-digit year as read from the clock chip 409 * into full width. 410 * Being here, deal with the CMOS century byte. 411 */ 412 static int centb = NVRAM_CENTURY; 413 static int clock_expandyear(int); 414 static int 415 clock_expandyear(int clockyear) 416 { 417 int s, clockcentury, cmoscentury; 418 419 clockcentury = (clockyear < 70) ? 20 : 19; 420 clockyear += 100 * clockcentury; 421 422 if (rtc_update_century < 0) 423 return (clockyear); 424 425 s = splclock(); 426 if (cmoscheck()) 427 cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); 428 else 429 cmoscentury = 0; 430 splx(s); 431 if (!cmoscentury) { 432 #ifdef DIAGNOSTIC 433 printf("clock: unknown CMOS layout\n"); 434 #endif 435 return (clockyear); 436 } 437 cmoscentury = bcdtobin(cmoscentury); 438 439 if (cmoscentury != clockcentury) { 440 /* XXX note: saying "century is 20" might confuse the naive. */ 441 printf("WARNING: NVRAM century is %d but RTC year is %d\n", 442 cmoscentury, clockyear); 443 444 /* Kludge to roll over century. */ 445 if ((rtc_update_century > 0) || 446 ((cmoscentury == 19) && (clockcentury == 20) && 447 (clockyear == 2000))) { 448 printf("WARNING: Setting NVRAM century to %d\n", 449 clockcentury); 450 s = splclock(); 451 mc146818_write(NULL, centb, bintobcd(clockcentury)); 452 splx(s); 453 } 454 } else if (cmoscentury == 19 && rtc_update_century == 0) 455 rtc_update_century = 1; /* will update later in resettodr() */ 456 457 return (clockyear); 458 } 459 460 /* 461 * Initialize the time of day register, based on the time base which is, e.g. 462 * from a filesystem. 463 */ 464 void 465 inittodr(time_t base) 466 { 467 struct timespec ts; 468 mc_todregs rtclk; 469 struct clock_ymdhms dt; 470 int s; 471 472 ts.tv_nsec = 0; 473 474 /* 475 * We mostly ignore the suggested time (which comes from the 476 * file system) and go for the RTC clock time stored in the 477 * CMOS RAM. If the time can't be obtained from the CMOS, or 478 * if the time obtained from the CMOS is 5 or more years less 479 * than the suggested time, we used the suggested time. (In 480 * the latter case, it's likely that the CMOS battery has 481 * died.) 482 */ 483 484 /* 485 * if the file system time is more than a year older than the 486 * kernel, warn and then set the base time to the CONFIG_TIME. 487 */ 488 if (base < 30*SECYR) { /* if before 2000, something's odd... */ 489 printf("WARNING: preposterous time in file system\n"); 490 base = 30*SECYR; 491 } 492 493 s = splclock(); 494 if (rtcget(&rtclk)) { 495 splx(s); 496 printf("WARNING: invalid time in clock chip\n"); 497 goto fstime; 498 } 499 splx(s); 500 #ifdef DEBUG_CLOCK 501 printf("readclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], 502 rtclk[MC_MONTH], rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], 503 rtclk[MC_SEC]); 504 #endif 505 506 dt.dt_sec = bcdtobin(rtclk[MC_SEC]); 507 dt.dt_min = bcdtobin(rtclk[MC_MIN]); 508 dt.dt_hour = bcdtobin(rtclk[MC_HOUR]); 509 dt.dt_day = bcdtobin(rtclk[MC_DOM]); 510 dt.dt_mon = bcdtobin(rtclk[MC_MONTH]); 511 dt.dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR])); 512 513 /* 514 * If time_t is 32 bits, then the "End of Time" is 515 * Mon Jan 18 22:14:07 2038 (US/Eastern) 516 * This code copes with RTC's past the end of time if time_t 517 * is an int32 or less. Needed because sometimes RTCs screw 518 * up or are badly set, and that would cause the time to go 519 * negative in the calculation below, which causes Very Bad 520 * Mojo. This at least lets the user boot and fix the problem. 521 * Note the code is self eliminating once time_t goes to 64 bits. 522 */ 523 if (sizeof(time_t) <= sizeof(int32_t)) { 524 if (dt.dt_year >= 2038) { 525 printf("WARNING: RTC time at or beyond 2038.\n"); 526 dt.dt_year = 2037; 527 printf("WARNING: year set back to 2037.\n"); 528 printf("WARNING: CHECK AND RESET THE DATE!\n"); 529 } 530 } 531 532 ts.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60; 533 if (tz.tz_dsttime) 534 ts.tv_sec -= 3600; 535 536 if (base != 0 && base < ts.tv_sec - 5*SECYR) 537 printf("WARNING: file system time much less than clock time\n"); 538 else if (base > ts.tv_sec + 5*SECYR) { 539 printf("WARNING: clock time much less than file system time\n"); 540 printf("WARNING: using file system time\n"); 541 goto fstime; 542 } 543 544 tc_setclock(&ts); 545 timeset = 1; 546 return; 547 548 fstime: 549 ts.tv_sec = base; 550 tc_setclock(&ts); 551 timeset = 1; 552 printf("WARNING: CHECK AND RESET THE DATE!\n"); 553 } 554 555 /* 556 * Reset the clock. 557 */ 558 void 559 resettodr(void) 560 { 561 mc_todregs rtclk; 562 struct clock_ymdhms dt; 563 int century, diff, s; 564 565 /* 566 * We might have been called by boot() due to a crash early 567 * on. Don't reset the clock chip in this case. 568 */ 569 if (!timeset) 570 return; 571 572 s = splclock(); 573 if (rtcget(&rtclk)) 574 memset(&rtclk, 0, sizeof(rtclk)); 575 splx(s); 576 577 diff = tz.tz_minuteswest * 60; 578 if (tz.tz_dsttime) 579 diff -= 3600; 580 clock_secs_to_ymdhms(time_second - diff, &dt); 581 582 rtclk[MC_SEC] = bintobcd(dt.dt_sec); 583 rtclk[MC_MIN] = bintobcd(dt.dt_min); 584 rtclk[MC_HOUR] = bintobcd(dt.dt_hour); 585 rtclk[MC_DOW] = dt.dt_wday + 1; 586 rtclk[MC_YEAR] = bintobcd(dt.dt_year % 100); 587 rtclk[MC_MONTH] = bintobcd(dt.dt_mon); 588 rtclk[MC_DOM] = bintobcd(dt.dt_day); 589 590 #ifdef DEBUG_CLOCK 591 printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH], 592 rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]); 593 #endif 594 s = splclock(); 595 rtcput(&rtclk); 596 if (rtc_update_century > 0) { 597 century = bintobcd(dt.dt_year / 100); 598 mc146818_write(NULL, centb, century); /* XXX softc */ 599 } 600 splx(s); 601 } 602 603 void 604 setstatclockrate(int arg) 605 { 606 if (initclock_func == i8254_initclocks) { 607 if (arg == stathz) 608 mc146818_write(NULL, MC_REGA, 609 MC_BASE_32_KHz | MC_RATE_128_Hz); 610 else 611 mc146818_write(NULL, MC_REGA, 612 MC_BASE_32_KHz | MC_RATE_1024_Hz); 613 } 614 } 615 616 void 617 i8254_inittimecounter(void) 618 { 619 tc_init(&i8254_timecounter); 620 } 621 622 /* 623 * If we're using lapic to drive hardclock, we can use a simpler 624 * algorithm for the i8254 timecounters. 625 */ 626 void 627 i8254_inittimecounter_simple(void) 628 { 629 i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount; 630 i8254_timecounter.tc_counter_mask = 0x7fff; 631 i8254_timecounter.tc_frequency = TIMER_FREQ; 632 633 mtx_enter(&timer_mutex); 634 rtclock_tval = 0x8000; 635 i8254_startclock(); 636 mtx_leave(&timer_mutex); 637 638 tc_init(&i8254_timecounter); 639 } 640 641 void 642 i8254_startclock(void) 643 { 644 u_long tval = rtclock_tval; 645 646 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 647 outb(IO_TIMER1 + TIMER_CNTR0, tval & 0xff); 648 outb(IO_TIMER1 + TIMER_CNTR0, tval >> 8); 649 } 650 651 u_int 652 i8254_simple_get_timecount(struct timecounter *tc) 653 { 654 return (rtclock_tval - gettick()); 655 } 656 657 u_int 658 i8254_get_timecount(struct timecounter *tc) 659 { 660 u_char hi, lo; 661 u_int count; 662 u_long ef; 663 664 ef = read_rflags(); 665 disable_intr(); 666 667 outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 668 lo = inb(IO_TIMER1+TIMER_CNTR0); 669 hi = inb(IO_TIMER1+TIMER_CNTR0); 670 671 count = rtclock_tval - ((hi << 8) | lo); 672 673 if (count < i8254_lastcount) { 674 i8254_ticked = 1; 675 i8254_offset += rtclock_tval; 676 } 677 i8254_lastcount = count; 678 count += i8254_offset; 679 write_rflags(ef); 680 681 return (count); 682 } 683