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