root/arch/i386/isa/clock.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mc146818_read
  2. mc146818_write
  3. startrtclock
  4. rtcdrain
  5. initrtclock
  6. clockintr
  7. rtcintr
  8. gettick
  9. i8254_delay
  10. calibrate_cyclecounter
  11. i8254_initclocks
  12. rtcget
  13. rtcput
  14. hexdectodec
  15. dectohexdec
  16. cmoscheck
  17. clock_expandyear
  18. inittodr
  19. resettodr
  20. setstatclockrate
  21. i8254_inittimecounter
  22. i8254_inittimecounter_simple
  23. i8254_simple_get_timecount
  24. i8254_get_timecount

    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 }

/* [<][>][^][v][top][bottom][index][help] */