1 /* $NetBSD: ka780.c,v 1.35 2024/02/04 18:47:27 andvar Exp $ */
2 /*-
3 * Copyright (c) 1982, 1986, 1988 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * @(#)ka780.c 7.4 (Berkeley) 5/9/91
31 */
32
33 /*
34 * 780-specific code.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ka780.c,v 1.35 2024/02/04 18:47:27 andvar Exp $");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/bus.h>
43 #include <sys/cpu.h>
44 #include <sys/device.h>
45
46 #include <machine/nexus.h>
47 #include <machine/sid.h>
48 #include <machine/clock.h>
49
50 #include "ioconf.h"
51 #include "locators.h"
52
53 static void ka780_memerr(void);
54 static int ka780_mchk(void *);
55 static void ka780_conf(void);
56 static void ka780_attach_cpu(device_t);
57 static int getsort(int type);
58
59 static int mem_sbi_match(device_t, cfdata_t, void *);
60 static void mem_sbi_attach(device_t, device_t, void *);
61
62 CFATTACH_DECL_NEW(mem_sbi, sizeof(struct mem_softc),
63 mem_sbi_match, mem_sbi_attach, NULL, NULL);
64
65 int
mem_sbi_match(device_t parent,cfdata_t cf,void * aux)66 mem_sbi_match(device_t parent, cfdata_t cf, void *aux)
67 {
68 struct sbi_attach_args * const sa = aux;
69
70 if (cf->cf_loc[SBICF_TR] != sa->sa_nexnum &&
71 cf->cf_loc[SBICF_TR] != SBICF_TR_DEFAULT)
72 return 0;
73
74 return getsort(sa->sa_type);
75 }
76
77 int
getsort(int type)78 getsort(int type)
79 {
80 switch (type) {
81 case NEX_MEM4:
82 case NEX_MEM4I:
83 case NEX_MEM16:
84 case NEX_MEM16I:
85 return M780C;
86
87 case NEX_MEM64I:
88 case NEX_MEM64L:
89 case NEX_MEM64LI:
90 case NEX_MEM256I:
91 case NEX_MEM256L:
92 case NEX_MEM256LI:
93 return M780EL;
94
95 case NEX_MEM64U:
96 case NEX_MEM64UI:
97 case NEX_MEM256U:
98 case NEX_MEM256UI:
99 return M780EU;
100
101 default:
102 return M_NONE;
103 }
104 }
105
106 static const char * const ka780_devs[] = { "cpu", "sbi", NULL };
107
108 /*
109 * Declaration of 780-specific calls.
110 */
111 const struct cpu_dep ka780_calls = {
112 .cpu_mchk = ka780_mchk,
113 .cpu_memerr = ka780_memerr,
114 .cpu_conf = ka780_conf,
115 .cpu_gettime = generic_gettime,
116 .cpu_settime = generic_settime,
117 .cpu_vups = 2, /* ~VUPS */
118 .cpu_scbsz = 5, /* SCB pages */
119 .cpu_devs = ka780_devs,
120 .cpu_attach_cpu = ka780_attach_cpu,
121 };
122
123 /*
124 * Memory controller register usage varies per controller.
125 */
126 struct mcr780 {
127 int mc_reg[4];
128 };
129
130 #define M780_ICRD 0x40000000 /* inhibit crd interrupts, in [2] */
131 #define M780_HIER 0x20000000 /* high error rate, in reg[2] */
132 #define M780_ERLOG 0x10000000 /* error log request, in reg[2] */
133 /* on a 780, memory crd's occur only when bit 15 is set in the SBIER */
134 /* register; bit 14 there is an error bit which we also clear */
135 /* these bits are in the back of the ``red book'' (or in the VMS code) */
136
137 #define M780C_INH(mcr) \
138 ((mcr)->mc_reg[2] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
139 mtpr(0, PR_SBIER);
140 #define M780C_ENA(mcr) \
141 ((mcr)->mc_reg[2] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
142 #define M780C_ERR(mcr) \
143 ((mcr)->mc_reg[2] & (M780_ERLOG))
144
145 #define M780C_SYN(mcr) ((mcr)->mc_reg[2] & 0xff)
146 #define M780C_ADDR(mcr) (((mcr)->mc_reg[2] >> 8) & 0xfffff)
147
148 #define M780EL_INH(mcr) \
149 ((mcr)->mc_reg[2] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
150 mtpr(0, PR_SBIER);
151 #define M780EL_ENA(mcr) \
152 ((mcr)->mc_reg[2] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
153 #define M780EL_ERR(mcr) \
154 ((mcr)->mc_reg[2] & (M780_ERLOG))
155
156 #define M780EL_SYN(mcr) ((mcr)->mc_reg[2] & 0x7f)
157 #define M780EL_ADDR(mcr) (((mcr)->mc_reg[2] >> 11) & 0x1ffff)
158
159 #define M780EU_INH(mcr) \
160 ((mcr)->mc_reg[3] = (M780_ICRD|M780_HIER|M780_ERLOG)); \
161 mtpr(0, PR_SBIER);
162 #define M780EU_ENA(mcr) \
163 ((mcr)->mc_reg[3] = (M780_HIER|M780_ERLOG)); mtpr(3<<14, PR_SBIER);
164 #define M780EU_ERR(mcr) \
165 ((mcr)->mc_reg[3] & (M780_ERLOG))
166
167 #define M780EU_SYN(mcr) ((mcr)->mc_reg[3] & 0x7f)
168 #define M780EU_ADDR(mcr) (((mcr)->mc_reg[3] >> 11) & 0x1ffff)
169
170 /* enable crd interrupts */
171 void
mem_sbi_attach(device_t parent,device_t self,void * aux)172 mem_sbi_attach(device_t parent, device_t self, void *aux)
173 {
174 struct sbi_attach_args * const sa = (struct sbi_attach_args *)aux;
175 struct mem_softc * const sc = device_private(self);
176 struct mcr780 * const mcr = (void *)sa->sa_ioh; /* XXX */
177
178 sc->sc_dev = self;
179 sc->sc_memaddr = (void *)sa->sa_ioh; /* XXX */
180 sc->sc_memtype = getsort(sa->sa_type);
181 sc->sc_memnr = sa->sa_type;
182
183 switch (sc->sc_memtype) {
184 case M780C:
185 aprint_normal(": standard");
186 M780C_ENA(mcr);
187 break;
188
189 case M780EL:
190 aprint_normal(": (el) ");
191 M780EL_ENA(mcr);
192 if (sc->sc_memnr != NEX_MEM64I && sc->sc_memnr != NEX_MEM256I)
193 break;
194
195 case M780EU:
196 aprint_normal(": (eu)");
197 M780EU_ENA(mcr);
198 break;
199 }
200 printf("\n");
201 }
202
203 #ifdef TRENDATA
204 /*
205 * Figure out what chip to replace on Trendata boards.
206 * Assumes all your memory is Trendata or the non-Trendata
207 * memory never fails..
208 */
209 const struct {
210 u_char m_syndrome;
211 char m_chip[4];
212 } memlogtab[] = {
213 {0x01, "C00"}, {0x02, "C01"}, {0x04, "C02"}, {0x08, "C03"},
214 {0x10, "C04"}, {0x19, "L01"}, {0x1A, "L02"}, {0x1C, "L04"},
215 {0x1F, "L07"}, {0x20, "C05"}, {0x38, "L00"}, {0x3B, "L03"},
216 {0x3D, "L05"}, {0x3E, "L06"}, {0x40, "C06"}, {0x49, "L09"},
217 {0x4A, "L10"}, {0x4c, "L12"}, {0x4F, "L15"}, {0x51, "L17"},
218 {0x52, "L18"}, {0x54, "L20"}, {0x57, "L23"}, {0x58, "L24"},
219 {0x5B, "L27"}, {0x5D, "L29"}, {0x5E, "L30"}, {0x68, "L08"},
220 {0x6B, "L11"}, {0x6D, "L13"}, {0x6E, "L14"}, {0x70, "L16"},
221 {0x73, "L19"}, {0x75, "L21"}, {0x76, "L22"}, {0x79, "L25"},
222 {0x7A, "L26"}, {0x7C, "L28"}, {0x7F, "L31"}, {0x80, "C07"},
223 {0x89, "U01"}, {0x8A, "U02"}, {0x8C, "U04"}, {0x8F, "U07"},
224 {0x91, "U09"}, {0x92, "U10"}, {0x94, "U12"}, {0x97, "U15"},
225 {0x98, "U16"}, {0x9B, "U19"}, {0x9D, "U21"}, {0x9E, "U22"},
226 {0xA8, "U00"}, {0xAB, "U03"}, {0xAD, "U05"}, {0xAE, "U06"},
227 {0xB0, "U08"}, {0xB3, "U11"}, {0xB5, "U13"}, {0xB6, "U14"},
228 {0xB9, "U17"}, {0xBA, "U18"}, {0xBC, "U20"}, {0xBF, "U23"},
229 {0xC1, "U25"}, {0xC2, "U26"}, {0xC4, "U28"}, {0xC7, "U31"},
230 {0xE0, "U24"}, {0xE3, "U27"}, {0xE5, "U29"}, {0xE6, "U30"}
231 };
232
233 static void
memlog(int m,struct mcr780 * mcr)234 memlog(int m, struct mcr780 *mcr)
235 {
236 int i;
237
238 for (i = 0; i < __arraycount(memlogtab); i++)
239 if ((u_char)(M780C_SYN(mcr)) == memlogtab[i].m_syndrome) {
240 printf(
241 "mcr%d: replace %s chip in %s bank of memory"
242 " board %d (0-15)\n",
243 m, memlogtab[i].m_chip,
244 (M780C_ADDR(mcr) & 0x8000) ? "upper" : "lower",
245 (M780C_ADDR(mcr) >> 16));
246 return;
247 }
248 printf("mcr%d: multiple errors, not traceable\n", m);
249 }
250 #endif /* TRENDATA */
251
252 /* log crd errors */
253 void
ka780_memerr(void)254 ka780_memerr(void)
255 {
256 struct mem_softc *sc;
257 struct mcr780 *mcr;
258 int m;
259
260 for (m = 0; m < mem_cd.cd_ndevs; m++) {
261 sc = device_lookup_private(&mem_cd, m);
262 if (sc == NULL)
263 continue;
264 mcr = (struct mcr780 *)sc->sc_memaddr;
265 switch (sc->sc_memtype) {
266
267 case M780C:
268 if (M780C_ERR(mcr)) {
269 aprint_error_dev(sc->sc_dev,
270 "soft ecc addr %x syn %x\n",
271 M780C_ADDR(mcr), M780C_SYN(mcr));
272 #ifdef TRENDATA
273 memlog(m, mcr);
274 #endif
275 M780C_INH(mcr);
276 }
277 break;
278
279 case M780EL:
280 if (M780EL_ERR(mcr)) {
281 aprint_error_dev(sc->sc_dev,
282 "soft ecc addr %x syn %x\n",
283 M780EL_ADDR(mcr), M780EL_SYN(mcr));
284 M780EL_INH(mcr);
285 }
286 if (sc->sc_memnr != NEX_MEM64I &&
287 sc->sc_memnr != NEX_MEM256I)
288 break;
289
290 case M780EU:
291 if (M780EU_ERR(mcr)) {
292 aprint_error_dev(sc->sc_dev,
293 "soft ecc addr %x syn %x\n",
294 M780EU_ADDR(mcr), M780EU_SYN(mcr));
295 M780EU_INH(mcr);
296 }
297 break;
298 }
299 }
300 }
301
302 const char mc780[][3] = {
303 "0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"
304 };
305
306 struct mc780frame {
307 int mc8_bcnt; /* byte count == 0x28 */
308 int mc8_summary; /* summary parameter (as above) */
309 int mc8_cpues; /* cpu error status */
310 int mc8_upc; /* micro pc */
311 int mc8_vaviba; /* va/viba register */
312 int mc8_dreg; /* d register */
313 int mc8_tber0; /* tbuf error reg 0 */
314 int mc8_tber1; /* tbuf error reg 1 */
315 int mc8_timo; /* timeout address divided by 4 */
316 int mc8_parity; /* parity */
317 int mc8_sbier; /* sbi error register */
318 int mc8_pc; /* trapped pc */
319 int mc8_psl; /* trapped psl */
320 };
321
322 int
ka780_mchk(void * cmcf)323 ka780_mchk(void *cmcf)
324 {
325 struct mc780frame * const mcf = (struct mc780frame *)cmcf;
326 int type = mcf->mc8_summary;
327 int sbifs;
328
329 printf("machine check %x: %s%s\n", type, mc780[type&0xf],
330 (type&0xf0) ? " abort" : " fault");
331 printf("\tcpues %x upc %x va/viba %x dreg %x tber %x %x\n",
332 mcf->mc8_cpues, mcf->mc8_upc, mcf->mc8_vaviba,
333 mcf->mc8_dreg, mcf->mc8_tber0, mcf->mc8_tber1);
334 sbifs = mfpr(PR_SBIFS);
335 printf("\ttimo %x parity %x sbier %x pc %x psl %x sbifs %x\n",
336 mcf->mc8_timo*4, mcf->mc8_parity, mcf->mc8_sbier,
337 mcf->mc8_pc, mcf->mc8_psl, sbifs);
338 /* THE FUNNY BITS IN THE FOLLOWING ARE FROM THE ``BLACK BOOK'' */
339 /* AND SHOULD BE PUT IN AN ``sbi.h'' */
340 mtpr(sbifs &~ 0x2000000, PR_SBIFS);
341 mtpr(mfpr(PR_SBIER) | 0x70c0, PR_SBIER);
342 return (MCHK_PANIC);
343 }
344
345 struct ka78x {
346 unsigned snr:12,
347 plant:3,
348 eco:8,
349 v785:1,
350 type:8;
351 };
352
353 void
ka780_conf(void)354 ka780_conf(void)
355 {
356 /* Enable cache */
357 mtpr(0x200000, PR_SBIMT);
358
359 }
360
361 void
ka780_attach_cpu(device_t self)362 ka780_attach_cpu(device_t self)
363 {
364 struct ka78x * const ka78 = (void *)&vax_cpudata;
365
366 aprint_normal(": KA%s, S/N %d(%d), hardware ECO level %d(%d)\n",
367 cpu_getmodel() + 7, ka78->snr, ka78->plant, ka78->eco >> 4, ka78->eco);
368 aprint_normal_dev(self, "4KB L1 cache");
369 if (mfpr(PR_ACCS) & 255) {
370 aprint_normal(", FPA present\n");
371 mtpr(0x8000, PR_ACCS);
372 } else
373 aprint_normal(", no FPA\n");
374
375 }
376