1 /* $OpenBSD: clock.c,v 1.24 2017/01/25 08:23:50 tom 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 ts.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60; 510 if (tz.tz_dsttime) 511 ts.tv_sec -= 3600; 512 513 if (base != 0 && base < ts.tv_sec - 5*SECYR) 514 printf("WARNING: file system time much less than clock time\n"); 515 else if (base > ts.tv_sec + 5*SECYR) { 516 printf("WARNING: clock time much less than file system time\n"); 517 printf("WARNING: using file system time\n"); 518 goto fstime; 519 } 520 521 tc_setclock(&ts); 522 timeset = 1; 523 return; 524 525 fstime: 526 ts.tv_sec = base; 527 tc_setclock(&ts); 528 timeset = 1; 529 printf("WARNING: CHECK AND RESET THE DATE!\n"); 530 } 531 532 /* 533 * Reset the clock. 534 */ 535 void 536 resettodr(void) 537 { 538 mc_todregs rtclk; 539 struct clock_ymdhms dt; 540 int century, diff, s; 541 542 /* 543 * We might have been called by boot() due to a crash early 544 * on. Don't reset the clock chip in this case. 545 */ 546 if (!timeset) 547 return; 548 549 s = splclock(); 550 if (rtcget(&rtclk)) 551 memset(&rtclk, 0, sizeof(rtclk)); 552 splx(s); 553 554 diff = tz.tz_minuteswest * 60; 555 if (tz.tz_dsttime) 556 diff -= 3600; 557 clock_secs_to_ymdhms(time_second - diff, &dt); 558 559 rtclk[MC_SEC] = bintobcd(dt.dt_sec); 560 rtclk[MC_MIN] = bintobcd(dt.dt_min); 561 rtclk[MC_HOUR] = bintobcd(dt.dt_hour); 562 rtclk[MC_DOW] = dt.dt_wday + 1; 563 rtclk[MC_YEAR] = bintobcd(dt.dt_year % 100); 564 rtclk[MC_MONTH] = bintobcd(dt.dt_mon); 565 rtclk[MC_DOM] = bintobcd(dt.dt_day); 566 567 #ifdef DEBUG_CLOCK 568 printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH], 569 rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]); 570 #endif 571 s = splclock(); 572 rtcput(&rtclk); 573 if (rtc_update_century > 0) { 574 century = bintobcd(dt.dt_year / 100); 575 mc146818_write(NULL, centb, century); /* XXX softc */ 576 } 577 splx(s); 578 } 579 580 void 581 setstatclockrate(int arg) 582 { 583 if (initclock_func == i8254_initclocks) { 584 if (arg == stathz) 585 mc146818_write(NULL, MC_REGA, 586 MC_BASE_32_KHz | MC_RATE_128_Hz); 587 else 588 mc146818_write(NULL, MC_REGA, 589 MC_BASE_32_KHz | MC_RATE_1024_Hz); 590 } 591 } 592 593 void 594 i8254_inittimecounter(void) 595 { 596 tc_init(&i8254_timecounter); 597 } 598 599 /* 600 * If we're using lapic to drive hardclock, we can use a simpler 601 * algorithm for the i8254 timecounters. 602 */ 603 void 604 i8254_inittimecounter_simple(void) 605 { 606 i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount; 607 i8254_timecounter.tc_counter_mask = 0x7fff; 608 i8254_timecounter.tc_frequency = TIMER_FREQ; 609 610 mtx_enter(&timer_mutex); 611 rtclock_tval = 0x8000; 612 i8254_startclock(); 613 mtx_leave(&timer_mutex); 614 615 tc_init(&i8254_timecounter); 616 } 617 618 void 619 i8254_startclock(void) 620 { 621 u_long tval = rtclock_tval; 622 623 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 624 outb(IO_TIMER1 + TIMER_CNTR0, tval & 0xff); 625 outb(IO_TIMER1 + TIMER_CNTR0, tval >> 8); 626 } 627 628 u_int 629 i8254_simple_get_timecount(struct timecounter *tc) 630 { 631 return (rtclock_tval - gettick()); 632 } 633 634 u_int 635 i8254_get_timecount(struct timecounter *tc) 636 { 637 u_char hi, lo; 638 u_int count; 639 u_long ef; 640 641 ef = read_rflags(); 642 disable_intr(); 643 644 outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH); 645 lo = inb(IO_TIMER1+TIMER_CNTR0); 646 hi = inb(IO_TIMER1+TIMER_CNTR0); 647 648 count = rtclock_tval - ((hi << 8) | lo); 649 650 if (count < i8254_lastcount) { 651 i8254_ticked = 1; 652 i8254_offset += rtclock_tval; 653 } 654 i8254_lastcount = count; 655 count += i8254_offset; 656 write_rflags(ef); 657 658 return (count); 659 } 660