xref: /netbsd/sys/arch/sparc/sparc/timer.c (revision bf9ec67e)
1 /*	$NetBSD: timer.c,v 1.3 2002/03/28 20:04:27 uwe Exp $ */
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 1994 Gordon W. Ross
7  * Copyright (c) 1993 Adam Glass
8  * Copyright (c) 1996 Paul Kranenburg
9  * Copyright (c) 1996
10  * 	The President and Fellows of Harvard College. All rights reserved.
11  *
12  * This software was developed by the Computer Systems Engineering group
13  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
14  * contributed to Berkeley.
15  *
16  * All advertising materials mentioning features or use of this software
17  * must display the following acknowledgement:
18  *	This product includes software developed by Harvard University.
19  *	This product includes software developed by the University of
20  *	California, Lawrence Berkeley Laboratory.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  *
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *	This product includes software developed by the University of
34  *	California, Berkeley and its contributors.
35  *	This product includes software developed by Paul Kranenburg.
36  *	This product includes software developed by Harvard University.
37  * 4. Neither the name of the University nor the names of its contributors
38  *    may be used to endorse or promote products derived from this software
39  *    without specific prior written permission.
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  *	@(#)clock.c	8.1 (Berkeley) 6/11/93
54  *
55  */
56 
57 /*
58  * Kernel clocks provided by "timer" device.  The
59  * hardclock is provided by the timer register (aka system counter).
60  * The statclock is provided by per cpu counter register(s) (aka
61  * processor counter(s)).
62  *
63  */
64 #include "opt_sparc_arch.h"
65 
66 #include <sys/param.h>
67 #include <sys/kernel.h>
68 #include <sys/device.h>
69 #include <sys/systm.h>
70 
71 #include <machine/bus.h>
72 #include <machine/autoconf.h>
73 #include <machine/eeprom.h>
74 #include <machine/idprom.h>
75 
76 #include <sparc/sparc/vaddrs.h>
77 #include <sparc/sparc/cpuvar.h>
78 #include <sparc/sparc/timerreg.h>
79 
80 #if defined(MSIIEP)
81 #include <sparc/sparc/msiiepreg.h>
82 #include <sparc/sparc/msiiepvar.h>
83 #endif
84 
85 static struct intrhand level10;
86 static struct intrhand level14;
87 
88 #if defined(SUN4) || defined(SUN4C)
89 static int	clockintr_4(void *);
90 static int	statintr_4(void *);
91 static void	timer_init_4(void);
92 #endif
93 
94 #if defined(SUN4M)
95 static int	clockintr_4m(void *);
96 static int	statintr_4m(void *);
97 static void	timer_init_4m(void);
98 #endif
99 
100 #if defined(MSIIEP)
101 static int	clockintr_msiiep(void *);
102 static int	statintr_msiiep(void *);
103 static void	timer_init_msiiep(void);
104 #endif
105 
106 static int	timermatch_mainbus(struct device *, struct cfdata *, void *);
107 static int	timermatch_obio(struct device *, struct cfdata *, void *);
108 static int	timermatch_msiiep(struct device *, struct cfdata *, void *);
109 static void	timerattach_mainbus(struct device *, struct device *, void *);
110 static void	timerattach_obio(struct device *, struct device *, void *);
111 static void	timerattach_msiiep(struct device *, struct device *, void *);
112 
113 static void	timerattach(volatile int *, volatile int *);
114 
115 static int timerok;
116 
117 /* Imported from clock.c: */
118 extern int statvar, statmin, statint;
119 extern int timerblurb;
120 extern void (*timer_init)(void);
121 
122 
123 #if defined(SUN4) || defined(SUN4C)
124 #define	timerreg4	((struct timerreg_4 *)TIMERREG_VA)
125 #endif
126 
127 #if defined(SUN4M)
128 struct timer_4m		*timerreg4m;
129 #define counterreg4m	cpuinfo.counterreg_4m
130 #endif
131 
132 #if defined(MSIIEP)
133 /* XXX: move this stuff to msiiepreg.h? */
134 
135 /* ms-IIep PCIC registers mapped at fixed VA (see vaddrs.h) */
136 #define msiiep ((volatile struct msiiep_pcic_reg *)MSIIEP_PCIC_VA)
137 
138 /*
139  * ms-IIep counters tick every 4 cpu clock @100MHz.
140  * counter is reset to 1 when new limit is written.
141  */
142 #define tmr_ustolimIIep(n) ((n) * 25 + 1)
143 #endif /* MSIIEP */
144 
145 
146 struct cfattach timer_mainbus_ca = {
147 	sizeof(struct device), timermatch_mainbus, timerattach_mainbus
148 };
149 
150 struct cfattach timer_obio_ca = {
151 	sizeof(struct device), timermatch_obio, timerattach_obio
152 };
153 
154 struct cfattach timer_msiiep_ca = {
155 	sizeof(struct device), timermatch_msiiep, timerattach_msiiep
156 };
157 
158 /*
159  * The sun4c OPENPROM calls the timer the "counter-timer".
160  */
161 static int
162 timermatch_mainbus(parent, cf, aux)
163 	struct device *parent;
164 	struct cfdata *cf;
165 	void *aux;
166 {
167 	struct mainbus_attach_args *ma = aux;
168 
169 	return (strcmp("counter-timer", ma->ma_name) == 0);
170 }
171 
172 /*
173  * The sun4m OPENPROM calls the timer the "counter".
174  * The sun4 timer must be probed.
175  */
176 static int
177 timermatch_obio(parent, cf, aux)
178 	struct device *parent;
179 	struct cfdata *cf;
180 	void *aux;
181 {
182 	union obio_attach_args *uoba = aux;
183 	struct obio4_attach_args *oba;
184 
185 	if (uoba->uoba_isobio4 == 0)
186 		return (strcmp("counter", uoba->uoba_sbus.sa_name) == 0);
187 
188 	if (!CPU_ISSUN4) {
189 		printf("timermatch_obio: attach args mixed up\n");
190 		return (0);
191 	}
192 
193 	/* Only these sun4s have "timer" (others have "oclock") */
194 	if (cpuinfo.cpu_type != CPUTYP_4_300 &&
195 	    cpuinfo.cpu_type != CPUTYP_4_400)
196 		return (0);
197 
198 	/* Make sure there is something there */
199 	oba = &uoba->uoba_oba4;
200 	return (bus_space_probe(oba->oba_bustag, oba->oba_paddr,
201 				4,	/* probe size */
202 				0,	/* offset */
203 				0,	/* flags */
204 				NULL, NULL));
205 }
206 
207 static int
208 timermatch_msiiep(parent, cf, aux)
209 	struct device *parent;
210 	struct cfdata *cf;
211 	void *aux;
212 {
213 #if defined(MSIIEP)
214 	struct msiiep_attach_args *msa = aux;
215 
216 	return (strcmp(msa->msa_name, "timer") == 0);
217 #else
218 	return (0);
219 #endif
220 }
221 
222 /* ARGSUSED */
223 static void
224 timerattach_mainbus(parent, self, aux)
225 	struct device *parent, *self;
226 	void *aux;
227 {
228 #if defined(SUN4) || defined(SUN4C)
229 	struct mainbus_attach_args *ma = aux;
230 	bus_space_handle_t bh;
231 
232 	/*
233 	 * This time, we ignore any existing virtual address because
234 	 * we have a fixed virtual address for the timer, to make
235 	 * microtime() faster.
236 	 */
237 	if (bus_space_map2(ma->ma_bustag,
238 			   ma->ma_paddr,
239 			   sizeof(struct timerreg_4),
240 			   BUS_SPACE_MAP_LINEAR,
241 			   TIMERREG_VA, &bh) != 0) {
242 		printf("%s: can't map register\n", self->dv_xname);
243 		return;
244 	}
245 
246 	timerattach(&timerreg4->t_c14.t_counter, &timerreg4->t_c14.t_limit);
247 #endif /* SUN4/SUN4C */
248 }
249 
250 static void
251 timerattach_obio(parent, self, aux)
252 	struct device *parent, *self;
253 	void *aux;
254 {
255 	union obio_attach_args *uoba = aux;
256 
257 	if (uoba->uoba_isobio4 == 0) {
258 		/* sun4m timer at obio */
259 #if defined(SUN4M)
260 		struct sbus_attach_args *sa = &uoba->uoba_sbus;
261 		bus_space_handle_t bh;
262 		int i;
263 
264 		if (sa->sa_nreg < 2) {
265 			printf("%s: only %d register sets\n", self->dv_xname,
266 				sa->sa_nreg);
267 			return;
268 		}
269 
270 		/* Map the system timer */
271 		i = sa->sa_nreg - 1;
272 		if (bus_space_map2(sa->sa_bustag,
273 				 BUS_ADDR(
274 					sa->sa_reg[i].sbr_slot,
275 					sa->sa_reg[i].sbr_offset),
276 				 sizeof(struct timer_4m),
277 				 BUS_SPACE_MAP_LINEAR,
278 				 TIMERREG_VA, &bh) != 0) {
279 			printf("%s: can't map register\n", self->dv_xname);
280 			return;
281 		}
282 		timerreg4m = (struct timer_4m *)TIMERREG_VA;
283 
284 		/* Map each CPU's counter */
285 		for (i = 0; i < sa->sa_nreg - 1; i++) {
286 			struct cpu_info *cpi = NULL;
287 			int n;
288 
289 			/*
290 			 * Check whether the CPU corresponding to this
291 			 * timer register is installed.
292 			 */
293 			for (n = 0; n < ncpu; n++) {
294 				if ((cpi = cpus[n]) == NULL)
295 					continue;
296 				if ((i == 0 && ncpu == 1) || cpi->mid == i + 8)
297 					/* We got a corresponding MID */
298 					break;
299 				cpi = NULL;
300 			}
301 			if (cpi == NULL)
302 				continue;
303 			if (sbus_bus_map(sa->sa_bustag,
304 					 sa->sa_reg[i].sbr_slot,
305 					 sa->sa_reg[i].sbr_offset,
306 					 sizeof(struct timer_4m),
307 					 BUS_SPACE_MAP_LINEAR,
308 					 &bh) != 0) {
309 				printf("%s: can't map register\n",
310 					self->dv_xname);
311 				return;
312 			}
313 			cpi->counterreg_4m = (struct counter_4m *)bh;
314 		}
315 
316 		/* Put processor counter in "timer" mode */
317 		timerreg4m->t_cfg = 0;
318 
319 		timerattach(&counterreg4m->t_counter, &counterreg4m->t_limit);
320 #endif /* SUN4M */
321 		return;
322 	} else {
323 #if defined(SUN4)
324 		/* sun4 timer at obio */
325 		struct obio4_attach_args *oba = &uoba->uoba_oba4;
326 		bus_space_handle_t bh;
327 
328 		if (bus_space_map2(oba->oba_bustag,
329 				  oba->oba_paddr,
330 				  sizeof(struct timerreg_4),
331 				  BUS_SPACE_MAP_LINEAR,
332 				  TIMERREG_VA,
333 				  &bh) != 0) {
334 			printf("%s: can't map register\n", self->dv_xname);
335 			return;
336 		}
337 		timerattach(&timerreg4->t_c14.t_counter,
338 			    &timerreg4->t_c14.t_limit);
339 #endif /* SUN4 */
340 	}
341 }
342 
343 /*
344  * sun4/sun4c/sun4m common timer attach code
345  */
346 static void
347 timerattach(cntreg, limreg)
348 	volatile int *cntreg, *limreg;
349 {
350 
351 	/*
352 	 * Calibrate delay() by tweaking the magic constant
353 	 * until a delay(100) actually reads (at least) 100 us on the clock.
354 	 * Note: sun4m clocks tick with 500ns periods.
355 	 */
356 	for (timerblurb = 1; ; timerblurb++) {
357 		volatile int discard;
358 		int t0, t1;
359 
360 		/* Reset counter register by writing some large limit value */
361 		discard = *limreg;
362 		*limreg = tmr_ustolim(TMR_MASK-1);
363 
364 		t0 = *cntreg;
365 		delay(100);
366 		t1 = *cntreg;
367 
368 		if (t1 & TMR_LIMIT)
369 			panic("delay calibration");
370 
371 		t0 = (t0 >> TMR_SHIFT) & TMR_MASK;
372 		t1 = (t1 >> TMR_SHIFT) & TMR_MASK;
373 
374 		if (t1 >= t0 + 100)
375 			break;
376 	}
377 
378 	printf(" delay constant %d\n", timerblurb);
379 
380 #if defined(SUN4) || defined(SUN4C)
381 	if (CPU_ISSUN4OR4C) {
382 		timer_init = timer_init_4;
383 		level10.ih_fun = clockintr_4;
384 		level14.ih_fun = statintr_4;
385 	}
386 #endif
387 #if defined(SUN4M)
388 	if (CPU_ISSUN4M) {
389 		timer_init = timer_init_4m;
390 		level10.ih_fun = clockintr_4m;
391 		level14.ih_fun = statintr_4m;
392 	}
393 #endif
394 	/* link interrupt handlers */
395 	intr_establish(10, &level10);
396 	intr_establish(14, &level14);
397 
398 	timerok = 1;
399 }
400 
401 
402 /* ARGSUSED */
403 static void
404 timerattach_msiiep(parent, self, aux)
405 	struct device *parent, *self;
406 	void *aux;
407 {
408 #if defined(MSIIEP)
409 	/*
410 	 * Attach system and cpu counters (kernel hard and stat clocks)
411 	 * for ms-IIep. Counters are part of the PCIC and there's no
412 	 * PROM node for them.
413 	 */
414 	/* Put processor counter in "counter" mode */
415 	msiiep->pcic_pc_ctl = 0; /* stop user timer (just in case) */
416 	msiiep->pcic_pc_cfg = 0; /* timer mode disabled (processor counter) */
417 
418 	/*
419 	 * Calibrate delay() by tweaking the magic constant
420 	 * until a delay(100) actually reads (at least) 100 us on the clock.
421 	 * Note: ms-IIep clocks ticks every 4 processor cycles.
422 	 */
423 	for (timerblurb = 1; ; ++timerblurb) {
424 		volatile int discard;
425 		int t;
426 
427 		discard = msiiep->pcic_pclr; /* clear the limit bit */
428 		msiiep->pcic_pclr = 0; /* reset counter to 1, free run */
429 		delay(100);
430 		t = msiiep->pcic_pccr;
431 
432 		if (t & TMR_LIMIT) /* cannot happen */
433 			panic("delay calibration");
434 
435 		/* counter ticks -> usec, inverse of tmr_ustolimIIep */
436 		t = (t - 1) / 25;
437 		if (t >= 100)
438 			break;
439 	}
440 	printf(" delay constant %d\n", timerblurb);
441 
442 	/*
443 	 * Set counter interrupt priority assignment:
444 	 * upper 4 bits are for system counter: level 10
445 	 * lower 4 bits are for processor counter: level 14
446 	 */
447 	msiiep->pcic_cipar = 0xae;
448 
449 	timer_init = timer_init_msiiep;
450 	level10.ih_fun = clockintr_msiiep;
451 	level14.ih_fun = statintr_msiiep;
452 
453 	/* link interrupt handlers */
454 	intr_establish(10, &level10);
455 	intr_establish(14, &level14);
456 
457 	timerok = 1;
458 #endif /* MSIIEP */
459 }
460 
461 /*
462  * Set up the real-time and statistics clocks.
463  * Leave stathz 0 only if no alternative timer is available.
464  *
465  * The frequencies of these clocks must be an even number of microseconds.
466  */
467 #if defined(SUN4) || defined(SUN4C)
468 void
469 timer_init_4()
470 {
471 	timerreg4->t_c10.t_limit = tmr_ustolim(tick);
472 	timerreg4->t_c14.t_limit = tmr_ustolim(statint);
473 	ienab_bis(IE_L14 | IE_L10);
474 }
475 #endif
476 
477 #if defined(SUN4M)
478 void
479 timer_init_4m()
480 {
481 	int n;
482 	timerreg4m->t_limit = tmr_ustolim4m(tick);
483 	for (n = 0; n < ncpu; n++) {
484 		struct cpu_info *cpi;
485 		if ((cpi = cpus[n]) == NULL)
486 			continue;
487 		cpi->counterreg_4m->t_limit = tmr_ustolim4m(statint);
488 	}
489 	ienab_bic(SINTR_T);
490 }
491 #endif
492 
493 #if defined(MSIIEP)
494 void
495 timer_init_msiiep()
496 {
497 	/* ms-IIep kernels support *only* IIep */
498 	msiiep->pcic_sclr = tmr_ustolimIIep(tick);
499 	msiiep->pcic_pclr = tmr_ustolimIIep(statint);
500 	/* XXX: ensure interrupt target mask doesn't masks them? */
501 }
502 #endif /* MSIIEP */
503 
504 #if defined(SUN4) || defined(SUN4C)
505 /*
506  * Level 10 (clock) interrupts from system counter.
507  */
508 int
509 clockintr_4(cap)
510 	void *cap;
511 {
512 	volatile int discard;
513 
514 	/* read the limit register to clear the interrupt */
515 	discard = timerreg4->t_c10.t_limit;
516 	hardclock((struct clockframe *)cap);
517 	return (1);
518 }
519 #endif /* SUN4/SUN4C */
520 
521 #if defined(SUN4M)
522 int
523 clockintr_4m(cap)
524 	void *cap;
525 {
526 	volatile int discard;
527 	int s;
528 
529 	/*
530 	 * Protect the clearing of the clock interrupt.  If we don't
531 	 * do this, and we're interrupted (by the zs, for example),
532 	 * the clock stops!
533 	 * XXX WHY DOES THIS HAPPEN?
534 	 */
535 	s = splhigh();
536 
537 	/* read the limit register to clear the interrupt */
538 	discard = timerreg4m->t_limit;
539 	splx(s);
540 
541 	hardclock((struct clockframe *)cap);
542 	return (1);
543 }
544 #endif /* SUN4M */
545 
546 #if defined(MSIIEP)
547 int
548 clockintr_msiiep(cap)
549 	void *cap;
550 {
551 	volatile int discard;
552 
553 	/* read the limit register to clear the interrupt */
554 	discard = msiiep->pcic_sclr;
555 	hardclock((struct clockframe *)cap);
556 	return (1);
557 }
558 #endif /* MSIIEP */
559 
560 static __inline__ u_long
561 new_interval(void)
562 {
563 	u_long newint, r, var;
564 
565 	/*
566 	 * Compute new randomized interval.  The intervals are uniformly
567 	 * distributed on [statint - statvar / 2, statint + statvar / 2],
568 	 * and therefore have mean statint, giving a stathz frequency clock.
569 	 */
570 	var = statvar;
571 	do {
572 		r = random() & (var - 1);
573 	} while (r == 0);
574 	newint = statmin + r;
575 	return (newint);
576 }
577 
578 /*
579  * Level 14 (stat clock) interrupts from processor counter.
580  */
581 #if defined(SUN4) || defined(SUN4C)
582 int
583 statintr_4(cap)
584 	void *cap;
585 {
586 	volatile int discard;
587 	u_long newint;
588 
589 	/* read the limit register to clear the interrupt */
590 	discard = timerreg4->t_c14.t_limit;
591 
592 	statclock((struct clockframe *)cap);
593 
594 	/*
595 	 * Compute new randomized interval.
596 	 */
597 	newint = new_interval();
598 
599 	/*
600 	 * The sun4/4c timer has no `non-resetting' register;
601 	 * use the current counter value to compensate the new
602 	 * limit value for the number of counter ticks elapsed.
603 	 */
604 	newint -= tmr_cnttous(timerreg4->t_c14.t_counter);
605 	timerreg4->t_c14.t_limit = tmr_ustolim(newint);
606 	return (1);
607 }
608 #endif /* SUN4/SUN4C */
609 
610 #if defined(SUN4M)
611 int
612 statintr_4m(cap)
613 	void *cap;
614 {
615 	volatile int discard;
616 	u_long newint;
617 
618 	/* read the limit register to clear the interrupt */
619 	discard = counterreg4m->t_limit;
620 	if (timerok == 0) {
621 		/* Stop the clock */
622 		printf("note: counter running!\n");
623 		discard = counterreg4m->t_limit;
624 		counterreg4m->t_limit = 0;
625 		counterreg4m->t_ss = 0;
626 		timerreg4m->t_cfg = TMR_CFG_USER;
627 		return 1;
628 	}
629 
630 	statclock((struct clockframe *)cap);
631 
632 	/*
633 	 * Compute new randomized interval.
634 	 */
635 	newint = new_interval();
636 
637 	/*
638 	 * Use the `non-resetting' limit register, so we don't
639 	 * loose the counter ticks that happened since this
640 	 * interrupt was raised.
641 	 */
642 	counterreg4m->t_limit_nr = tmr_ustolim4m(newint);
643 	return (1);
644 }
645 #endif /* SUN4M */
646 
647 #if defined(MSIIEP)
648 int
649 statintr_msiiep(cap)
650 	void *cap;
651 {
652 	volatile int discard;
653 	u_long newint;
654 
655 	/* read the limit register to clear the interrupt */
656 	discard = msiiep->pcic_pclr;
657 	if (timerok == 0) {
658 		/* Stop the clock */
659 		printf("note: counter running!\n");
660 		/*
661 		 * Turn interrupting processor counter
662 		 * into non-interrupting user timer.
663 		 */
664 		msiiep->pcic_pc_cfg = 1; /* make it a user timer */
665 		msiiep->pcic_pc_ctl = 0; /* stop user timer */
666 		return (1);
667 	}
668 
669 	statclock((struct clockframe *)cap);
670 
671 	/*
672 	 * Compute new randomized interval.
673 	 */
674 	newint = new_interval();
675 
676 	/*
677 	 * Use the `non-resetting' limit register, so we don't
678 	 * loose the counter ticks that happened since this
679 	 * interrupt was raised.
680 	 */
681 	msiiep->pcic_pclr_nr = tmr_ustolimIIep(newint);
682 	return (1);
683 }
684 #endif /* MSIIEP */
685