xref: /netbsd/sys/arch/sparc/sparc/timer_sun4m.c (revision 6550d01e)
1 /*	$NetBSD: timer_sun4m.c,v 1.23 2011/01/27 06:24:59 mrg 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  * Sun4m timer support.
58  */
59 
60 #include <sys/cdefs.h>
61 __KERNEL_RCSID(0, "$NetBSD: timer_sun4m.c,v 1.23 2011/01/27 06:24:59 mrg Exp $");
62 
63 #include <sys/param.h>
64 #include <sys/kernel.h>
65 #include <sys/device.h>
66 #include <sys/systm.h>
67 #include <sys/cpu.h>
68 
69 #include <machine/autoconf.h>
70 #include <machine/bus.h>
71 
72 #include <sparc/sparc/vaddrs.h>
73 #include <sparc/sparc/cpuvar.h>
74 #include <sparc/sparc/timerreg.h>
75 #include <sparc/sparc/timervar.h>
76 
77 struct timer_4m		*timerreg4m;
78 #define	counterreg4m	cpuinfo.counterreg_4m
79 
80 /*
81  * Set up the real-time and statistics clocks.
82  * Leave stathz 0 only if no alternative timer is available.
83  *
84  * The frequencies of these clocks must be an even number of microseconds.
85  */
86 void
87 timer_init_4m(void)
88 {
89 	struct cpu_info *cpi;
90 	int n;
91 
92 	timerreg4m->t_limit = tmr_ustolim4m(tick);
93 	for (CPU_INFO_FOREACH(n, cpi)) {
94 		cpi->counterreg_4m->t_limit = tmr_ustolim4m(statint);
95 	}
96 	icr_si_bic(SINTR_T);
97 }
98 
99 void
100 schedintr_4m(void *v)
101 {
102 
103 #ifdef MULTIPROCESSOR
104 	/*
105 	 * We call hardclock() here so that we make sure it is called on
106 	 * all CPUs.  This function ends up being called on sun4m systems
107 	 * every tick.
108 	 */
109 	hardclock(v);
110 
111 	/*
112 	 * The factor 8 is only valid for stathz==100.
113 	 * See also clock.c
114 	 */
115 	if ((++cpuinfo.ci_schedstate.spc_schedticks & 7) == 0 && schedhz != 0)
116 #endif
117 		schedclock(curlwp);
118 }
119 
120 
121 /*
122  * Level 10 (clock) interrupts from system counter.
123  */
124 int
125 clockintr_4m(void *cap)
126 {
127 
128 	/*
129 	 * XXX this needs to be fixed in a more general way
130 	 * problem is that the kernel enables interrupts and THEN
131 	 * sets up clocks. In between there's an opportunity to catch
132 	 * a timer interrupt - if we call hardclock() at that point we'll
133 	 * panic
134 	 * so for now just bail when cold
135 	 *
136 	 * For MP, we defer calling hardclock() to the schedintr so
137 	 * that we call it on all cpus.
138 	 */
139 	if (cold)
140 		return 0;
141 	/* read the limit register to clear the interrupt */
142 	*((volatile int *)&timerreg4m->t_limit);
143 	tickle_tc();
144 #if !defined(MULTIPROCESSOR)
145 	hardclock((struct clockframe *)cap);
146 #endif
147 	return (1);
148 }
149 
150 /*
151  * Level 14 (stat clock) interrupts from processor counter.
152  */
153 int
154 statintr_4m(void *cap)
155 {
156 	struct clockframe *frame = cap;
157 	u_long newint;
158 
159 	/* read the limit register to clear the interrupt */
160 	*((volatile int *)&counterreg4m->t_limit);
161 
162 	statclock(frame);
163 
164 	/*
165 	 * Compute new randomized interval.
166 	 */
167 	newint = new_interval();
168 
169 	/*
170 	 * Use the `non-resetting' limit register, so we don't
171 	 * loose the counter ticks that happened since this
172 	 * interrupt was raised.
173 	 */
174 	counterreg4m->t_limit_nr = tmr_ustolim4m(newint);
175 
176 	/*
177 	 * The factor 8 is only valid for stathz==100.
178 	 * See also clock.c
179 	 */
180 #if !defined(MULTIPROCESSOR)
181 	if ((++cpuinfo.ci_schedstate.spc_schedticks & 7) == 0 && schedhz != 0) {
182 #endif
183 		if (CLKF_LOPRI(frame, IPL_SCHED)) {
184 			/* No need to schedule a soft interrupt */
185 			spllowerschedclock();
186 			schedintr_4m(cap);
187 		} else {
188 			/*
189 			 * We're interrupting a thread that may have the
190 			 * scheduler lock; run schedintr_4m() on this CPU later.
191 			 */
192 			raise_ipi(&cpuinfo, IPL_SCHED); /* sched_cookie->pil */
193 		}
194 #if !defined(MULTIPROCESSOR)
195 	}
196 #endif
197 
198 	return (1);
199 }
200 
201 void
202 timerattach_obio_4m(struct device *parent, struct device *self, void *aux)
203 {
204 	union obio_attach_args *uoba = aux;
205 	struct sbus_attach_args *sa = &uoba->uoba_sbus;
206 	struct cpu_info *cpi;
207 	bus_space_handle_t bh;
208 	int i, n;
209 
210 	if (sa->sa_nreg < 2) {
211 		printf(": only %d register sets\n", sa->sa_nreg);
212 		return;
213 	}
214 
215 	/* Map the system timer */
216 	i = sa->sa_nreg - 1;
217 	if (bus_space_map2(sa->sa_bustag,
218 			   BUS_ADDR(sa->sa_reg[i].oa_space,
219 				    sa->sa_reg[i].oa_base),
220 			   sizeof(struct timer_4m),
221 			   BUS_SPACE_MAP_LINEAR,
222 			   TIMERREG_VA, &bh) != 0) {
223 		printf(": can't map registers\n");
224 		return;
225 	}
226 	timerreg4m = (struct timer_4m *)TIMERREG_VA;
227 
228 	/* Map each CPU's counter */
229 	for (i = 0; i < sa->sa_nreg - 1; i++) {
230 		/*
231 		 * Check whether the CPU corresponding to this timer
232 		 * register is installed.
233 		 */
234 		for (CPU_INFO_FOREACH(n, cpi)) {
235 			if ((i == 0 && sparc_ncpus == 1) || cpi->mid == i + 8) {
236 				/* We got a corresponding MID. */
237 				break;
238 			}
239 			cpi = NULL;
240 		}
241 		if (cpi == NULL)
242 			continue;
243 
244 		if (sbus_bus_map(sa->sa_bustag,
245 				 sa->sa_reg[i].oa_space,
246 				 sa->sa_reg[i].oa_base,
247 				 sizeof(struct timer_4m),
248 				 BUS_SPACE_MAP_LINEAR,
249 				 &bh) != 0) {
250 			printf(": can't map CPU counter %d\n", i);
251 			return;
252 		}
253 		cpi->counterreg_4m = (struct counter_4m *)bh;
254 	}
255 
256 	/* Put processor counter in "timer" mode */
257 	timerreg4m->t_cfg = 0;
258 
259 	timerattach(&timerreg4m->t_counter, &timerreg4m->t_limit);
260 }
261