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