clock.c revision 1.36.8.6 1 1.36.8.6 nathanw /* $NetBSD: clock.c,v 1.36.8.6 2002/10/18 02:34:49 nathanw Exp $ */
2 1.36.8.2 scw
3 1.36.8.2 scw /*
4 1.36.8.2 scw * Copyright (c) 1988 University of Utah.
5 1.36.8.2 scw * Copyright (c) 1982, 1990 The Regents of the University of California.
6 1.36.8.2 scw * All rights reserved.
7 1.36.8.2 scw *
8 1.36.8.2 scw * This code is derived from software contributed to Berkeley by
9 1.36.8.2 scw * the Systems Programming Group of the University of Utah Computer
10 1.36.8.2 scw * Science Department.
11 1.36.8.2 scw *
12 1.36.8.2 scw * Redistribution and use in source and binary forms, with or without
13 1.36.8.2 scw * modification, are permitted provided that the following conditions
14 1.36.8.2 scw * are met:
15 1.36.8.2 scw * 1. Redistributions of source code must retain the above copyright
16 1.36.8.2 scw * notice, this list of conditions and the following disclaimer.
17 1.36.8.2 scw * 2. Redistributions in binary form must reproduce the above copyright
18 1.36.8.2 scw * notice, this list of conditions and the following disclaimer in the
19 1.36.8.2 scw * documentation and/or other materials provided with the distribution.
20 1.36.8.2 scw * 3. All advertising materials mentioning features or use of this software
21 1.36.8.2 scw * must display the following acknowledgement:
22 1.36.8.2 scw * This product includes software developed by the University of
23 1.36.8.2 scw * California, Berkeley and its contributors.
24 1.36.8.2 scw * 4. Neither the name of the University nor the names of its contributors
25 1.36.8.2 scw * may be used to endorse or promote products derived from this software
26 1.36.8.2 scw * without specific prior written permission.
27 1.36.8.2 scw *
28 1.36.8.2 scw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 1.36.8.2 scw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 1.36.8.2 scw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 1.36.8.2 scw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 1.36.8.2 scw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 1.36.8.2 scw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 1.36.8.2 scw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 1.36.8.2 scw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 1.36.8.2 scw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 1.36.8.2 scw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 1.36.8.2 scw * SUCH DAMAGE.
39 1.36.8.2 scw *
40 1.36.8.2 scw * from: Utah $Hdr: clock.c 1.18 91/01/21$
41 1.36.8.2 scw *
42 1.36.8.2 scw * @(#)clock.c 7.6 (Berkeley) 5/7/91
43 1.36.8.2 scw */
44 1.36.8.2 scw
45 1.36.8.3 nathanw #include <sys/cdefs.h>
46 1.36.8.6 nathanw __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.36.8.6 2002/10/18 02:34:49 nathanw Exp $");
47 1.36.8.3 nathanw
48 1.36.8.2 scw #include <sys/param.h>
49 1.36.8.2 scw #include <sys/kernel.h>
50 1.36.8.2 scw #include <sys/device.h>
51 1.36.8.2 scw #include <sys/systm.h>
52 1.36.8.2 scw #include <machine/psl.h>
53 1.36.8.2 scw #include <machine/cpu.h>
54 1.36.8.2 scw #include <amiga/amiga/device.h>
55 1.36.8.2 scw #include <amiga/amiga/custom.h>
56 1.36.8.2 scw #include <amiga/amiga/cia.h>
57 1.36.8.2 scw #ifdef DRACO
58 1.36.8.2 scw #include <amiga/amiga/drcustom.h>
59 1.36.8.2 scw #include <m68k/include/asm_single.h>
60 1.36.8.2 scw #endif
61 1.36.8.2 scw #include <amiga/dev/rtc.h>
62 1.36.8.2 scw #include <amiga/dev/zbusvar.h>
63 1.36.8.2 scw
64 1.36.8.2 scw #if defined(PROF) && defined(PROFTIMER)
65 1.36.8.2 scw #include <sys/PROF.h>
66 1.36.8.2 scw #endif
67 1.36.8.2 scw
68 1.36.8.3 nathanw /* the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz.
69 1.36.8.2 scw We're using a 100 Hz clock. */
70 1.36.8.2 scw
71 1.36.8.2 scw #define CLK_INTERVAL amiga_clk_interval
72 1.36.8.2 scw int amiga_clk_interval;
73 1.36.8.2 scw int eclockfreq;
74 1.36.8.2 scw struct CIA *clockcia;
75 1.36.8.4 nathanw int (*usettod)(struct timeval *);
76 1.36.8.4 nathanw int (*ugettod)(struct timeval *);
77 1.36.8.2 scw
78 1.36.8.2 scw /*
79 1.36.8.2 scw * Machine-dependent clock routines.
80 1.36.8.2 scw *
81 1.36.8.2 scw * Startrtclock restarts the real-time clock, which provides
82 1.36.8.2 scw * hardclock interrupts to kern_clock.c.
83 1.36.8.2 scw *
84 1.36.8.2 scw * Inittodr initializes the time of day hardware which provides
85 1.36.8.2 scw * date functions.
86 1.36.8.2 scw *
87 1.36.8.2 scw * Resettodr restores the time of day hardware after a time change.
88 1.36.8.2 scw *
89 1.36.8.2 scw * A note on the real-time clock:
90 1.36.8.2 scw * We actually load the clock with CLK_INTERVAL-1 instead of CLK_INTERVAL.
91 1.36.8.2 scw * This is because the counter decrements to zero after N+1 enabled clock
92 1.36.8.2 scw * periods where N is the value loaded into the counter.
93 1.36.8.2 scw */
94 1.36.8.2 scw
95 1.36.8.3 nathanw int clockmatch(struct device *, struct cfdata *, void *);
96 1.36.8.3 nathanw void clockattach(struct device *, struct device *, void *);
97 1.36.8.3 nathanw void cpu_initclocks(void);
98 1.36.8.3 nathanw void calibrate_delay(struct device *);
99 1.36.8.2 scw
100 1.36.8.6 nathanw CFATTACH_DECL(clock, sizeof(struct device),
101 1.36.8.6 nathanw clockmatch, clockattach, NULL, NULL);
102 1.36.8.2 scw
103 1.36.8.2 scw int
104 1.36.8.3 nathanw clockmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
105 1.36.8.2 scw {
106 1.36.8.2 scw if (matchname("clock", auxp))
107 1.36.8.2 scw return(1);
108 1.36.8.2 scw return(0);
109 1.36.8.2 scw }
110 1.36.8.2 scw
111 1.36.8.2 scw /*
112 1.36.8.2 scw * Start the real-time clock.
113 1.36.8.2 scw */
114 1.36.8.2 scw void
115 1.36.8.3 nathanw clockattach(struct device *pdp, struct device *dp, void *auxp)
116 1.36.8.2 scw {
117 1.36.8.2 scw char *clockchip;
118 1.36.8.2 scw unsigned short interval;
119 1.36.8.2 scw #ifdef DRACO
120 1.36.8.2 scw u_char dracorev;
121 1.36.8.2 scw #endif
122 1.36.8.2 scw
123 1.36.8.2 scw if (eclockfreq == 0)
124 1.36.8.2 scw eclockfreq = 715909; /* guess NTSC */
125 1.36.8.3 nathanw
126 1.36.8.2 scw CLK_INTERVAL = (eclockfreq / 100);
127 1.36.8.2 scw
128 1.36.8.2 scw #ifdef DRACO
129 1.36.8.2 scw dracorev = is_draco();
130 1.36.8.2 scw if (dracorev >= 4) {
131 1.36.8.2 scw CLK_INTERVAL = (eclockfreq / 700);
132 1.36.8.2 scw clockchip = "QuickLogic";
133 1.36.8.2 scw } else if (dracorev) {
134 1.36.8.2 scw clockcia = (struct CIA *)CIAAbase;
135 1.36.8.2 scw clockchip = "CIA A";
136 1.36.8.3 nathanw } else
137 1.36.8.2 scw #endif
138 1.36.8.2 scw {
139 1.36.8.2 scw clockcia = (struct CIA *)CIABbase;
140 1.36.8.2 scw clockchip = "CIA B";
141 1.36.8.2 scw }
142 1.36.8.2 scw
143 1.36.8.2 scw if (dp)
144 1.36.8.2 scw printf(": %s system hz %d hardware hz %d\n", clockchip, hz,
145 1.36.8.2 scw #ifdef DRACO
146 1.36.8.2 scw dracorev >= 4 ? eclockfreq / 7 : eclockfreq);
147 1.36.8.2 scw #else
148 1.36.8.2 scw eclockfreq);
149 1.36.8.2 scw #endif
150 1.36.8.2 scw
151 1.36.8.2 scw #ifdef DRACO
152 1.36.8.2 scw if (dracorev >= 4) {
153 1.36.8.3 nathanw /*
154 1.36.8.2 scw * can't preload anything beforehand, timer is free_running;
155 1.36.8.2 scw * but need this for delay calibration.
156 1.36.8.2 scw */
157 1.36.8.2 scw
158 1.36.8.2 scw draco_ioct->io_timerlo = CLK_INTERVAL & 0xff;
159 1.36.8.2 scw draco_ioct->io_timerhi = CLK_INTERVAL >> 8;
160 1.36.8.2 scw
161 1.36.8.2 scw calibrate_delay(dp);
162 1.36.8.2 scw
163 1.36.8.2 scw return;
164 1.36.8.2 scw }
165 1.36.8.2 scw #endif
166 1.36.8.2 scw /*
167 1.36.8.3 nathanw * stop timer A
168 1.36.8.2 scw */
169 1.36.8.2 scw clockcia->cra = clockcia->cra & 0xc0;
170 1.36.8.2 scw clockcia->icr = 1 << 0; /* disable timer A interrupt */
171 1.36.8.2 scw interval = clockcia->icr; /* and make sure it's clear */
172 1.36.8.2 scw
173 1.36.8.2 scw /*
174 1.36.8.2 scw * load interval into registers.
175 1.36.8.2 scw * the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz
176 1.36.8.2 scw * supprort for PAL WHEN?!?! XXX
177 1.36.8.2 scw */
178 1.36.8.2 scw interval = CLK_INTERVAL - 1;
179 1.36.8.2 scw
180 1.36.8.2 scw /*
181 1.36.8.2 scw * order of setting is important !
182 1.36.8.2 scw */
183 1.36.8.2 scw clockcia->talo = interval & 0xff;
184 1.36.8.2 scw clockcia->tahi = interval >> 8;
185 1.36.8.2 scw /*
186 1.36.8.2 scw * start timer A in continuous mode
187 1.36.8.2 scw */
188 1.36.8.2 scw clockcia->cra = (clockcia->cra & 0xc0) | 1;
189 1.36.8.2 scw
190 1.36.8.2 scw calibrate_delay(dp);
191 1.36.8.2 scw }
192 1.36.8.2 scw
193 1.36.8.2 scw /*
194 1.36.8.2 scw * Calibrate delay loop.
195 1.36.8.2 scw * We use two iterations because we don't have enough bits to do a factor of
196 1.36.8.2 scw * 8 with better than 1%.
197 1.36.8.2 scw *
198 1.36.8.3 nathanw * XXX Note that we MUST stay below 1 tick if using clkread(), even for
199 1.36.8.3 nathanw * underestimated values of delaydivisor.
200 1.36.8.2 scw *
201 1.36.8.2 scw * XXX the "ns" below is only correct for a shift of 10 bits, and even then
202 1.36.8.2 scw * off by 2.4%
203 1.36.8.2 scw */
204 1.36.8.2 scw
205 1.36.8.3 nathanw void
206 1.36.8.3 nathanw calibrate_delay(struct device *dp)
207 1.36.8.2 scw {
208 1.36.8.2 scw unsigned long t1, t2;
209 1.36.8.2 scw extern u_int32_t delaydivisor;
210 1.36.8.2 scw /* XXX this should be defined elsewhere */
211 1.36.8.2 scw
212 1.36.8.2 scw if (dp)
213 1.36.8.3 nathanw printf("Calibrating delay loop... ");
214 1.36.8.2 scw
215 1.36.8.2 scw do {
216 1.36.8.2 scw t1 = clkread();
217 1.36.8.2 scw delay(1024);
218 1.36.8.2 scw t2 = clkread();
219 1.36.8.2 scw } while (t2 <= t1);
220 1.36.8.2 scw t2 -= t1;
221 1.36.8.2 scw delaydivisor = (delaydivisor * t2 + 1023) >> 10;
222 1.36.8.2 scw #ifdef DEBUG
223 1.36.8.2 scw if (dp)
224 1.36.8.2 scw printf("\ndiff %ld us, new divisor %u/1024 us\n", t2,
225 1.36.8.3 nathanw delaydivisor);
226 1.36.8.2 scw do {
227 1.36.8.2 scw t1 = clkread();
228 1.36.8.2 scw delay(1024);
229 1.36.8.2 scw t2 = clkread();
230 1.36.8.2 scw } while (t2 <= t1);
231 1.36.8.2 scw t2 -= t1;
232 1.36.8.2 scw delaydivisor = (delaydivisor * t2 + 1023) >> 10;
233 1.36.8.2 scw if (dp)
234 1.36.8.2 scw printf("diff %ld us, new divisor %u/1024 us\n", t2,
235 1.36.8.3 nathanw delaydivisor);
236 1.36.8.2 scw #endif
237 1.36.8.2 scw do {
238 1.36.8.2 scw t1 = clkread();
239 1.36.8.2 scw delay(1024);
240 1.36.8.2 scw t2 = clkread();
241 1.36.8.2 scw } while (t2 <= t1);
242 1.36.8.2 scw t2 -= t1;
243 1.36.8.2 scw delaydivisor = (delaydivisor * t2 + 1023) >> 10;
244 1.36.8.2 scw #ifdef DEBUG
245 1.36.8.2 scw if (dp)
246 1.36.8.2 scw printf("diff %ld us, new divisor ", t2);
247 1.36.8.2 scw #endif
248 1.36.8.2 scw if (dp)
249 1.36.8.3 nathanw printf("%u/1024 us\n", delaydivisor);
250 1.36.8.2 scw }
251 1.36.8.2 scw
252 1.36.8.2 scw void
253 1.36.8.3 nathanw cpu_initclocks(void)
254 1.36.8.2 scw {
255 1.36.8.2 scw #ifdef DRACO
256 1.36.8.2 scw unsigned char dracorev;
257 1.36.8.2 scw dracorev = is_draco();
258 1.36.8.2 scw if (dracorev >= 4) {
259 1.36.8.2 scw draco_ioct->io_timerlo = CLK_INTERVAL & 0xFF;
260 1.36.8.2 scw draco_ioct->io_timerhi = CLK_INTERVAL >> 8;
261 1.36.8.2 scw draco_ioct->io_timerrst = 0; /* any value resets */
262 1.36.8.2 scw single_inst_bset_b(draco_ioct->io_status2, DRSTAT2_TMRINTENA);
263 1.36.8.2 scw
264 1.36.8.2 scw return;
265 1.36.8.2 scw }
266 1.36.8.2 scw #endif
267 1.36.8.2 scw /*
268 1.36.8.2 scw * enable interrupts for timer A
269 1.36.8.2 scw */
270 1.36.8.2 scw clockcia->icr = (1<<7) | (1<<0);
271 1.36.8.2 scw
272 1.36.8.2 scw /*
273 1.36.8.2 scw * start timer A in continuous shot mode
274 1.36.8.2 scw */
275 1.36.8.2 scw clockcia->cra = (clockcia->cra & 0xc0) | 1;
276 1.36.8.3 nathanw
277 1.36.8.2 scw /*
278 1.36.8.2 scw * and globally enable interrupts for ciab
279 1.36.8.2 scw */
280 1.36.8.2 scw #ifdef DRACO
281 1.36.8.2 scw if (dracorev) /* we use cia a on DraCo */
282 1.36.8.2 scw single_inst_bset_b(*draco_intena, DRIRQ_INT2);
283 1.36.8.2 scw else
284 1.36.8.2 scw #endif
285 1.36.8.2 scw custom.intena = INTF_SETCLR | INTF_EXTER;
286 1.36.8.2 scw
287 1.36.8.2 scw }
288 1.36.8.2 scw
289 1.36.8.2 scw void
290 1.36.8.3 nathanw setstatclockrate(int hz)
291 1.36.8.2 scw {
292 1.36.8.2 scw }
293 1.36.8.2 scw
294 1.36.8.2 scw /*
295 1.36.8.2 scw * Returns number of usec since last recorded clock "tick"
296 1.36.8.2 scw * (i.e. clock interrupt).
297 1.36.8.2 scw */
298 1.36.8.2 scw u_long
299 1.36.8.3 nathanw clkread(void)
300 1.36.8.2 scw {
301 1.36.8.2 scw u_int interval;
302 1.36.8.2 scw u_char hi, hi2, lo;
303 1.36.8.2 scw
304 1.36.8.2 scw #ifdef DRACO
305 1.36.8.2 scw if (is_draco() >= 4) {
306 1.36.8.2 scw hi2 = draco_ioct->io_chiprev; /* latch timer */
307 1.36.8.2 scw hi = draco_ioct->io_timerhi;
308 1.36.8.2 scw lo = draco_ioct->io_timerlo;
309 1.36.8.2 scw interval = ((hi<<8) | lo);
310 1.36.8.2 scw if (interval > CLK_INTERVAL) /* timer underflow */
311 1.36.8.2 scw interval = 65536 + CLK_INTERVAL - interval;
312 1.36.8.2 scw else
313 1.36.8.2 scw interval = CLK_INTERVAL - interval;
314 1.36.8.2 scw
315 1.36.8.2 scw } else
316 1.36.8.2 scw #endif
317 1.36.8.2 scw {
318 1.36.8.2 scw hi = clockcia->tahi;
319 1.36.8.2 scw lo = clockcia->talo;
320 1.36.8.2 scw hi2 = clockcia->tahi;
321 1.36.8.2 scw if (hi != hi2) {
322 1.36.8.2 scw lo = clockcia->talo;
323 1.36.8.2 scw hi = hi2;
324 1.36.8.2 scw }
325 1.36.8.2 scw
326 1.36.8.2 scw interval = (CLK_INTERVAL - 1) - ((hi<<8) | lo);
327 1.36.8.3 nathanw
328 1.36.8.2 scw /*
329 1.36.8.2 scw * should read ICR and if there's an int pending, adjust
330 1.36.8.2 scw * interval. However, since reading ICR clears the interrupt,
331 1.36.8.2 scw * we'd lose a hardclock int, and this is not tolerable.
332 1.36.8.2 scw */
333 1.36.8.2 scw }
334 1.36.8.2 scw
335 1.36.8.2 scw return((interval * tick) / CLK_INTERVAL);
336 1.36.8.2 scw }
337 1.36.8.2 scw
338 1.36.8.2 scw #if notyet
339 1.36.8.2 scw
340 1.36.8.2 scw /* implement this later. I'd suggest using both timers in CIA-A, they're
341 1.36.8.2 scw not yet used. */
342 1.36.8.2 scw
343 1.36.8.2 scw #include "clock.h"
344 1.36.8.2 scw #if NCLOCK > 0
345 1.36.8.2 scw /*
346 1.36.8.2 scw * /dev/clock: mappable high resolution timer.
347 1.36.8.2 scw *
348 1.36.8.2 scw * This code implements a 32-bit recycling counter (with a 4 usec period)
349 1.36.8.2 scw * using timers 2 & 3 on the 6840 clock chip. The counter can be mapped
350 1.36.8.2 scw * RO into a user's address space to achieve low overhead (no system calls),
351 1.36.8.2 scw * high-precision timing.
352 1.36.8.2 scw *
353 1.36.8.2 scw * Note that timer 3 is also used for the high precision profiling timer
354 1.36.8.2 scw * (PROFTIMER code above). Care should be taken when both uses are
355 1.36.8.2 scw * configured as only a token effort is made to avoid conflicting use.
356 1.36.8.2 scw */
357 1.36.8.2 scw #include <sys/proc.h>
358 1.36.8.2 scw #include <sys/resourcevar.h>
359 1.36.8.2 scw #include <sys/ioctl.h>
360 1.36.8.2 scw #include <sys/malloc.h>
361 1.36.8.2 scw #include <uvm/uvm_extern.h>
362 1.36.8.2 scw #include <amiga/amiga/clockioctl.h>
363 1.36.8.2 scw #include <sys/specdev.h>
364 1.36.8.2 scw #include <sys/vnode.h>
365 1.36.8.2 scw #include <sys/mman.h>
366 1.36.8.2 scw
367 1.36.8.2 scw int clockon = 0; /* non-zero if high-res timer enabled */
368 1.36.8.2 scw #ifdef PROFTIMER
369 1.36.8.2 scw int profprocs = 0; /* # of procs using profiling timer */
370 1.36.8.2 scw #endif
371 1.36.8.2 scw #ifdef DEBUG
372 1.36.8.2 scw int clockdebug = 0;
373 1.36.8.2 scw #endif
374 1.36.8.2 scw
375 1.36.8.2 scw /*ARGSUSED*/
376 1.36.8.3 nathanw int
377 1.36.8.3 nathanw clockopen(dev_t dev, int flags)
378 1.36.8.2 scw {
379 1.36.8.2 scw #ifdef PROFTIMER
380 1.36.8.2 scw #ifdef PROF
381 1.36.8.2 scw /*
382 1.36.8.2 scw * Kernel profiling enabled, give up.
383 1.36.8.2 scw */
384 1.36.8.2 scw if (profiling)
385 1.36.8.2 scw return(EBUSY);
386 1.36.8.2 scw #endif
387 1.36.8.2 scw /*
388 1.36.8.2 scw * If any user processes are profiling, give up.
389 1.36.8.2 scw */
390 1.36.8.2 scw if (profprocs)
391 1.36.8.2 scw return(EBUSY);
392 1.36.8.2 scw #endif
393 1.36.8.2 scw if (!clockon) {
394 1.36.8.2 scw startclock();
395 1.36.8.2 scw clockon++;
396 1.36.8.2 scw }
397 1.36.8.2 scw return(0);
398 1.36.8.2 scw }
399 1.36.8.2 scw
400 1.36.8.2 scw /*ARGSUSED*/
401 1.36.8.3 nathanw int
402 1.36.8.3 nathanw clockclose(dev_t dev, int flags)
403 1.36.8.2 scw {
404 1.36.8.5 nathanw (void) clockunmmap(dev, (caddr_t)0, curproc); /* XXX */
405 1.36.8.2 scw stopclock();
406 1.36.8.2 scw clockon = 0;
407 1.36.8.2 scw return(0);
408 1.36.8.2 scw }
409 1.36.8.2 scw
410 1.36.8.2 scw /*ARGSUSED*/
411 1.36.8.3 nathanw int
412 1.36.8.3 nathanw clockioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
413 1.36.8.2 scw {
414 1.36.8.2 scw int error = 0;
415 1.36.8.3 nathanw
416 1.36.8.2 scw switch (cmd) {
417 1.36.8.2 scw
418 1.36.8.2 scw case CLOCKMAP:
419 1.36.8.2 scw error = clockmmap(dev, (caddr_t *)data, p);
420 1.36.8.2 scw break;
421 1.36.8.2 scw
422 1.36.8.2 scw case CLOCKUNMAP:
423 1.36.8.2 scw error = clockunmmap(dev, *(caddr_t *)data, p);
424 1.36.8.2 scw break;
425 1.36.8.2 scw
426 1.36.8.2 scw case CLOCKGETRES:
427 1.36.8.2 scw *(int *)data = CLK_RESOLUTION;
428 1.36.8.2 scw break;
429 1.36.8.2 scw
430 1.36.8.2 scw default:
431 1.36.8.2 scw error = EINVAL;
432 1.36.8.2 scw break;
433 1.36.8.2 scw }
434 1.36.8.2 scw return(error);
435 1.36.8.2 scw }
436 1.36.8.2 scw
437 1.36.8.2 scw /*ARGSUSED*/
438 1.36.8.3 nathanw void
439 1.36.8.3 nathanw clockmap(dev_t dev, int off, int prot)
440 1.36.8.2 scw {
441 1.36.8.2 scw return((off + (INTIOBASE+CLKBASE+CLKSR-1)) >> PGSHIFT);
442 1.36.8.2 scw }
443 1.36.8.2 scw
444 1.36.8.3 nathanw int
445 1.36.8.3 nathanw clockmmap(dev_t dev, caddr_t *addrp, struct proc *p)
446 1.36.8.2 scw {
447 1.36.8.2 scw int error;
448 1.36.8.2 scw struct vnode vn;
449 1.36.8.2 scw struct specinfo si;
450 1.36.8.2 scw int flags;
451 1.36.8.2 scw
452 1.36.8.2 scw flags = MAP_FILE|MAP_SHARED;
453 1.36.8.2 scw if (*addrp)
454 1.36.8.2 scw flags |= MAP_FIXED;
455 1.36.8.2 scw else
456 1.36.8.2 scw *addrp = (caddr_t)0x1000000; /* XXX */
457 1.36.8.2 scw vn.v_type = VCHR; /* XXX */
458 1.36.8.2 scw vn.v_specinfo = &si; /* XXX */
459 1.36.8.2 scw vn.v_rdev = dev; /* XXX */
460 1.36.8.2 scw error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp,
461 1.36.8.2 scw PAGE_SIZE, VM_PROT_ALL, flags, (caddr_t)&vn, 0);
462 1.36.8.2 scw return(error);
463 1.36.8.2 scw }
464 1.36.8.2 scw
465 1.36.8.3 nathanw int
466 1.36.8.3 nathanw clockunmmap(dev_t dev, caddr_t addr, struct proc *p)
467 1.36.8.2 scw {
468 1.36.8.2 scw int rv;
469 1.36.8.2 scw
470 1.36.8.2 scw if (addr == 0)
471 1.36.8.2 scw return(EINVAL); /* XXX: how do we deal with this? */
472 1.36.8.2 scw uvm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, PAGE_SIZE);
473 1.36.8.2 scw return 0;
474 1.36.8.2 scw }
475 1.36.8.2 scw
476 1.36.8.3 nathanw void
477 1.36.8.3 nathanw startclock(void)
478 1.36.8.2 scw {
479 1.36.8.2 scw register struct clkreg *clk = (struct clkreg *)clkstd[0];
480 1.36.8.2 scw
481 1.36.8.2 scw clk->clk_msb2 = -1; clk->clk_lsb2 = -1;
482 1.36.8.2 scw clk->clk_msb3 = -1; clk->clk_lsb3 = -1;
483 1.36.8.2 scw
484 1.36.8.2 scw clk->clk_cr2 = CLK_CR3;
485 1.36.8.2 scw clk->clk_cr3 = CLK_OENAB|CLK_8BIT;
486 1.36.8.2 scw clk->clk_cr2 = CLK_CR1;
487 1.36.8.2 scw clk->clk_cr1 = CLK_IENAB;
488 1.36.8.2 scw }
489 1.36.8.2 scw
490 1.36.8.3 nathanw void
491 1.36.8.3 nathanw stopclock(void)
492 1.36.8.2 scw {
493 1.36.8.2 scw register struct clkreg *clk = (struct clkreg *)clkstd[0];
494 1.36.8.2 scw
495 1.36.8.2 scw clk->clk_cr2 = CLK_CR3;
496 1.36.8.2 scw clk->clk_cr3 = 0;
497 1.36.8.2 scw clk->clk_cr2 = CLK_CR1;
498 1.36.8.2 scw clk->clk_cr1 = CLK_IENAB;
499 1.36.8.2 scw }
500 1.36.8.2 scw #endif
501 1.36.8.2 scw
502 1.36.8.2 scw #endif
503 1.36.8.2 scw
504 1.36.8.2 scw
505 1.36.8.2 scw #ifdef PROFTIMER
506 1.36.8.2 scw /*
507 1.36.8.2 scw * This code allows the amiga kernel to use one of the extra timers on
508 1.36.8.2 scw * the clock chip for profiling, instead of the regular system timer.
509 1.36.8.2 scw * The advantage of this is that the profiling timer can be turned up to
510 1.36.8.2 scw * a higher interrupt rate, giving finer resolution timing. The profclock
511 1.36.8.2 scw * routine is called from the lev6intr in locore, and is a specialized
512 1.36.8.2 scw * routine that calls addupc. The overhead then is far less than if
513 1.36.8.2 scw * hardclock/softclock was called. Further, the context switch code in
514 1.36.8.2 scw * locore has been changed to turn the profile clock on/off when switching
515 1.36.8.2 scw * into/out of a process that is profiling (startprofclock/stopprofclock).
516 1.36.8.2 scw * This reduces the impact of the profiling clock on other users, and might
517 1.36.8.3 nathanw * possibly increase the accuracy of the profiling.
518 1.36.8.2 scw */
519 1.36.8.2 scw int profint = PRF_INTERVAL; /* Clock ticks between interrupts */
520 1.36.8.2 scw int profscale = 0; /* Scale factor from sys clock to prof clock */
521 1.36.8.2 scw char profon = 0; /* Is profiling clock on? */
522 1.36.8.2 scw
523 1.36.8.2 scw /* profon values - do not change, locore.s assumes these values */
524 1.36.8.2 scw #define PRF_NONE 0x00
525 1.36.8.2 scw #define PRF_USER 0x01
526 1.36.8.2 scw #define PRF_KERNEL 0x80
527 1.36.8.2 scw
528 1.36.8.3 nathanw void
529 1.36.8.3 nathanw initprofclock(void)
530 1.36.8.2 scw {
531 1.36.8.2 scw #if NCLOCK > 0
532 1.36.8.5 nathanw struct proc *p = curproc; /* XXX */
533 1.36.8.2 scw
534 1.36.8.2 scw /*
535 1.36.8.2 scw * If the high-res timer is running, force profiling off.
536 1.36.8.2 scw * Unfortunately, this gets reflected back to the user not as
537 1.36.8.2 scw * an error but as a lack of results.
538 1.36.8.2 scw */
539 1.36.8.2 scw if (clockon) {
540 1.36.8.2 scw p->p_stats->p_prof.pr_scale = 0;
541 1.36.8.2 scw return;
542 1.36.8.2 scw }
543 1.36.8.2 scw /*
544 1.36.8.2 scw * Keep track of the number of user processes that are profiling
545 1.36.8.2 scw * by checking the scale value.
546 1.36.8.2 scw *
547 1.36.8.2 scw * XXX: this all assumes that the profiling code is well behaved;
548 1.36.8.2 scw * i.e. profil() is called once per process with pcscale non-zero
549 1.36.8.2 scw * to turn it on, and once with pcscale zero to turn it off.
550 1.36.8.2 scw * Also assumes you don't do any forks or execs. Oh well, there
551 1.36.8.2 scw * is always adb...
552 1.36.8.2 scw */
553 1.36.8.2 scw if (p->p_stats->p_prof.pr_scale)
554 1.36.8.2 scw profprocs++;
555 1.36.8.2 scw else
556 1.36.8.2 scw profprocs--;
557 1.36.8.2 scw #endif
558 1.36.8.2 scw /*
559 1.36.8.2 scw * The profile interrupt interval must be an even divisor
560 1.36.8.2 scw * of the CLK_INTERVAL so that scaling from a system clock
561 1.36.8.2 scw * tick to a profile clock tick is possible using integer math.
562 1.36.8.2 scw */
563 1.36.8.2 scw if (profint > CLK_INTERVAL || (CLK_INTERVAL % profint) != 0)
564 1.36.8.2 scw profint = CLK_INTERVAL;
565 1.36.8.2 scw profscale = CLK_INTERVAL / profint;
566 1.36.8.2 scw }
567 1.36.8.2 scw
568 1.36.8.3 nathanw void
569 1.36.8.3 nathanw startprofclock(void)
570 1.36.8.2 scw {
571 1.36.8.2 scw unsigned short interval;
572 1.36.8.2 scw
573 1.36.8.2 scw /* stop timer B */
574 1.36.8.2 scw clockcia->crb = clockcia->crb & 0xc0;
575 1.36.8.2 scw
576 1.36.8.2 scw /* load interval into registers.
577 1.36.8.2 scw the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz */
578 1.36.8.2 scw
579 1.36.8.2 scw interval = profint - 1;
580 1.36.8.2 scw
581 1.36.8.2 scw /* order of setting is important ! */
582 1.36.8.2 scw clockcia->tblo = interval & 0xff;
583 1.36.8.2 scw clockcia->tbhi = interval >> 8;
584 1.36.8.2 scw
585 1.36.8.2 scw /* enable interrupts for timer B */
586 1.36.8.2 scw clockcia->icr = (1<<7) | (1<<1);
587 1.36.8.2 scw
588 1.36.8.2 scw /* start timer B in continuous shot mode */
589 1.36.8.2 scw clockcia->crb = (clockcia->crb & 0xc0) | 1;
590 1.36.8.2 scw }
591 1.36.8.2 scw
592 1.36.8.3 nathanw void
593 1.36.8.3 nathanw stopprofclock(void)
594 1.36.8.2 scw {
595 1.36.8.2 scw /* stop timer B */
596 1.36.8.2 scw clockcia->crb = clockcia->crb & 0xc0;
597 1.36.8.2 scw }
598 1.36.8.2 scw
599 1.36.8.2 scw #ifdef PROF
600 1.36.8.2 scw /*
601 1.36.8.2 scw * profclock() is expanded in line in lev6intr() unless profiling kernel.
602 1.36.8.2 scw * Assumes it is called with clock interrupts blocked.
603 1.36.8.2 scw */
604 1.36.8.3 nathanw void
605 1.36.8.3 nathanw profclock(caddr_t pc, int ps)
606 1.36.8.2 scw {
607 1.36.8.2 scw /*
608 1.36.8.2 scw * Came from user mode.
609 1.36.8.2 scw * If this process is being profiled record the tick.
610 1.36.8.2 scw */
611 1.36.8.2 scw if (USERMODE(ps)) {
612 1.36.8.2 scw if (p->p_stats.p_prof.pr_scale)
613 1.36.8.5 nathanw addupc(pc, &curproc->p_stats.p_prof, 1);
614 1.36.8.2 scw }
615 1.36.8.2 scw /*
616 1.36.8.2 scw * Came from kernel (supervisor) mode.
617 1.36.8.2 scw * If we are profiling the kernel, record the tick.
618 1.36.8.2 scw */
619 1.36.8.2 scw else if (profiling < 2) {
620 1.36.8.2 scw register int s = pc - s_lowpc;
621 1.36.8.2 scw
622 1.36.8.2 scw if (s < s_textsize)
623 1.36.8.2 scw kcount[s / (HISTFRACTION * sizeof (*kcount))]++;
624 1.36.8.2 scw }
625 1.36.8.2 scw /*
626 1.36.8.2 scw * Kernel profiling was on but has been disabled.
627 1.36.8.2 scw * Mark as no longer profiling kernel and if all profiling done,
628 1.36.8.2 scw * disable the clock.
629 1.36.8.2 scw */
630 1.36.8.2 scw if (profiling && (profon & PRF_KERNEL)) {
631 1.36.8.2 scw profon &= ~PRF_KERNEL;
632 1.36.8.2 scw if (profon == PRF_NONE)
633 1.36.8.2 scw stopprofclock();
634 1.36.8.2 scw }
635 1.36.8.2 scw }
636 1.36.8.2 scw #endif
637 1.36.8.2 scw #endif
638 1.36.8.2 scw
639 1.36.8.2 scw /*
640 1.36.8.2 scw * Initialize the time of day register, based on the time base which is, e.g.
641 1.36.8.2 scw * from a filesystem.
642 1.36.8.2 scw */
643 1.36.8.2 scw void
644 1.36.8.3 nathanw inittodr(time_t base)
645 1.36.8.2 scw {
646 1.36.8.2 scw struct timeval tvbuf;
647 1.36.8.2 scw
648 1.36.8.2 scw tvbuf.tv_usec = 0;
649 1.36.8.2 scw tvbuf.tv_sec = base; /* assume no battery clock exists */
650 1.36.8.3 nathanw
651 1.36.8.2 scw if (ugettod == NULL)
652 1.36.8.2 scw printf("WARNING: no battery clock\n");
653 1.36.8.2 scw else {
654 1.36.8.2 scw ugettod(&tvbuf);
655 1.36.8.2 scw tvbuf.tv_sec += rtc_offset * 60;
656 1.36.8.2 scw }
657 1.36.8.2 scw
658 1.36.8.2 scw if (tvbuf.tv_sec < base) {
659 1.36.8.2 scw printf("WARNING: bad date in battery clock\n");
660 1.36.8.2 scw tvbuf.tv_sec = base;
661 1.36.8.2 scw }
662 1.36.8.3 nathanw
663 1.36.8.2 scw time = tvbuf;
664 1.36.8.2 scw }
665 1.36.8.2 scw
666 1.36.8.2 scw void
667 1.36.8.3 nathanw resettodr(void)
668 1.36.8.2 scw {
669 1.36.8.2 scw struct timeval tvbuf;
670 1.36.8.2 scw
671 1.36.8.2 scw if (!usettod)
672 1.36.8.2 scw return;
673 1.36.8.2 scw
674 1.36.8.2 scw tvbuf = time;
675 1.36.8.2 scw
676 1.36.8.2 scw tvbuf.tv_sec -= rtc_offset * 60;
677 1.36.8.2 scw
678 1.36.8.2 scw if (!usettod(&tvbuf))
679 1.36.8.2 scw printf("Cannot set battery backed clock\n");
680 1.36.8.2 scw }
681