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