[BACK]Return to clock.c CVS log [TXT][DIR] Up to [local] / sys / arch / amd64 / isa

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