xref: /netbsd/sys/arch/sparc/sparc/memreg.c (revision 6550d01e)
1 /*	$NetBSD: memreg.c,v 1.43 2008/12/17 19:09:56 cegger 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 
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: memreg.c,v 1.43 2008/12/17 19:09:56 cegger Exp $");
51 
52 #include "opt_sparc_arch.h"
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/proc.h>
57 #include <sys/device.h>
58 
59 #include <machine/autoconf.h>
60 #include <machine/ctlreg.h>
61 
62 #include <sparc/sparc/memreg.h>
63 #include <sparc/sparc/vaddrs.h>
64 #include <sparc/sparc/asm.h>
65 #include <sparc/sparc/cpuvar.h>
66 
67 #include <machine/pte.h>
68 #include <machine/reg.h>	/* for trapframe */
69 #include <machine/trap.h>	/* for trap types */
70 
71 static int	memregmatch_mainbus(struct device *, struct cfdata *, void *);
72 static int	memregmatch_obio(struct device *, struct cfdata *, void *);
73 static void	memregattach_mainbus(struct device *, struct device *, void *);
74 static void	memregattach_obio(struct device *, struct device *, void *);
75 
76 CFATTACH_DECL(memreg_mainbus, sizeof(struct device),
77     memregmatch_mainbus, memregattach_mainbus, NULL, NULL);
78 
79 CFATTACH_DECL(memreg_obio, sizeof(struct device),
80     memregmatch_obio, memregattach_obio, NULL, NULL);
81 
82 #if defined(SUN4M)
83 static void hardmemerr4m(unsigned, u_int, u_int, u_int, u_int);
84 #endif
85 
86 /*
87  * The OPENPROM calls this "memory-error".
88  */
89 static int
90 memregmatch_mainbus(struct device *parent, struct cfdata *cf, void *aux)
91 {
92 	struct mainbus_attach_args *ma = aux;
93 
94 	return (strcmp("memory-error", ma->ma_name) == 0);
95 }
96 
97 static int
98 memregmatch_obio(struct device *parent, struct cfdata *cf, void *aux)
99 {
100 	union obio_attach_args *uoba = aux;
101 
102 	if (uoba->uoba_isobio4 == 0)
103 		return (strcmp("memory-error", uoba->uoba_sbus.sa_name) == 0);
104 
105 	if (!CPU_ISSUN4) {
106 		printf("memregmatch_obio: attach args mixed up\n");
107 		return (0);
108 	}
109 
110 	return (1);
111 }
112 
113 /* ARGSUSED */
114 static void
115 memregattach_mainbus(struct device *parent, struct device *self, void *aux)
116 {
117 	struct mainbus_attach_args *ma = aux;
118 	bus_space_handle_t bh;
119 
120 	printf("\n");
121 	if (ma->ma_promvaddr != 0) {
122 		par_err_reg = (volatile int *)ma->ma_promvaddr;
123 		return;
124 	}
125 
126 	if (bus_space_map(ma->ma_bustag,
127 			   ma->ma_paddr,
128 			   sizeof(par_err_reg),
129 			   BUS_SPACE_MAP_LINEAR,
130 			   &bh) != 0) {
131 		printf("memregattach_mainbus: can't map register\n");
132 		return;
133 	}
134 	par_err_reg = (volatile int *)bh;
135 }
136 
137 /* ARGSUSED */
138 static void
139 memregattach_obio(struct device *parent, struct device *self, void *aux)
140 {
141 	union obio_attach_args *uoba = aux;
142 	bus_space_handle_t bh;
143 
144 	if (uoba->uoba_isobio4 == 0) {
145 		struct sbus_attach_args *sa = &uoba->uoba_sbus;
146 		if (sa->sa_promvaddr != 0) {
147 			par_err_reg = (volatile int *)sa->sa_promvaddr;
148 			return;
149 		}
150 
151 		if (sbus_bus_map(sa->sa_bustag,
152 				 sa->sa_slot, sa->sa_offset,
153 				 sizeof(par_err_reg),
154 				 BUS_SPACE_MAP_LINEAR, &bh) != 0) {
155 			printf("memregattach_obio: can't map register\n");
156 			return;
157 		}
158 		par_err_reg = (volatile int *)bh;
159 	}
160 
161 	/* On sun4, `par_err_reg' has already been mapped in autoconf.c */
162 	if (par_err_reg == NULL)
163 		panic("memregattach");
164 
165 	printf("\n");
166 }
167 
168 /*
169  * Synchronous and asynchronous memory error handler.
170  * (This is the level 15 interrupt, which is not vectored.)
171  * Should kill the process that got its bits clobbered,
172  * and take the page out of the page pool, but for now...
173  */
174 
175 void
176 memerr4_4c(unsigned int issync,
177 	   u_int ser, u_int sva, u_int aer, u_int ava,
178 	   struct trapframe *tf) /* XXX - unused/invalid */
179 {
180 	char bits[64];
181 	u_int pte;
182 
183 	snprintb(bits, sizeof(bits), SER_BITS, ser);
184 	printf("%ssync mem arr: ser=%s sva=0x%x ",
185 	    issync ? "" : "a", bits, sva);
186 	snprintb(bits, sizeof(bits), AER_BITS, aer & 0xff);
187 	printf("aer=%s ava=0x%x\n", bits, ava);
188 
189 	pte = getpte4(sva);
190 	if ((pte & PG_V) != 0 && (pte & PG_TYPE) == PG_OBMEM) {
191 		u_int pa = (pte & PG_PFNUM) << PGSHIFT;
192 		printf(" spa=0x%x, module location: %s\n", pa,
193 			prom_pa_location(pa, 0));
194 	}
195 
196 	pte = getpte4(ava);
197 	if ((pte & PG_V) != 0 && (pte & PG_TYPE) == PG_OBMEM) {
198 		u_int pa = (pte & PG_PFNUM) << PGSHIFT;
199 		printf(" apa=0x%x, module location: %s\n", pa,
200 			prom_pa_location(pa, 0));
201 	}
202 
203 	if (par_err_reg) {
204 		snprintb(bits, sizeof(bits), PER_BITS, *par_err_reg);
205 		printf("parity error register = %s\n", bits);
206 	}
207 	panic("memory error");		/* XXX */
208 }
209 
210 
211 #if defined(SUN4M)
212 /*
213  * hardmemerr4m: called upon fatal memory error. Print a message and panic.
214  */
215 static void
216 hardmemerr4m(unsigned type, u_int sfsr, u_int sfva, u_int afsr, u_int afva)
217 {
218 	char bits[64];
219 
220 	printf("memory fault: type %d", type);
221 	snprintb(bits, sizeof(bits), SFSR_BITS, sfsr);
222 	printf("sfsr=%s sfva=0x%x\n", bits, sfva);
223 
224 	if (afsr != 0) {
225 		snprintb(bits, sizeof(bits), AFSR_BITS, afsr);
226 		printf("; afsr=%s afva=0x%x%x\n", bits,
227 			(afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
228 	}
229 
230 	if ((sfsr & SFSR_FT) == SFSR_FT_NONE  && (afsr & AFSR_AFO) == 0)
231 		return;
232 
233 	panic("hard memory error");
234 }
235 
236 /*
237  * Memerr4m: handle a non-trivial memory fault. These include HyperSPARC
238  * asynchronous faults, SuperSPARC store-buffer copyback failures, and
239  * data faults without a valid faulting VA. We try to retry the operation
240  * once, and then fail if we get called again.
241  */
242 
243 /* XXXSMP */
244 static int addrold = (int) 0xdeadbeef; /* We pick an unlikely address */
245 static int addroldtop = (int) 0xdeadbeef;
246 static int oldtype = -1;
247 /* XXXSMP */
248 
249 void
250 hypersparc_memerr(unsigned type, u_int sfsr, u_int sfva, struct trapframe *tf)
251 {
252 	u_int afsr;
253 	u_int afva;
254 
255 	KERNEL_LOCK(1, NULL);
256 
257 	(*cpuinfo.get_asyncflt)(&afsr, &afva);
258 	if ((afsr & AFSR_AFO) != 0) {	/* HS async fault! */
259 
260 		printf("HyperSPARC async cache memory failure at phys 0x%x%x\n",
261 		       (afsr & AFSR_AFA) >> AFSR_AFA_RSHIFT, afva);
262 
263 		if (afva == addrold && (afsr & AFSR_AFA) == addroldtop)
264 			goto hard;
265 
266 		oldtype = -1;
267 		addrold = afva;
268 		addroldtop = afsr & AFSR_AFA;
269 	}
270 out:
271 	KERNEL_UNLOCK_ONE(NULL);
272 	return;
273 
274 hard:
275 	hardmemerr4m(type, sfsr, sfva, afsr, afva);
276 	goto out;
277 }
278 
279 void
280 viking_memerr(unsigned type, u_int sfsr, u_int sfva, struct trapframe *tf)
281 {
282 	u_int afsr=0;	/* No Async fault registers on the viking */
283 	u_int afva=0;
284 
285 	KERNEL_LOCK(1, NULL);
286 
287 	if (type == T_STOREBUFFAULT) {
288 
289 		/*
290 		 * On Supersparc, we try to re-enable the store buffers
291 		 * to force a retry.
292 		 */
293 		printf("store buffer copy-back failure at 0x%x. Retrying...\n",
294 		       sfva);
295 
296 		if (oldtype == T_STOREBUFFAULT || addrold == sfva)
297 			goto hard;
298 
299 		oldtype = T_STOREBUFFAULT;
300 		addrold = sfva;
301 
302 		/* re-enable store buffer */
303 		sta(SRMMU_PCR, ASI_SRMMU,
304 		    lda(SRMMU_PCR, ASI_SRMMU) | VIKING_PCR_SB);
305 
306 	} else if (type == T_DATAFAULT && (sfsr & SFSR_FAV) == 0) {
307 		/*
308 		 * bizarre.
309 		 * XXX: Should handle better. See SuperSPARC manual pg. 9-35
310 		 */
311 		printf("warning: got data fault with no faulting address."
312 		       " Ignoring.\n");
313 
314 		if (oldtype == T_DATAFAULT)
315 			goto hard;
316 		oldtype = T_DATAFAULT;
317 	}
318 
319 out:
320 	KERNEL_UNLOCK_ONE(NULL);
321 	return;
322 
323 hard:
324 	hardmemerr4m(type, sfsr, sfva, afsr, afva);
325 	goto out;
326 }
327 
328 void
329 memerr4m(unsigned type, u_int sfsr, u_int sfva, struct trapframe *tf)
330 {
331 	u_int afsr;
332 	u_int afva;
333 
334 	KERNEL_LOCK(1, NULL);
335 
336 	/*
337 	 * No known special cases.
338 	 * Just get async registers, if any, and report the unhandled case.
339 	 */
340 	if ((*cpuinfo.get_asyncflt)(&afsr, &afva) != 0)
341 		afsr = afva = 0;
342 
343 	hardmemerr4m(type, sfsr, sfva, afsr, afva);
344 	KERNEL_UNLOCK_ONE(NULL);
345 }
346 #endif /* SUN4M */
347