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

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