[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

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