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