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