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