[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

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