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