Home | History | Annotate | Line # | Download | only in isa
clock.c revision 1.10.4.1
      1 /*	$NetBSD: clock.c,v 1.10.4.1 2006/09/09 02:43:07 rpaulo Exp $	*/
      2 
      3 /*
      4  * Copyright 1997
      5  * Digital Equipment Corporation. All rights reserved.
      6  *
      7  * This software is furnished under license and may be used and
      8  * copied only in accordance with the following terms and conditions.
      9  * Subject to these conditions, you may download, copy, install,
     10  * use, modify and distribute this software in source and/or binary
     11  * form. No title or ownership is transferred hereby.
     12  *
     13  * 1) Any source code used, modified or distributed must reproduce
     14  *    and retain this copyright notice and list of conditions as
     15  *    they appear in the source file.
     16  *
     17  * 2) No right is granted to use any trade name, trademark, or logo of
     18  *    Digital Equipment Corporation. Neither the "Digital Equipment
     19  *    Corporation" name nor any trademark or logo of Digital Equipment
     20  *    Corporation may be used to endorse or promote products derived
     21  *    from this software without the prior written permission of
     22  *    Digital Equipment Corporation.
     23  *
     24  * 3) This software is provided "AS-IS" and any express or implied
     25  *    warranties, including but not limited to, any implied warranties
     26  *    of merchantability, fitness for a particular purpose, or
     27  *    non-infringement are disclaimed. In no event shall DIGITAL be
     28  *    liable for any damages whatsoever, and in particular, DIGITAL
     29  *    shall not be liable for special, indirect, consequential, or
     30  *    incidental damages or damages for lost profits, loss of
     31  *    revenue or loss of use, whether such damages arise in contract,
     32  *    negligence, tort, under statute, in equity, at law or otherwise,
     33  *    even if advised of the possibility of such damage.
     34  */
     35 
     36 /*-
     37  * Copyright (c) 1990 The Regents of the University of California.
     38  * All rights reserved.
     39  *
     40  * This code is derived from software contributed to Berkeley by
     41  * William Jolitz and Don Ahn.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  * 1. Redistributions of source code must retain the above copyright
     47  *    notice, this list of conditions and the following disclaimer.
     48  * 2. Redistributions in binary form must reproduce the above copyright
     49  *    notice, this list of conditions and the following disclaimer in the
     50  *    documentation and/or other materials provided with the distribution.
     51  * 3. Neither the name of the University nor the names of its contributors
     52  *    may be used to endorse or promote products derived from this software
     53  *    without specific prior written permission.
     54  *
     55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     65  * SUCH DAMAGE.
     66  *
     67  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
     68  */
     69 /*-
     70  * Copyright (c) 1993, 1994 Charles M. Hannum.
     71  *
     72  * This code is derived from software contributed to Berkeley by
     73  * William Jolitz and Don Ahn.
     74  *
     75  * Redistribution and use in source and binary forms, with or without
     76  * modification, are permitted provided that the following conditions
     77  * are met:
     78  * 1. Redistributions of source code must retain the above copyright
     79  *    notice, this list of conditions and the following disclaimer.
     80  * 2. Redistributions in binary form must reproduce the above copyright
     81  *    notice, this list of conditions and the following disclaimer in the
     82  *    documentation and/or other materials provided with the distribution.
     83  * 3. All advertising materials mentioning features or use of this software
     84  *    must display the following acknowledgement:
     85  *	This product includes software developed by the University of
     86  *	California, Berkeley and its contributors.
     87  * 4. Neither the name of the University nor the names of its contributors
     88  *    may be used to endorse or promote products derived from this software
     89  *    without specific prior written permission.
     90  *
     91  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     92  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     93  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     94  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     95  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     96  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     97  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     98  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     99  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    100  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    101  * SUCH DAMAGE.
    102  *
    103  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
    104  */
    105 /*
    106  * Mach Operating System
    107  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
    108  * All Rights Reserved.
    109  *
    110  * Permission to use, copy, modify and distribute this software and its
    111  * documentation is hereby granted, provided that both the copyright
    112  * notice and this permission notice appear in all copies of the
    113  * software, derivative works or modified versions, and any portions
    114  * thereof, and that both notices appear in supporting documentation.
    115  *
    116  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
    117  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
    118  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
    119  *
    120  * Carnegie Mellon requests users of this software to return to
    121  *
    122  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
    123  *  School of Computer Science
    124  *  Carnegie Mellon University
    125  *  Pittsburgh PA 15213-3890
    126  *
    127  * any improvements or extensions that they make and grant Carnegie Mellon
    128  * the rights to redistribute these changes.
    129  */
    130 /*
    131   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
    132 
    133 		All Rights Reserved
    134 
    135 Permission to use, copy, modify, and distribute this software and
    136 its documentation for any purpose and without fee is hereby
    137 granted, provided that the above copyright notice appears in all
    138 copies and that both the copyright notice and this permission notice
    139 appear in supporting documentation, and that the name of Intel
    140 not be used in advertising or publicity pertaining to distribution
    141 of the software without specific, written prior permission.
    142 
    143 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
    144 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
    145 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
    146 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    147 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
    148 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
    149 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    150 */
    151 
    152 /*
    153  * Primitive clock interrupt routines.
    154  */
    155 
    156 #include <sys/cdefs.h>
    157 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.10.4.1 2006/09/09 02:43:07 rpaulo Exp $");
    158 
    159 #include <sys/param.h>
    160 #include <sys/systm.h>
    161 #include <sys/time.h>
    162 #include <sys/kernel.h>
    163 #include <sys/device.h>
    164 
    165 #include <machine/cpu.h>
    166 #include <machine/intr.h>
    167 #include <machine/pio.h>
    168 #include <arm/cpufunc.h>
    169 
    170 #include <dev/isa/isareg.h>
    171 #include <dev/isa/isavar.h>
    172 #include <dev/ic/mc146818reg.h>
    173 #include <dev/ic/i8253reg.h>
    174 #include <shark/isa/nvram.h>
    175 #include <shark/isa/spkrreg.h>
    176 #include <shark/shark/hat.h>
    177 
    178 void	sysbeepstop(void *);
    179 void	sysbeep(int, int);
    180 void	rtcinit(void);
    181 int     timer_hz_to_count(int);
    182 
    183 static void findcpuspeed(void);
    184 static void init_isa_timer_tables(void);
    185 static void delayloop(int);
    186 static int  clockintr(void *);
    187 static int  gettick(void);
    188 
    189 void startrtclock(void);
    190 
    191 inline u_int mc146818_read(void *, u_int);
    192 inline void mc146818_write(void *, u_int, u_int);
    193 
    194 #define	SECMIN	((unsigned)60)			/* seconds per minute */
    195 #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
    196 #define	SECDAY	((unsigned)(24*SECHOUR))	/* seconds per day */
    197 #define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */
    198 
    199 inline u_int
    200 mc146818_read(sc, reg)
    201 	void *sc;					/* XXX use it? */
    202 	u_int reg;
    203 {
    204 
    205 	outb(IO_RTC, reg);
    206 	return (inb(IO_RTC+1));
    207 }
    208 
    209 inline void
    210 mc146818_write(sc, reg, datum)
    211 	void *sc;					/* XXX use it? */
    212 	u_int reg, datum;
    213 {
    214 
    215 	outb(IO_RTC, reg);
    216 	outb(IO_RTC+1, datum);
    217 }
    218 
    219 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */
    220 
    221 /* number of timer ticks in a Musec = 2^20 usecs */
    222 #define TIMER_MUSECFREQ\
    223     (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000)
    224 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x))
    225 
    226 /*
    227  * microtime() makes use of the following globals.
    228  * timer_msb_table[] and timer_lsb_table[] are used to compute the
    229  * microsecond increment.
    230  *
    231  * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb];
    232  */
    233 
    234 u_short	isa_timer_msb_table[256];	/* timer->usec MSB */
    235 u_short	isa_timer_lsb_table[256];	/* timer->usec conversion for LSB */
    236 
    237 /* 64 bit counts from timer 0 */
    238 struct count64 {
    239   unsigned lo;   /* low 32 bits */
    240   unsigned hi;   /* high 32 bits */
    241 };
    242 
    243 #define TIMER0_ROLLOVER  0xFFFF  /* maximum rollover for 8254 counter */
    244 
    245 struct count64 timer0count;
    246 struct count64 timer0_at_last_clockintr;
    247 unsigned       timer0last;
    248 
    249 /*#define TESTHAT*/
    250 #ifdef TESTHAT
    251 #define HATSTACKSIZE 1024
    252 #define HATHZ  50000
    253 #define HATHZ2 10000
    254 unsigned char hatStack[HATSTACKSIZE];
    255 
    256 unsigned testHatOn = 0;
    257 unsigned nHats = 0;
    258 unsigned nHatWedges = 0;
    259 unsigned fiqReason = 0;
    260 unsigned hatCount = 0;
    261 unsigned hatCount2 = 0;
    262 
    263 void hatTest(int testReason)
    264 {
    265   fiqReason |= testReason;
    266   nHats++;
    267 
    268 }
    269 
    270 void hatWedge(int nFIQs)
    271 {
    272     printf("Unwedging the HAT.  fiqs_happened = %d\n", nFIQs);
    273     nHatWedges++;
    274 }
    275 #endif
    276 
    277 void
    278 startrtclock()
    279 {
    280 	findcpuspeed();		/* use the clock (while it's free)
    281 					to find the CPU speed */
    282 
    283 	init_isa_timer_tables();
    284 
    285 	timer0count.lo = 0;
    286 	timer0count.hi = 0;
    287 	timer0_at_last_clockintr.lo = 0;
    288 	timer0_at_last_clockintr.hi = 0;
    289 	timer0last     = 0;
    290 
    291 	/* initialize 8253 clock */
    292 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
    293 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256);
    294 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256);
    295 
    296 #ifdef TESTHAT
    297 	hatCount = timer_hz_to_count(HATHZ);
    298 	hatCount2 = timer_hz_to_count(HATHZ2);
    299 	printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount);
    300 #endif
    301 }
    302 
    303 static void
    304 init_isa_timer_tables()
    305 {
    306 	int s;
    307 	u_long t, msbmillion, quotient, remainder;
    308 
    309 	for (s = 0; s < 256; s++) {
    310 	        /* LSB table is easy, just divide and round */
    311 		t = ((u_long) s * 1000000 * 2) / TIMER_FREQ;
    312 		isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1));
    313 
    314 		msbmillion = s * 1000000;
    315 		quotient = msbmillion / TIMER_FREQ;
    316 		remainder = msbmillion % TIMER_FREQ;
    317 		t = (remainder * 256 * 2) / TIMER_FREQ;
    318 		isa_timer_msb_table[s] =
    319 		  (u_short)((t / 2) + (t & 1) + (quotient * 256));
    320 
    321 #ifdef DIAGNOSTIC
    322 		if ((s > 0) &&
    323 		    (isa_timer_msb_table[s] <
    324 		     (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF])))
    325 		  panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n",
    326 			 s, isa_timer_msb_table[s],
    327 			 isa_timer_msb_table[s - 1],
    328 			 isa_timer_lsb_table[0xFF],
    329 			 isa_timer_msb_table[s - 1] +
    330 			 isa_timer_lsb_table[0xFF]);
    331 #endif
    332 	} /* END for */
    333 }
    334 
    335 int
    336 timer_hz_to_count(timer_hz)
    337 	int timer_hz;
    338 {
    339 	u_long tval;
    340 
    341 	tval = (TIMER_FREQ * 2) / (u_long) timer_hz;
    342 	tval = (tval / 2) + (tval & 0x1);
    343 
    344 	return (int)tval;
    345 
    346 }
    347 
    348 void gettimer0count(struct count64 *);
    349 
    350 /* must be called at SPL_CLOCK or higher */
    351 void gettimer0count(pcount)
    352 	struct count64 *pcount;
    353 {
    354 	unsigned current, ticks, oldlo;
    355 
    356 	/*
    357 	 * Latch the current value of the timer and then read it.
    358 	 * This guarantees an atomic reading of the time.
    359 	 */
    360 
    361 	current = gettick();
    362 
    363 	if (timer0last >= current)
    364 	  ticks = timer0last - current;
    365 	else
    366 	  ticks = timer0last + (TIMER0_ROLLOVER - current);
    367 
    368 	timer0last = current;
    369 
    370 	oldlo = timer0count.lo;
    371 
    372 	if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */
    373 	  timer0count.hi++;
    374 
    375 	*pcount = timer0count;
    376 }
    377 
    378 static int
    379 clockintr(arg)
    380 	void *arg;
    381 {
    382 	struct clockframe *frame = arg;		/* not strictly necessary */
    383 	extern void isa_specific_eoi(int irq);
    384 #ifdef TESTHAT
    385 	static int ticks = 0;
    386 #endif
    387 	static int hatUnwedgeCtr = 0;
    388 
    389 	gettimer0count(&timer0_at_last_clockintr);
    390 
    391 	mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */
    392 
    393 	/* check to see if the high-availability timer needs to be unwedged */
    394 	if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) {
    395 	  hatUnwedgeCtr = 0;
    396 	  hatUnwedge();
    397 	}
    398 
    399 #ifdef TESTHAT
    400 	++ticks;
    401 
    402 	if (testHatOn && ((ticks & 0x3f) == 0)) {
    403 	  if (testHatOn == 1) {
    404 	    hatClkAdjust(hatCount2);
    405 	    testHatOn = 2;
    406 	  } else {
    407 	    testHatOn = 0;
    408 	    hatClkOff();
    409 	    printf("hat off status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    410 	  }
    411 	} else if (!testHatOn && (ticks & 0x1ff) == 0) {
    412 	  printf("hat on status: %d %d %x\n", nHats, nHatWedges, fiqReason);
    413 	  testHatOn = 1;
    414 	  nHats = 0;
    415 	  fiqReason = 0;
    416 	  hatClkOn(hatCount, hatTest, 0xfeedface,
    417 		   hatStack + HATSTACKSIZE - sizeof(unsigned),
    418 		   hatWedge);
    419 	}
    420 #endif
    421 	hardclock(frame);
    422 	return(0);
    423 }
    424 
    425 static int
    426 gettick()
    427 {
    428 	u_char lo, hi;
    429 	u_int savedints;
    430 
    431 	/* Don't want someone screwing with the counter while we're here. */
    432 	savedints = disable_interrupts(I32_bit);
    433 	/* Select counter 0 and latch it. */
    434 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
    435 	lo = inb(IO_TIMER1 + TIMER_CNTR0);
    436 	hi = inb(IO_TIMER1 + TIMER_CNTR0);
    437 	restore_interrupts(savedints);
    438 	return ((hi << 8) | lo);
    439 }
    440 
    441 /* modifications from i386 to shark isa version:
    442    - removed hardcoded "n -=" values that approximated the time to
    443      calculate delay ticks
    444    - made the time to calculate delay ticks almost negligable. 4 multiplies
    445      = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts;
    446      as opposed to 4 multiplies plus a bunch of divides.
    447    - removed i386 assembly language hack
    448    - put code in findcpuspeed that works even if FIRST_GUESS is orders
    449      of magnitude low
    450    - put code in delay() to use delayloop() for short delays
    451    - microtime no longer in assembly language
    452 */
    453 
    454 /*
    455  * Wait "n" microseconds.
    456  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
    457  * Note: timer had better have been programmed before this is first used!
    458  * (Note that we use `rate generator' mode, which counts at 1:1; `square
    459  * wave' mode counts at 2:1).
    460  */
    461 void
    462 delay(n)
    463 	unsigned n;
    464 {
    465 	int ticks, otick;
    466 	int nticks;
    467 
    468 	if (n < 100) {
    469 	  /* it can take a long time (1 usec or longer) just for 1 ISA read,
    470 	     so it's best not to use the timer for short delays */
    471 	  delayloop((n * count1024usec) >> 10);
    472 	  return;
    473 	}
    474 
    475 	/*
    476 	 * Read the counter first, so that the rest of the setup overhead is
    477 	 * counted.
    478 	 */
    479 	otick = gettick();
    480 
    481 	/*
    482 	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
    483 	 * without any avoidable overflows.
    484 	 */
    485 	{
    486 	        /* a Musec = 2^20 usec */
    487 		int Musec = n >> 20,
    488 		    usec = n & ((1 << 20) - 1);
    489 		nticks
    490 		  = (Musec * TIMER_MUSECFREQ) +
    491 		    (usec * (TIMER_MUSECFREQ >> 20)) +
    492 		    ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) +
    493 		    ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20);
    494 	}
    495 
    496 	while (nticks > 0) {
    497 		ticks = gettick();
    498 		if (ticks > otick)
    499 			nticks -= TIMER0_ROLLOVER - (ticks - otick);
    500 		else
    501 			nticks -= otick - ticks;
    502 		otick = ticks;
    503 	}
    504 
    505 }
    506 
    507 void
    508 sysbeepstop(arg)
    509 	void *arg;
    510 {
    511 }
    512 
    513 void
    514 sysbeep(pitch, period)
    515 	int pitch, period;
    516 {
    517 }
    518 
    519 #define FIRST_GUESS   0x2000
    520 
    521 static void
    522 findcpuspeed()
    523 {
    524 	int ticks;
    525 	unsigned int guess = FIRST_GUESS;
    526 
    527 	while (1) { /* loop until accurate enough */
    528 	  /* Put counter in count down mode */
    529 	  outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
    530 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    531 	  outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    532 	  delayloop(guess);
    533 
    534 	  /* Read the value left in the counter */
    535 	  /*
    536 	   * Formula for delaycount is:
    537 	   *  (loopcount * timer clock speed) / (counter ticks * 1000)
    538 	   */
    539 	  ticks = 0xFFFF - gettick();
    540 	  if (ticks == 0) ticks = 1; /* just in case */
    541 	  if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */
    542 	    guess *= max(2, (TIMER_MUSECDIV(1024) / ticks));
    543 	    continue;
    544 	  }
    545 	  count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks;
    546 	  return;
    547 	}
    548 }
    549 
    550 static void
    551 delayloop(counts)
    552 {
    553   while (counts--)
    554 	__insn_barrier();
    555 }
    556 
    557 void
    558 cpu_initclocks()
    559 {
    560         unsigned hzval;
    561 
    562 	printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
    563 
    564 	/* install RTC interrupt handler */
    565 	(void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK,
    566 				 clockintr, 0);
    567 
    568 	/* code for values of hz that don't divide 1000000 exactly */
    569         tickfix = 1000000 - (hz * tick);
    570         if (tickfix) {
    571                 int ftp;
    572 
    573                 ftp = min(ffs(tickfix), ffs(hz));
    574                 tickfix >>= (ftp - 1);
    575                 tickfixinterval = hz >> (ftp - 1);
    576         }
    577 
    578 	/* set  up periodic interrupt @ hz
    579 	   this is the subset of hz values in kern_clock.c that are
    580 	   supported by the ISA RTC */
    581 	switch (hz) {
    582 	case 64:
    583 		hzval = MC_RATE_64_Hz;
    584 		break;
    585 	case 128:
    586 		hzval = MC_RATE_128_Hz;
    587 		break;
    588 	case 256:
    589 		hzval = MC_RATE_256_Hz;
    590 		break;
    591 	case 1024:
    592 		hzval = MC_RATE_1024_Hz;
    593 		break;
    594 	default:
    595 		panic("cannot configure hz = %d", hz);
    596         }
    597 
    598 	rtcinit(); /* make sure basics are done by now */
    599 
    600 	/* blast values to set up clock interrupt */
    601 	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval);
    602 	/* enable periodic interrupt */
    603 	mc146818_write(NULL, MC_REGB,
    604 		       mc146818_read(NULL, MC_REGB) | MC_REGB_PIE);
    605 }
    606 
    607 void
    608 rtcinit()
    609 {
    610 	static int first_rtcopen_ever = 1;
    611 
    612 	if (!first_rtcopen_ever)
    613 		return;
    614 	first_rtcopen_ever = 0;
    615 
    616 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    617 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    618 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    619 }
    620 
    621 void
    622 setstatclockrate(arg)
    623 	int arg;
    624 {
    625 }
    626 
    627 /*
    628  * void microtime(struct timeval *tvp)
    629  *
    630  * Fill in the specified timeval struct with the current time
    631  * accurate to the microsecond.
    632  */
    633 
    634 void
    635 microtime(tvp)
    636 	struct timeval *tvp;
    637 {
    638         int s;
    639 	unsigned lsb, msb;
    640 	int tm;
    641 	static struct timeval oldtv;
    642 	struct count64 timer0current;
    643 	int ticks;
    644 
    645 	s = splstatclock();
    646 
    647 	gettimer0count(&timer0current);
    648 
    649 	tm = time.tv_usec;
    650 
    651 	/* unsigned arithmetic should take care of overflow */
    652 	/* with a >= 32 Hz clock, ticks will always be < 0x7FFF */
    653 	ticks = (int)((unsigned)
    654 		      (timer0current.lo - timer0_at_last_clockintr.lo));
    655 
    656 #ifdef DIAGNOSTIC
    657 	if ((ticks < 0) || (ticks > 0xffff))
    658 	  printf("microtime bug: ticks = %x\n", ticks);
    659 #endif
    660 
    661 	while (ticks > 0) {
    662 
    663 	  if (ticks < 0xffff) {
    664 	    msb = (ticks >> 8) & 0xFF;
    665 	    lsb = ticks & 0xFF;
    666 	  } else {
    667 	    msb = 0xff;
    668 	    lsb = 0xff;
    669 	  }
    670 
    671 	  /* see comments above */
    672 	  tm  += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb];
    673 
    674 	  /* for a 64 Hz RTC, ticks will never overflow table */
    675 	  /* microtime will be less accurate if the RTC is < 36 Hz */
    676 	  ticks -= 0xffff;
    677 	}
    678 
    679 	tvp->tv_sec = time.tv_sec;
    680 	if (tm >= 1000000) {
    681 	  tvp->tv_sec += 1;
    682 	  tm -= 1000000;
    683 	}
    684 
    685 	tvp->tv_usec = tm;
    686 
    687 	/* Make sure the time has advanced. */
    688 
    689 	if (tvp->tv_sec == oldtv.tv_sec &&
    690 	    tvp->tv_usec <= oldtv.tv_usec) {
    691 		tvp->tv_usec = oldtv.tv_usec + 1;
    692 		if (tvp->tv_usec >= 1000000) {
    693 			tvp->tv_usec -= 1000000;
    694 			++tvp->tv_sec;
    695 		}
    696 	}
    697 
    698 	oldtv = *tvp;
    699 	(void)splx(s);
    700 }
    701 
    702 /* End of clock.c */
    703