LCOV - code coverage report
Current view: top level - arch/amd64/isa - clock.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 224 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: clock.c,v 1.28 2018/07/27 21:11:31 kettenis 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/timeout.h>
      97             : #include <sys/timetc.h>
      98             : 
      99             : #include <machine/cpu.h>
     100             : #include <machine/intr.h>
     101             : #include <machine/pio.h>
     102             : #include <machine/cpufunc.h>
     103             : 
     104             : #include <dev/isa/isareg.h>
     105             : #include <dev/isa/isavar.h>
     106             : #include <dev/ic/mc146818reg.h>
     107             : #include <dev/ic/i8253reg.h>
     108             : #include <amd64/isa/nvram.h>
     109             : 
     110             : /* Timecounter on the i8254 */
     111             : u_int32_t i8254_lastcount;
     112             : u_int32_t i8254_offset;
     113             : int i8254_ticked;
     114             : u_int i8254_get_timecount(struct timecounter *tc);
     115             : 
     116             : u_int i8254_simple_get_timecount(struct timecounter *tc);
     117             : 
     118             : static struct timecounter i8254_timecounter = {
     119             :         i8254_get_timecount, NULL, ~0u, TIMER_FREQ, "i8254", 0, NULL
     120             : };
     121             : 
     122             : int     clockintr(void *);
     123             : int     rtcintr(void *);
     124             : int     gettick(void);
     125             : void    rtcdrain(void *v);
     126             : int     rtcget(mc_todregs *);
     127             : void    rtcput(mc_todregs *);
     128             : int     bcdtobin(int);
     129             : int     bintobcd(int);
     130             : 
     131             : u_int mc146818_read(void *, u_int);
     132             : void mc146818_write(void *, u_int, u_int);
     133             : 
     134             : u_int
     135           0 : mc146818_read(void *sc, u_int reg)
     136             : {
     137           0 :         outb(IO_RTC, reg);
     138           0 :         DELAY(1);
     139           0 :         return (inb(IO_RTC+1));
     140             : }
     141             : 
     142             : void
     143           0 : mc146818_write(void *sc, u_int reg, u_int datum)
     144             : {
     145           0 :         outb(IO_RTC, reg);
     146           0 :         DELAY(1);
     147           0 :         outb(IO_RTC+1, datum);
     148           0 :         DELAY(1);
     149           0 : }
     150             : 
     151             : struct mutex timer_mutex = MUTEX_INITIALIZER(IPL_HIGH);
     152             : 
     153             : u_long rtclock_tval;
     154             : 
     155             : void
     156           0 : startclocks(void)
     157             : {
     158           0 :         mtx_enter(&timer_mutex);
     159           0 :         rtclock_tval = TIMER_DIV(hz);
     160           0 :         i8254_startclock();
     161           0 :         mtx_leave(&timer_mutex);
     162           0 : }
     163             : 
     164             : int
     165           0 : clockintr(void *arg)
     166             : {
     167           0 :         struct clockframe *frame = arg;
     168             : 
     169           0 :         if (timecounter->tc_get_timecount == i8254_get_timecount) {
     170           0 :                 if (i8254_ticked) {
     171           0 :                         i8254_ticked = 0;
     172           0 :                 } else {
     173           0 :                         i8254_offset += rtclock_tval;
     174           0 :                         i8254_lastcount = 0;
     175             :                 }
     176             :         }
     177             : 
     178           0 :         hardclock(frame);
     179             : 
     180           0 :         return 1;
     181             : }
     182             : 
     183             : int
     184           0 : rtcintr(void *arg)
     185             : {
     186           0 :         struct clockframe *frame = arg;
     187             :         u_int stat = 0;
     188             : 
     189             :         /*
     190             :         * If rtcintr is 'late', next intr may happen immediately.
     191             :         * Get them all. (Also, see comment in cpu_initclocks().)
     192             :         */
     193           0 :         while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) {
     194           0 :                 statclock(frame);
     195             :                 stat = 1;
     196             :         }
     197             : 
     198           0 :         return (stat);
     199             : }
     200             : 
     201             : int
     202           0 : gettick(void)
     203             : {
     204             :         u_long s;
     205             :         u_char lo, hi;
     206             : 
     207             :         /* Don't want someone screwing with the counter while we're here. */
     208           0 :         mtx_enter(&timer_mutex);
     209           0 :         s = intr_disable();
     210             :         /* Select counter 0 and latch it. */
     211           0 :         outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
     212           0 :         lo = inb(IO_TIMER1+TIMER_CNTR0);
     213           0 :         hi = inb(IO_TIMER1+TIMER_CNTR0);
     214           0 :         intr_restore(s);
     215           0 :         mtx_leave(&timer_mutex);
     216           0 :         return ((hi << 8) | lo);
     217             : }
     218             : 
     219             : /*
     220             :  * Wait "n" microseconds.
     221             :  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
     222             :  * Note: timer had better have been programmed before this is first used!
     223             :  * (Note that we use `rate generator' mode, which counts at 1:1; `square
     224             :  * wave' mode counts at 2:1).
     225             :  */
     226             : void
     227           0 : i8254_delay(int n)
     228             : {
     229             :         int limit, tick, otick;
     230             :         static const int delaytab[26] = {
     231             :                  0,  2,  3,  4,  5,  6,  7,  9, 10, 11,
     232             :                 12, 13, 15, 16, 17, 18, 19, 21, 22, 23,
     233             :                 24, 25, 27, 28, 29, 30,
     234             :         };
     235             : 
     236             :         /*
     237             :          * Read the counter first, so that the rest of the setup overhead is
     238             :          * counted.
     239             :          */
     240           0 :         otick = gettick();
     241             : 
     242           0 :         if (n <= 25)
     243           0 :                 n = delaytab[n];
     244             :         else {
     245             : #ifdef __GNUC__
     246             :                 /*
     247             :                  * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler
     248             :                  * code so we can take advantage of the intermediate 64-bit
     249             :                  * quantity to prevent loss of significance.
     250             :                  */
     251             :                 int m;
     252           0 :                 __asm volatile("mul %3"
     253             :                                  : "=a" (n), "=d" (m)
     254             :                                  : "0" (n), "r" (TIMER_FREQ));
     255           0 :                 __asm volatile("div %4"
     256             :                                  : "=a" (n), "=d" (m)
     257             :                                  : "0" (n), "1" (m), "r" (1000000));
     258             : #else
     259             :                 /*
     260             :                  * Calculate ((n * TIMER_FREQ) / 1e6) without using floating
     261             :                  * point and without any avoidable overflows.
     262             :                  */
     263             :                 int sec = n / 1000000,
     264             :                     usec = n % 1000000;
     265             :                 n = sec * TIMER_FREQ +
     266             :                     usec * (TIMER_FREQ / 1000000) +
     267             :                     usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 +
     268             :                     usec * (TIMER_FREQ % 1000) / 1000000;
     269             : #endif
     270             :         }
     271             : 
     272           0 :         limit = TIMER_FREQ / hz;
     273             : 
     274           0 :         while (n > 0) {
     275           0 :                 tick = gettick();
     276           0 :                 if (tick > otick)
     277           0 :                         n -= limit - (tick - otick);
     278             :                 else
     279           0 :                         n -= otick - tick;
     280             :                 otick = tick;
     281             :         }
     282           0 : }
     283             : 
     284             : void
     285           0 : rtcdrain(void *v)
     286             : {
     287           0 :         struct timeout *to = (struct timeout *)v;
     288             : 
     289           0 :         if (to != NULL)
     290           0 :                 timeout_del(to);
     291             : 
     292             :         /*
     293             :         * Drain any un-acknowledged RTC interrupts.
     294             :         * See comment in cpu_initclocks().
     295             :         */
     296           0 :         while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF)
     297             :                 ; /* Nothing. */
     298           0 : }
     299             : 
     300             : void
     301           0 : i8254_initclocks(void)
     302             : {
     303           0 :         stathz = 128;
     304           0 :         profhz = 1024;
     305             : 
     306             :         /*
     307             :          * While the clock interrupt handler isn't really MPSAFE, the
     308             :          * i8254 can't really be used as a clock on a true MP system.
     309             :          */
     310           0 :         isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK | IPL_MPSAFE,
     311             :             clockintr, 0, "clock");
     312           0 :         isa_intr_establish(NULL, 8, IST_PULSE, IPL_STATCLOCK | IPL_MPSAFE,
     313             :             rtcintr, 0, "rtc");
     314             : 
     315           0 :         rtcstart();                     /* start the mc146818 clock */
     316             : 
     317           0 :         i8254_inittimecounter();        /* hook the interrupt-based i8254 tc */
     318           0 : }
     319             : 
     320             : void
     321           0 : rtcstart(void)
     322             : {
     323             :         static struct timeout rtcdrain_timeout;
     324             : 
     325           0 :         mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
     326           0 :         mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE);
     327             : 
     328             :         /*
     329             :          * On a number of i386 systems, the rtc will fail to start when booting
     330             :          * the system. This is due to us missing to acknowledge an interrupt
     331             :          * during early stages of the boot process. If we do not acknowledge
     332             :          * the interrupt, the rtc clock will not generate further interrupts.
     333             :          * To solve this, once interrupts are enabled, use a timeout (once)
     334             :          * to drain any un-acknowledged rtc interrupt(s).
     335             :          */
     336           0 :         timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout);
     337           0 :         timeout_add(&rtcdrain_timeout, 1);
     338           0 : }
     339             : 
     340             : void
     341           0 : rtcstop(void)
     342             : {
     343           0 :         mc146818_write(NULL, MC_REGB, MC_REGB_24HR);
     344           0 : }
     345             : 
     346             : int
     347           0 : rtcget(mc_todregs *regs)
     348             : {
     349           0 :         if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
     350           0 :                 return (-1);
     351           0 :         MC146818_GETTOD(NULL, regs);                    /* XXX softc */
     352           0 :         return (0);
     353           0 : }
     354             : 
     355             : void
     356           0 : rtcput(mc_todregs *regs)
     357             : {
     358           0 :         MC146818_PUTTOD(NULL, regs);                    /* XXX softc */
     359           0 : }
     360             : 
     361             : int
     362           0 : bcdtobin(int n)
     363             : {
     364           0 :         return (((n >> 4) & 0x0f) * 10 + (n & 0x0f));
     365             : }
     366             : 
     367             : int
     368           0 : bintobcd(int n)
     369             : {
     370           0 :         return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f));
     371             : }
     372             : 
     373             : static int timeset;
     374             : 
     375             : /*
     376             :  * check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
     377             :  * to be called at splclock()
     378             :  */
     379             : static int cmoscheck(void);
     380             : static int
     381           0 : cmoscheck(void)
     382             : {
     383             :         int i;
     384             :         unsigned short cksum = 0;
     385             : 
     386           0 :         for (i = 0x10; i <= 0x2d; i++)
     387           0 :                 cksum += mc146818_read(NULL, i); /* XXX softc */
     388             : 
     389           0 :         return (cksum == (mc146818_read(NULL, 0x2e) << 8)
     390           0 :                           + mc146818_read(NULL, 0x2f));
     391             : }
     392             : 
     393             : /*
     394             :  * patchable to control century byte handling:
     395             :  * 1: always update
     396             :  * -1: never touch
     397             :  * 0: try to figure out itself
     398             :  */
     399             : int rtc_update_century = 0;
     400             : 
     401             : /*
     402             :  * Expand a two-digit year as read from the clock chip
     403             :  * into full width.
     404             :  * Being here, deal with the CMOS century byte.
     405             :  */
     406             : static int centb = NVRAM_CENTURY;
     407             : static int clock_expandyear(int);
     408             : static int
     409           0 : clock_expandyear(int clockyear)
     410             : {
     411             :         int s, clockcentury, cmoscentury;
     412             : 
     413           0 :         clockcentury = (clockyear < 70) ? 20 : 19;
     414           0 :         clockyear += 100 * clockcentury;
     415             : 
     416           0 :         if (rtc_update_century < 0)
     417           0 :                 return (clockyear);
     418             : 
     419           0 :         s = splclock();
     420           0 :         if (cmoscheck())
     421           0 :                 cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
     422             :         else
     423             :                 cmoscentury = 0;
     424           0 :         splx(s);
     425           0 :         if (!cmoscentury)
     426           0 :                 return (clockyear);
     427             : 
     428           0 :         cmoscentury = bcdtobin(cmoscentury);
     429             : 
     430           0 :         if (cmoscentury != clockcentury) {
     431             :                 /* XXX note: saying "century is 20" might confuse the naive. */
     432           0 :                 printf("WARNING: NVRAM century is %d but RTC year is %d\n",
     433             :                        cmoscentury, clockyear);
     434             : 
     435             :                 /* Kludge to roll over century. */
     436           0 :                 if ((rtc_update_century > 0) ||
     437           0 :                     ((cmoscentury == 19) && (clockcentury == 20) &&
     438           0 :                      (clockyear == 2000))) {
     439           0 :                         printf("WARNING: Setting NVRAM century to %d\n",
     440             :                                clockcentury);
     441           0 :                         s = splclock();
     442           0 :                         mc146818_write(NULL, centb, bintobcd(clockcentury));
     443           0 :                         splx(s);
     444           0 :                 }
     445           0 :         } else if (cmoscentury == 19 && rtc_update_century == 0)
     446           0 :                 rtc_update_century = 1; /* will update later in resettodr() */
     447             : 
     448           0 :         return (clockyear);
     449           0 : }
     450             : 
     451             : /*
     452             :  * Initialize the time of day register, based on the time base which is, e.g.
     453             :  * from a filesystem.
     454             :  */
     455             : void
     456           0 : inittodr(time_t base)
     457             : {
     458           0 :         struct timespec ts;
     459           0 :         mc_todregs rtclk;
     460           0 :         struct clock_ymdhms dt;
     461             :         int s;
     462             : 
     463           0 :         ts.tv_nsec = 0;
     464             : 
     465             :         /*
     466             :          * We mostly ignore the suggested time (which comes from the
     467             :          * file system) and go for the RTC clock time stored in the
     468             :          * CMOS RAM.  If the time can't be obtained from the CMOS, or
     469             :          * if the time obtained from the CMOS is 5 or more years less
     470             :          * than the suggested time, we used the suggested time.  (In
     471             :          * the latter case, it's likely that the CMOS battery has
     472             :          * died.)
     473             :          */
     474             : 
     475             :         /*
     476             :          * if the file system time is more than a year older than the
     477             :          * kernel, warn and then set the base time to the CONFIG_TIME.
     478             :          */
     479           0 :         if (base < 30*SECYR) {       /* if before 2000, something's odd... */
     480           0 :                 printf("WARNING: preposterous time in file system\n");
     481             :                 base = 30*SECYR;
     482           0 :         }
     483             : 
     484           0 :         s = splclock();
     485           0 :         if (rtcget(&rtclk)) {
     486             :                 splx(s);
     487           0 :                 printf("WARNING: invalid time in clock chip\n");
     488           0 :                 goto fstime;
     489             :         }
     490             :         splx(s);
     491             : #ifdef DEBUG_CLOCK
     492             :         printf("readclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR],
     493             :             rtclk[MC_MONTH], rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN],
     494             :             rtclk[MC_SEC]);
     495             : #endif
     496             : 
     497           0 :         dt.dt_sec = bcdtobin(rtclk[MC_SEC]);
     498           0 :         dt.dt_min = bcdtobin(rtclk[MC_MIN]);
     499           0 :         dt.dt_hour = bcdtobin(rtclk[MC_HOUR]);
     500           0 :         dt.dt_day = bcdtobin(rtclk[MC_DOM]);
     501           0 :         dt.dt_mon = bcdtobin(rtclk[MC_MONTH]);
     502           0 :         dt.dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR]));
     503             : 
     504           0 :         ts.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60;
     505           0 :         if (tz.tz_dsttime)
     506           0 :                 ts.tv_sec -= 3600;
     507             : 
     508           0 :         if (base != 0 && base < ts.tv_sec - 5*SECYR)
     509           0 :                 printf("WARNING: file system time much less than clock time\n");
     510           0 :         else if (base > ts.tv_sec + 5*SECYR) {
     511           0 :                 printf("WARNING: clock time much less than file system time\n");
     512           0 :                 printf("WARNING: using file system time\n");
     513           0 :                 goto fstime;
     514             :         }
     515             : 
     516           0 :         tc_setclock(&ts);
     517           0 :         timeset = 1;
     518           0 :         return;
     519             : 
     520             : fstime:
     521           0 :         ts.tv_sec = base;
     522           0 :         tc_setclock(&ts);
     523           0 :         timeset = 1;
     524           0 :         printf("WARNING: CHECK AND RESET THE DATE!\n");
     525           0 : }
     526             : 
     527             : /*
     528             :  * Reset the clock.
     529             :  */
     530             : void
     531           0 : resettodr(void)
     532             : {
     533           0 :         mc_todregs rtclk;
     534           0 :         struct clock_ymdhms dt;
     535             :         int century, diff, s;
     536             : 
     537             :         /*
     538             :          * We might have been called by boot() due to a crash early
     539             :          * on.  Don't reset the clock chip in this case.
     540             :          */
     541           0 :         if (!timeset)
     542           0 :                 return;
     543             : 
     544           0 :         s = splclock();
     545           0 :         if (rtcget(&rtclk))
     546           0 :                 memset(&rtclk, 0, sizeof(rtclk));
     547           0 :         splx(s);
     548             : 
     549           0 :         diff = tz.tz_minuteswest * 60;
     550           0 :         if (tz.tz_dsttime)
     551           0 :                 diff -= 3600;
     552           0 :         clock_secs_to_ymdhms(time_second - diff, &dt);
     553             : 
     554           0 :         rtclk[MC_SEC] = bintobcd(dt.dt_sec);
     555           0 :         rtclk[MC_MIN] = bintobcd(dt.dt_min);
     556           0 :         rtclk[MC_HOUR] = bintobcd(dt.dt_hour);
     557           0 :         rtclk[MC_DOW] = dt.dt_wday + 1;
     558           0 :         rtclk[MC_YEAR] = bintobcd(dt.dt_year % 100);
     559           0 :         rtclk[MC_MONTH] = bintobcd(dt.dt_mon);
     560           0 :         rtclk[MC_DOM] = bintobcd(dt.dt_day);
     561             : 
     562             : #ifdef DEBUG_CLOCK
     563             :         printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH],
     564             :            rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]);
     565             : #endif
     566           0 :         s = splclock();
     567           0 :         rtcput(&rtclk);
     568           0 :         if (rtc_update_century > 0) {
     569           0 :                 century = bintobcd(dt.dt_year / 100);
     570           0 :                 mc146818_write(NULL, centb, century); /* XXX softc */
     571           0 :         }
     572           0 :         splx(s);
     573           0 : }
     574             : 
     575             : void
     576           0 : setstatclockrate(int arg)
     577             : {
     578           0 :         if (initclock_func == i8254_initclocks) {
     579           0 :                 if (arg == stathz)
     580           0 :                         mc146818_write(NULL, MC_REGA,
     581             :                             MC_BASE_32_KHz | MC_RATE_128_Hz);
     582             :                 else
     583           0 :                         mc146818_write(NULL, MC_REGA,
     584             :                             MC_BASE_32_KHz | MC_RATE_1024_Hz);
     585             :         }
     586           0 : }
     587             : 
     588             : void
     589           0 : i8254_inittimecounter(void)
     590             : {
     591           0 :         tc_init(&i8254_timecounter);
     592           0 : }
     593             : 
     594             : /*
     595             :  * If we're using lapic to drive hardclock, we can use a simpler
     596             :  * algorithm for the i8254 timecounters.
     597             :  */
     598             : void
     599           0 : i8254_inittimecounter_simple(void)
     600             : {
     601           0 :         i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount;
     602           0 :         i8254_timecounter.tc_counter_mask = 0x7fff;
     603           0 :         i8254_timecounter.tc_frequency = TIMER_FREQ;
     604             : 
     605           0 :         mtx_enter(&timer_mutex);
     606           0 :         rtclock_tval = 0x8000;
     607           0 :         i8254_startclock();
     608           0 :         mtx_leave(&timer_mutex);
     609             : 
     610           0 :         tc_init(&i8254_timecounter);
     611           0 : }
     612             : 
     613             : void
     614           0 : i8254_startclock(void)
     615             : {
     616           0 :         u_long tval = rtclock_tval;
     617             : 
     618           0 :         outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
     619           0 :         outb(IO_TIMER1 + TIMER_CNTR0, tval & 0xff);
     620           0 :         outb(IO_TIMER1 + TIMER_CNTR0, tval >> 8);
     621           0 : }
     622             : 
     623             : u_int
     624           0 : i8254_simple_get_timecount(struct timecounter *tc)
     625             : {
     626           0 :         return (rtclock_tval - gettick());
     627             : }
     628             : 
     629             : u_int
     630           0 : i8254_get_timecount(struct timecounter *tc)
     631             : {
     632             :         u_char hi, lo;
     633             :         u_int count;
     634             :         u_long s;
     635             : 
     636           0 :         s = intr_disable();
     637             : 
     638           0 :         outb(IO_TIMER1+TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
     639           0 :         lo = inb(IO_TIMER1+TIMER_CNTR0);
     640           0 :         hi = inb(IO_TIMER1+TIMER_CNTR0);
     641             : 
     642           0 :         count = rtclock_tval - ((hi << 8) | lo);
     643             : 
     644           0 :         if (count < i8254_lastcount) {
     645           0 :                 i8254_ticked = 1;
     646           0 :                 i8254_offset += rtclock_tval;
     647           0 :         }
     648           0 :         i8254_lastcount = count;
     649           0 :         count += i8254_offset;
     650             : 
     651           0 :         intr_restore(s);
     652             : 
     653           0 :         return (count);
     654             : }

Generated by: LCOV version 1.13