clock.c revision 1.3 1 /* $NetBSD: clock.c,v 1.3 2002/10/05 17:01:49 chs 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 (at) 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 #include <sys/param.h>
125 #include <sys/systm.h>
126 #include <sys/time.h>
127 #include <sys/kernel.h>
128 #include <sys/device.h>
129
130 #include <machine/cpu.h>
131 #include <machine/intr.h>
132 #include <machine/pio.h>
133 #include <arm/cpufunc.h>
134
135 #include <dev/isa/isareg.h>
136 #include <dev/isa/isavar.h>
137 #include <dev/ic/mc146818reg.h>
138 #include <dev/ic/i8253reg.h>
139 #include <shark/isa/nvram.h>
140 #include <shark/isa/spkrreg.h>
141 #include <shark/shark/hat.h>
142
143 void sysbeepstop(void *);
144 void sysbeep(int, int);
145 void rtcinit(void);
146 int timer_hz_to_count(int);
147
148 static void findcpuspeed(void);
149 static void init_isa_timer_tables(void);
150 static void delayloop(int);
151 static int clockintr(void *);
152 static int gettick(void);
153
154 void startrtclock(void);
155
156 __inline u_int mc146818_read(void *, u_int);
157 __inline void mc146818_write(void *, u_int, u_int);
158
159 #define SECMIN ((unsigned)60) /* seconds per minute */
160 #define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */
161 #define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */
162 #define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */
163
164 __inline u_int
165 mc146818_read(sc, reg)
166 void *sc; /* XXX use it? */
167 u_int reg;
168 {
169
170 outb(IO_RTC, reg);
171 return (inb(IO_RTC+1));
172 }
173
174 __inline void
175 mc146818_write(sc, reg, datum)
176 void *sc; /* XXX use it? */
177 u_int reg, datum;
178 {
179
180 outb(IO_RTC, reg);
181 outb(IO_RTC+1, datum);
182 }
183
184 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */
185
186 /* number of timer ticks in a Musec = 2^20 usecs */
187 #define TIMER_MUSECFREQ\
188 (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000)
189 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x))
190
191 /*
192 * microtime() makes use of the following globals.
193 * timer_msb_table[] and timer_lsb_table[] are used to compute the
194 * microsecond increment.
195 *
196 * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb];
197 */
198
199 u_short isa_timer_msb_table[256]; /* timer->usec MSB */
200 u_short isa_timer_lsb_table[256]; /* timer->usec conversion for LSB */
201
202 /* 64 bit counts from timer 0 */
203 struct count64 {
204 unsigned lo; /* low 32 bits */
205 unsigned hi; /* high 32 bits */
206 };
207
208 #define TIMER0_ROLLOVER 0xFFFF /* maximum rollover for 8254 counter */
209
210 struct count64 timer0count;
211 struct count64 timer0_at_last_clockintr;
212 unsigned timer0last;
213
214 /*#define TESTHAT*/
215 #ifdef TESTHAT
216 #define HATSTACKSIZE 1024
217 #define HATHZ 50000
218 #define HATHZ2 10000
219 unsigned char hatStack[HATSTACKSIZE];
220
221 unsigned testHatOn = 0;
222 unsigned nHats = 0;
223 unsigned nHatWedges = 0;
224 unsigned fiqReason = 0;
225 unsigned hatCount = 0;
226 unsigned hatCount2 = 0;
227
228 void hatTest(int testReason)
229 {
230 fiqReason |= testReason;
231 nHats++;
232
233 }
234
235 void hatWedge(int nFIQs)
236 {
237 printf("Unwedging the HAT. fiqs_happened = %d\n", nFIQs);
238 nHatWedges++;
239 }
240 #endif
241
242 void
243 startrtclock()
244 {
245 findcpuspeed(); /* use the clock (while it's free)
246 to find the cpu speed */
247
248 init_isa_timer_tables();
249
250 timer0count.lo = 0;
251 timer0count.hi = 0;
252 timer0_at_last_clockintr.lo = 0;
253 timer0_at_last_clockintr.hi = 0;
254 timer0last = 0;
255
256 /* initialize 8253 clock */
257 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
258 outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256);
259 outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256);
260
261 #ifdef TESTHAT
262 hatCount = timer_hz_to_count(HATHZ);
263 hatCount2 = timer_hz_to_count(HATHZ2);
264 printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount);
265 #endif
266 }
267
268 static void
269 init_isa_timer_tables()
270 {
271 int s;
272 u_long t, msbmillion, quotient, remainder;
273
274 for (s = 0; s < 256; s++) {
275 /* LSB table is easy, just divide and round */
276 t = ((u_long) s * 1000000 * 2) / TIMER_FREQ;
277 isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1));
278
279 msbmillion = s * 1000000;
280 quotient = msbmillion / TIMER_FREQ;
281 remainder = msbmillion % TIMER_FREQ;
282 t = (remainder * 256 * 2) / TIMER_FREQ;
283 isa_timer_msb_table[s] =
284 (u_short)((t / 2) + (t & 1) + (quotient * 256));
285
286 #ifdef DIAGNOSTIC
287 if ((s > 0) &&
288 (isa_timer_msb_table[s] <
289 (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF])))
290 panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n",
291 s, isa_timer_msb_table[s],
292 isa_timer_msb_table[s - 1],
293 isa_timer_lsb_table[0xFF],
294 isa_timer_msb_table[s - 1] +
295 isa_timer_lsb_table[0xFF]);
296 #endif
297 } /* END for */
298 }
299
300 int
301 timer_hz_to_count(timer_hz)
302 int timer_hz;
303 {
304 u_long tval;
305
306 tval = (TIMER_FREQ * 2) / (u_long) timer_hz;
307 tval = (tval / 2) + (tval & 0x1);
308
309 return (int)tval;
310
311 }
312
313 void gettimer0count(struct count64 *);
314
315 /* must be called at SPL_CLOCK or higher */
316 void gettimer0count(pcount)
317 struct count64 *pcount;
318 {
319 unsigned current, ticks, oldlo;
320
321 /*
322 * Latch the current value of the timer and then read it.
323 * This guarentees an atomic reading of the time.
324 */
325
326 current = gettick();
327
328 if (timer0last >= current)
329 ticks = timer0last - current;
330 else
331 ticks = timer0last + (TIMER0_ROLLOVER - current);
332
333 timer0last = current;
334
335 oldlo = timer0count.lo;
336
337 if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */
338 timer0count.hi++;
339
340 *pcount = timer0count;
341 }
342
343 static int
344 clockintr(arg)
345 void *arg;
346 {
347 struct clockframe *frame = arg; /* not strictly necessary */
348 extern void isa_specific_eoi(int irq);
349 #ifdef TESTHAT
350 static int ticks = 0;
351 #endif
352 static int hatUnwedgeCtr = 0;
353
354 gettimer0count(&timer0_at_last_clockintr);
355
356 mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */
357
358 /* check to see if the high-availability timer needs to be unwedged */
359 if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) {
360 hatUnwedgeCtr = 0;
361 hatUnwedge();
362 }
363
364 #ifdef TESTHAT
365 ++ticks;
366
367 if (testHatOn && ((ticks & 0x3f) == 0)) {
368 if (testHatOn == 1) {
369 hatClkAdjust(hatCount2);
370 testHatOn = 2;
371 } else {
372 testHatOn = 0;
373 hatClkOff();
374 printf("hat off status: %d %d %x\n", nHats, nHatWedges, fiqReason);
375 }
376 } else if (!testHatOn && (ticks & 0x1ff) == 0) {
377 printf("hat on status: %d %d %x\n", nHats, nHatWedges, fiqReason);
378 testHatOn = 1;
379 nHats = 0;
380 fiqReason = 0;
381 hatClkOn(hatCount, hatTest, 0xfeedface,
382 hatStack + HATSTACKSIZE - sizeof(unsigned),
383 hatWedge);
384 }
385 #endif
386 hardclock(frame);
387 return(0);
388 }
389
390 static int
391 gettick()
392 {
393 u_char lo, hi;
394 u_int savedints;
395
396 /* Don't want someone screwing with the counter while we're here. */
397 savedints = disable_interrupts(I32_bit);
398 /* Select counter 0 and latch it. */
399 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
400 lo = inb(IO_TIMER1 + TIMER_CNTR0);
401 hi = inb(IO_TIMER1 + TIMER_CNTR0);
402 restore_interrupts(savedints);
403 return ((hi << 8) | lo);
404 }
405
406 /* modifications from i386 to shark isa version:
407 - removed hardcoded "n -=" values that approximated the time to
408 calculate delay ticks
409 - made the time to calculate delay ticks almost negligable. 4 multiplies
410 = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts;
411 as opposed to 4 multiplies plus a bunch of divides.
412 - removed i386 assembly language hack
413 - put code in findcpuspeed that works even if FIRST_GUESS is orders
414 of magnitude low
415 - put code in delay() to use delayloop() for short delays
416 - microtime no longer in assembly language
417 */
418
419 /*
420 * Wait "n" microseconds.
421 * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
422 * Note: timer had better have been programmed before this is first used!
423 * (Note that we use `rate generator' mode, which counts at 1:1; `square
424 * wave' mode counts at 2:1).
425 */
426 void
427 delay(n)
428 unsigned n;
429 {
430 int tick, otick;
431 int nticks;
432
433 if (n < 100) {
434 /* it can take a long time (1 usec or longer) just for 1 ISA read,
435 so it's best not to use the timer for short delays */
436 delayloop((n * count1024usec) >> 10);
437 return;
438 }
439
440 /*
441 * Read the counter first, so that the rest of the setup overhead is
442 * counted.
443 */
444 otick = gettick();
445
446 /*
447 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
448 * without any avoidable overflows.
449 */
450 {
451 /* a Musec = 2^20 usec */
452 int Musec = n >> 20,
453 usec = n & ((1 << 20) - 1);
454 nticks
455 = (Musec * TIMER_MUSECFREQ) +
456 (usec * (TIMER_MUSECFREQ >> 20)) +
457 ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) +
458 ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20);
459 }
460
461 while (nticks > 0) {
462 tick = gettick();
463 if (tick > otick)
464 nticks -= TIMER0_ROLLOVER - (tick - otick);
465 else
466 nticks -= otick - tick;
467 otick = tick;
468 }
469
470 }
471
472 void
473 sysbeepstop(arg)
474 void *arg;
475 {
476 }
477
478 void
479 sysbeep(pitch, period)
480 int pitch, period;
481 {
482 }
483
484 #define FIRST_GUESS 0x2000
485
486 static void
487 findcpuspeed()
488 {
489 int ticks;
490 unsigned int guess = FIRST_GUESS;
491
492 while (1) { /* loop until accurate enough */
493 /* Put counter in count down mode */
494 outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
495 outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
496 outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
497 delayloop(guess);
498
499 /* Read the value left in the counter */
500 /*
501 * Formula for delaycount is:
502 * (loopcount * timer clock speed) / (counter ticks * 1000)
503 */
504 ticks = 0xFFFF - gettick();
505 if (ticks == 0) ticks = 1; /* just in case */
506 if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */
507 guess *= max(2, (TIMER_MUSECDIV(1024) / ticks));
508 continue;
509 }
510 count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks;
511 return;
512 }
513 }
514
515 static void
516 delayloop(counts)
517 {
518 while (counts--);
519 }
520
521 void
522 cpu_initclocks()
523 {
524 unsigned hzval;
525
526 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
527
528 /* install RTC interrupt handler */
529 (void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK,
530 clockintr, 0);
531
532 /* code for values of hz that don't divide 1000000 exactly */
533 tickfix = 1000000 - (hz * tick);
534 if (tickfix) {
535 int ftp;
536
537 ftp = min(ffs(tickfix), ffs(hz));
538 tickfix >>= (ftp - 1);
539 tickfixinterval = hz >> (ftp - 1);
540 }
541
542 /* set up periodic interrupt @ hz
543 this is the subset of hz values in kern_clock.c that are
544 supported by the ISA RTC */
545 switch (hz) {
546 case 64:
547 hzval = MC_RATE_64_Hz;
548 break;
549 case 128:
550 hzval = MC_RATE_128_Hz;
551 break;
552 case 256:
553 hzval = MC_RATE_256_Hz;
554 break;
555 case 1024:
556 hzval = MC_RATE_1024_Hz;
557 break;
558 default:
559 panic("cannot configure hz = %d", hz);
560 }
561
562 rtcinit(); /* make sure basics are done by now */
563
564 /* blast values to set up clock interrupt */
565 mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval);
566 /* enable periodic interrupt */
567 mc146818_write(NULL, MC_REGB,
568 mc146818_read(NULL, MC_REGB) | MC_REGB_PIE);
569 }
570
571 void
572 rtcinit()
573 {
574 static int first_rtcopen_ever = 1;
575
576 if (!first_rtcopen_ever)
577 return;
578 first_rtcopen_ever = 0;
579
580 mc146818_write(NULL, MC_REGA, /* XXX softc */
581 MC_BASE_32_KHz | MC_RATE_1024_Hz);
582 mc146818_write(NULL, MC_REGB, MC_REGB_24HR); /* XXX softc */
583 }
584
585 void
586 setstatclockrate(arg)
587 int arg;
588 {
589 }
590
591 /*
592 * void microtime(struct timeval *tvp)
593 *
594 * Fill in the specified timeval struct with the current time
595 * accurate to the microsecond.
596 */
597
598 void
599 microtime(tvp)
600 struct timeval *tvp;
601 {
602 int s;
603 unsigned lsb, msb;
604 int tm;
605 static struct timeval oldtv;
606 struct count64 timer0current;
607 int ticks;
608
609 s = splstatclock();
610
611 gettimer0count(&timer0current);
612
613 tm = time.tv_usec;
614
615 /* unsigned arithmetic should take care of overflow */
616 /* with a >= 32 Hz clock, ticks will always be < 0x7FFF */
617 ticks = (int)((unsigned)
618 (timer0current.lo - timer0_at_last_clockintr.lo));
619
620 #ifdef DIAGNOSTIC
621 if ((ticks < 0) || (ticks > 0xffff))
622 printf("microtime bug: ticks = %x\n", ticks);
623 #endif
624
625 while (ticks > 0) {
626
627 if (ticks < 0xffff) {
628 msb = (ticks >> 8) & 0xFF;
629 lsb = ticks & 0xFF;
630 } else {
631 msb = 0xff;
632 lsb = 0xff;
633 }
634
635 /* see comments above */
636 tm += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb];
637
638 /* for a 64 Hz RTC, ticks will never overflow table */
639 /* microtime will be less accurate if the RTC is < 36 Hz */
640 ticks -= 0xffff;
641 }
642
643 tvp->tv_sec = time.tv_sec;
644 if (tm >= 1000000) {
645 tvp->tv_sec += 1;
646 tm -= 1000000;
647 }
648
649 tvp->tv_usec = tm;
650
651 /* Make sure the time has advanced. */
652
653 if (tvp->tv_sec == oldtv.tv_sec &&
654 tvp->tv_usec <= oldtv.tv_usec) {
655 tvp->tv_usec = oldtv.tv_usec + 1;
656 if (tvp->tv_usec >= 1000000) {
657 tvp->tv_usec -= 1000000;
658 ++tvp->tv_sec;
659 }
660 }
661
662 oldtv = *tvp;
663 (void)splx(s);
664 }
665
666 /* End of clock.c */
667