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 53static void ka780_memerr(void); 54static int ka780_mchk(void *); 55static void ka780_conf(void); 56static void ka780_attach_cpu(device_t); 57static int getsort(int type); 58 59static int mem_sbi_match(device_t, cfdata_t, void *); 60static void mem_sbi_attach(device_t, device_t, void *); 61 62CFATTACH_DECL_NEW(mem_sbi, sizeof(struct mem_softc), 63 mem_sbi_match, mem_sbi_attach, NULL, NULL); 64 65int 66mem_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 77int 78getsort(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 106static const char * const ka780_devs[] = { "cpu", "sbi", NULL }; 107 108/* 109 * Declaration of 780-specific calls. 110 */ 111const 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 */ 126struct 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 */ 171void 172mem_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 */ 209const 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 233static void 234memlog(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 */ 253void 254ka780_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 302const char mc780[][3] = { 303 "0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15" 304}; 305 306struct 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 322int 323ka780_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 345struct ka78x { 346 unsigned snr:12, 347 plant:3, 348 eco:8, 349 v785:1, 350 type:8; 351}; 352 353void 354ka780_conf(void) 355{ 356 /* Enable cache */ 357 mtpr(0x200000, PR_SBIMT); 358 359} 360 361void 362ka780_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