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