xref: /netbsd/sys/arch/sparc/sparc/memreg.c (revision bf9ec67e)
1 /*	$NetBSD: memreg.c,v 1.32 2002/03/11 16:27:04 pk Exp $ */
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratory.
15  *	This product includes software developed by Harvard University.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. All advertising materials mentioning features or use of this software
26  *    must display the following acknowledgement:
27  *	This product includes software developed by the University of
28  *	California, Berkeley and its contributors.
29  *	This product includes software developed by Harvard University.
30  * 4. Neither the name of the University nor the names of its contributors
31  *    may be used to endorse or promote products derived from this software
32  *    without specific prior written permission.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  *
46  *	@(#)memreg.c	8.1 (Berkeley) 6/11/93
47  */
48 #include "opt_sparc_arch.h"
49 
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/proc.h>
53 #include <sys/device.h>
54 
55 #include <machine/autoconf.h>
56 #include <machine/ctlreg.h>
57 
58 #include <sparc/sparc/memreg.h>
59 #include <sparc/sparc/vaddrs.h>
60 #include <sparc/sparc/asm.h>
61 #include <sparc/sparc/cpuvar.h>
62 
63 #include <machine/reg.h>	/* for trapframe */
64 #include <machine/trap.h>	/* for trap types */
65 
66 static int	memregmatch_mainbus
67 			__P((struct device *, struct cfdata *, void *));
68 static int	memregmatch_obio
69 			__P((struct device *, struct cfdata *, void *));
70 static void	memregattach_mainbus
71 			__P((struct device *, struct device *, void *));
72 static void	memregattach_obio
73 			__P((struct device *, struct device *, void *));
74 
75 struct cfattach memreg_mainbus_ca = {
76 	sizeof(struct device), memregmatch_mainbus, memregattach_mainbus
77 };
78 
79 struct cfattach memreg_obio_ca = {
80 	sizeof(struct device), memregmatch_obio, memregattach_obio
81 };
82 
83 #if defined(SUN4M)
84 static void hardmemerr4m __P((unsigned, u_int, u_int, u_int, u_int));
85 #endif
86 
87 /*
88  * The OPENPROM calls this "memory-error".
89  */
90 static int
91 memregmatch_mainbus(parent, cf, aux)
92 	struct device *parent;
93 	struct cfdata *cf;
94 	void *aux;
95 {
96 	struct mainbus_attach_args *ma = aux;
97 
98 	return (strcmp("memory-error", ma->ma_name) == 0);
99 }
100 
101 static int
102 memregmatch_obio(parent, cf, aux)
103 	struct device *parent;
104 	struct cfdata *cf;
105 	void *aux;
106 {
107 	union obio_attach_args *uoba = aux;
108 
109 	if (uoba->uoba_isobio4 == 0)
110 		return (strcmp("memory-error", uoba->uoba_sbus.sa_name) == 0);
111 
112 	if (!CPU_ISSUN4) {
113 		printf("memregmatch_obio: attach args mixed up\n");
114 		return (0);
115 	}
116 
117 	return (1);
118 }
119 
120 /* ARGSUSED */
121 static void
122 memregattach_mainbus(parent, self, aux)
123 	struct device *parent, *self;
124 	void *aux;
125 {
126 	struct mainbus_attach_args *ma = aux;
127 	bus_space_handle_t bh;
128 
129 	printf("\n");
130 	if (ma->ma_promvaddr != 0) {
131 		par_err_reg = (volatile int *)ma->ma_promvaddr;
132 		return;
133 	}
134 
135 	if (bus_space_map(ma->ma_bustag,
136 			   ma->ma_paddr,
137 			   sizeof(par_err_reg),
138 			   BUS_SPACE_MAP_LINEAR,
139 			   &bh) != 0) {
140 		printf("memregattach_mainbus: can't map register\n");
141 		return;
142 	}
143 	par_err_reg = (volatile int *)bh;
144 }
145 
146 /* ARGSUSED */
147 static void
148 memregattach_obio(parent, self, aux)
149 	struct device *parent, *self;
150 	void *aux;
151 {
152 	union obio_attach_args *uoba = aux;
153 	bus_space_handle_t bh;
154 
155 	if (uoba->uoba_isobio4 == 0) {
156 		struct sbus_attach_args *sa = &uoba->uoba_sbus;
157 		if (sa->sa_promvaddr != 0) {
158 			par_err_reg = (volatile int *)sa->sa_promvaddr;
159 			return;
160 		}
161 
162 		if (sbus_bus_map(sa->sa_bustag,
163 				 sa->sa_slot, sa->sa_offset,
164 				 sizeof(par_err_reg),
165 				 BUS_SPACE_MAP_LINEAR, &bh) != 0) {
166 			printf("memregattach_obio: can't map register\n");
167 			return;
168 		}
169 		par_err_reg = (volatile int *)bh;
170 	}
171 
172 	/* On sun4, `par_err_reg' has already been mapped in autoconf.c */
173 	if (par_err_reg == NULL)
174 		panic("memregattach");
175 
176 	printf("\n");
177 }
178 
179 /*
180  * Synchronous and asynchronous memory error handler.
181  * (This is the level 15 interrupt, which is not vectored.)
182  * Should kill the process that got its bits clobbered,
183  * and take the page out of the page pool, but for now...
184  */
185 
186 void
187 memerr4_4c(issync, ser, sva, aer, ava, tf)
188 	unsigned int issync;
189 	u_int ser, sva, aer, ava;
190 	struct trapframe *tf;	/* XXX - unused/invalid */
191 {
192 	char bits[64];
193 
194 	printf("%ssync mem arr: ser=%s sva=0x%x ",
195 		issync ? "" : "a",
196 		bitmask_snprintf(ser, SER_BITS, bits, sizeof(bits)),
197 		sva);
198 	printf("aer=%s ava=0x%x\n", bitmask_snprintf(aer & 0xff,
199 		AER_BITS, bits, sizeof(bits)), ava);
200 	if (par_err_reg)
201 		printf("parity error register = %s\n",
202 			bitmask_snprintf(*par_err_reg, PER_BITS,
203 					 bits, sizeof(bits)));
204 	panic("memory error");		/* XXX */
205 }
206 
207 
208 #if defined(SUN4M)
209 /*
210  * hardmemerr4m: called upon fatal memory error. Print a message and panic.
211  */
212 static void
213 hardmemerr4m(type, sfsr, sfva, afsr, afva)
214 	unsigned type;
215 	u_int sfsr;
216 	u_int sfva;
217 	u_int afsr;
218 	u_int afva;
219 {
220 	char *s, bits[64];
221 
222 	printf("memory fault: type %d", type);
223 	s = bitmask_snprintf(sfsr, SFSR_BITS, bits, sizeof(bits));
224 	printf("sfsr=%s sfva=0x%x\n", s, sfva);
225 
226 	if (afsr != 0) {
227 		s = bitmask_snprintf(afsr, AFSR_BITS, bits, sizeof(bits));
228 		printf("; afsr=%s afva=0x%x%x\n", s,
229 			(afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
230 	}
231 
232 	if ((sfsr & SFSR_FT) == SFSR_FT_NONE  && (afsr & AFSR_AFO) == 0)
233 		return;
234 
235 	panic("hard memory error");
236 }
237 
238 /*
239  * Memerr4m: handle a non-trivial memory fault. These include HyperSPARC
240  * asynchronous faults, SuperSPARC store-buffer copyback failures, and
241  * data faults without a valid faulting VA. We try to retry the operation
242  * once, and then fail if we get called again.
243  */
244 
245 /* XXXSMP */
246 static int addrold = (int) 0xdeadbeef; /* We pick an unlikely address */
247 static int addroldtop = (int) 0xdeadbeef;
248 static int oldtype = -1;
249 /* XXXSMP */
250 
251 void
252 hypersparc_memerr(type, sfsr, sfva, tf)
253 	unsigned type;
254 	u_int sfsr;
255 	u_int sfva;
256 	struct trapframe *tf;
257 {
258 	u_int afsr;
259 	u_int afva;
260 
261 	if ((tf->tf_psr & PSR_PS) == 0)
262 		KERNEL_PROC_LOCK(curproc);
263 	else
264 		KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
265 
266 	(*cpuinfo.get_asyncflt)(&afsr, &afva);
267 	if ((afsr & AFSR_AFO) != 0) {	/* HS async fault! */
268 
269 		printf("HyperSPARC async cache memory failure at phys 0x%x%x\n",
270 		       (afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
271 
272 		if (afva == addrold && (afsr & AFSR_AFA) == addroldtop)
273 			goto hard;
274 
275 		oldtype = -1;
276 		addrold = afva;
277 		addroldtop = afsr & AFSR_AFA;
278 	}
279 out:
280 	if ((tf->tf_psr & PSR_PS) == 0)
281 		KERNEL_PROC_UNLOCK(curproc);
282 	else
283 		KERNEL_UNLOCK();
284 	return;
285 
286 hard:
287 	hardmemerr4m(type, sfsr, sfva, afsr, afva);
288 	goto out;
289 }
290 
291 void
292 viking_memerr(type, sfsr, sfva, tf)
293 	unsigned type;
294 	u_int sfsr;
295 	u_int sfva;
296 	struct trapframe *tf;
297 {
298 	u_int afsr=0;	/* No Async fault registers on the viking */
299 	u_int afva=0;
300 
301 	if ((tf->tf_psr & PSR_PS) == 0)
302 		KERNEL_PROC_LOCK(curproc);
303 	else
304 		KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
305 
306 	if (type == T_STOREBUFFAULT) {
307 
308 		/*
309 		 * On Supersparc, we try to re-enable the store buffers
310 		 * to force a retry.
311 		 */
312 		printf("store buffer copy-back failure at 0x%x. Retrying...\n",
313 		       sfva);
314 
315 		if (oldtype == T_STOREBUFFAULT || addrold == sfva)
316 			goto hard;
317 
318 		oldtype = T_STOREBUFFAULT;
319 		addrold = sfva;
320 
321 		/* re-enable store buffer */
322 		sta(SRMMU_PCR, ASI_SRMMU,
323 		    lda(SRMMU_PCR, ASI_SRMMU) | VIKING_PCR_SB);
324 
325 	} else if (type == T_DATAFAULT && (sfsr & SFSR_FAV) == 0) {
326 		/*
327 		 * bizarre.
328 		 * XXX: Should handle better. See SuperSPARC manual pg. 9-35
329 		 */
330 		printf("warning: got data fault with no faulting address."
331 		       " Ignoring.\n");
332 
333 		if (oldtype == T_DATAFAULT)
334 			goto hard;
335 		oldtype = T_DATAFAULT;
336 	}
337 
338 out:
339 	if ((tf->tf_psr & PSR_PS) == 0)
340 		KERNEL_PROC_UNLOCK(curproc);
341 	else
342 		KERNEL_UNLOCK();
343 	return;
344 
345 hard:
346 	hardmemerr4m(type, sfsr, sfva, afsr, afva);
347 	goto out;
348 }
349 
350 void
351 memerr4m(type, sfsr, sfva, tf)
352 	unsigned type;
353 	u_int sfsr;
354 	u_int sfva;
355 	struct trapframe *tf;
356 {
357 	u_int afsr;
358 	u_int afva;
359 
360 	if ((tf->tf_psr & PSR_PS) == 0)
361 		KERNEL_PROC_LOCK(curproc);
362 	else
363 		KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
364 
365 	/*
366 	 * No known special cases.
367 	 * Just get async registers, if any, and report the unhandled case.
368 	 */
369 	if ((*cpuinfo.get_asyncflt)(&afsr, &afva) != 0)
370 		afsr = afva = 0;
371 
372 	hardmemerr4m(type, sfsr, sfva, afsr, afva);
373 	if ((tf->tf_psr & PSR_PS) == 0)
374 		KERNEL_PROC_UNLOCK(curproc);
375 	else
376 		KERNEL_UNLOCK();
377 }
378 #endif /* SUN4M */
379