1 /* $NetBSD: dec_kn8ae.c,v 1.45 2025/03/09 01:06:42 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1997 by Matthew Jacob 5 * NASA AMES Research Center. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice immediately at the beginning of the file, without modification, 13 * this list of conditions, and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 35 __KERNEL_RCSID(0, "$NetBSD: dec_kn8ae.c,v 1.45 2025/03/09 01:06:42 thorpej Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/lwp.h> 41 42 #include <machine/rpb.h> 43 #include <machine/autoconf.h> 44 #include <machine/cpuconf.h> 45 #include <machine/frame.h> 46 #include <machine/alpha.h> 47 #include <machine/logout.h> 48 49 #include <dev/pci/pcivar.h> 50 51 #include <alpha/tlsb/tlsbreg.h> 52 #include <alpha/tlsb/tlsbvar.h> 53 #include <alpha/tlsb/kftxxreg.h> 54 #include <alpha/tlsb/kftxxvar.h> 55 56 #define KV(_addr) ((void *)ALPHA_PHYS_TO_K0SEG((_addr))) 57 58 void dec_kn8ae_init(void); 59 void dec_kn8ae_cons_init(void); 60 static void dec_kn8ae_device_register(device_t, void *); 61 62 static void dec_kn8ae_mcheck_handler 63 (unsigned long, struct trapframe *, unsigned long, unsigned long); 64 65 const struct alpha_variation_table dec_kn8ae_variations[] = { 66 { 0, "AlphaServer 8400" }, 67 { 0, NULL }, 68 }; 69 70 void 71 dec_kn8ae_init(void) 72 { 73 uint64_t variation; 74 75 platform.family = "AlphaServer 8400"; 76 77 if ((platform.model = alpha_dsr_sysname()) == NULL) { 78 variation = hwrpb->rpb_variation & SV_ST_MASK; 79 if ((platform.model = alpha_variation_name(variation, 80 dec_kn8ae_variations)) == NULL) 81 platform.model = alpha_unknown_sysname(); 82 } 83 84 platform.iobus = "tlsb"; 85 platform.cons_init = dec_kn8ae_cons_init; 86 platform.device_register = dec_kn8ae_device_register; 87 platform.mcheck_handler = dec_kn8ae_mcheck_handler; 88 } 89 90 void 91 dec_kn8ae_cons_init(void) 92 { 93 94 /* 95 * Info to retain: 96 * 97 * The AXP 8X00 seems to encode the 98 * type of console in the ctb_type field, 99 * not the ctb_term_type field. 100 * 101 * XXX Not Type 4 CTB? 102 */ 103 } 104 105 /* #define BDEBUG 1 */ 106 static void 107 dec_kn8ae_device_register(device_t dev, void *aux) 108 { 109 static device_t primarydev; 110 struct bootdev_data *b = bootdev_data; 111 112 if (booted_device != NULL || b == NULL) { 113 return; 114 } 115 116 if (primarydev == NULL) { 117 if (device_is_a(dev, "dwlpx")) { 118 struct kft_dev_attach_args *ka = aux; 119 120 if (b->bus == ka->ka_hosenum) { 121 primarydev = dev; 122 #ifdef BDEBUG 123 printf("\nprimarydev = %s\n", 124 device_xname(dev)); 125 #endif 126 } 127 } 128 return; 129 } 130 131 pci_find_bootdev(primarydev, dev, aux); 132 } 133 134 /* 135 * KN8AE Machine Check Handlers. 136 */ 137 void kn8ae_harderr(unsigned long, unsigned long, 138 unsigned long, struct trapframe *); 139 140 static void kn8ae_softerr(unsigned long, unsigned long, 141 unsigned long, struct trapframe *); 142 143 void kn8ae_mcheck(unsigned long, unsigned long, 144 unsigned long, struct trapframe *); 145 146 /* 147 * Support routine for clearing errors 148 */ 149 static void clear_tlsb_ebits(int); 150 151 static void 152 clear_tlsb_ebits(int cpuonly) 153 { 154 int node; 155 uint32_t tldev; 156 157 for (node = 0; node <= TLSB_NODE_MAX; ++node) { 158 if ((tlsb_found & (1 << node)) == 0) 159 continue; 160 tldev = TLSB_GET_NODEREG(node, TLDEV); 161 if (tldev == 0) { 162 /* "cannot happen" */ 163 continue; 164 } 165 /* 166 * Registers to clear for all nodes. 167 */ 168 if (TLSB_GET_NODEREG(node, TLBER) & 169 (TLBER_UDE|TLBER_CWDE|TLBER_CRDE)) { 170 TLSB_PUT_NODEREG(node, TLESR0, 171 TLSB_GET_NODEREG(node, TLESR0)); 172 TLSB_PUT_NODEREG(node, TLESR1, 173 TLSB_GET_NODEREG(node, TLESR1)); 174 TLSB_PUT_NODEREG(node, TLESR2, 175 TLSB_GET_NODEREG(node, TLESR2)); 176 TLSB_PUT_NODEREG(node, TLESR3, 177 TLSB_GET_NODEREG(node, TLESR3)); 178 } 179 TLSB_PUT_NODEREG(node, TLBER, 180 TLSB_GET_NODEREG(node, TLBER)); 181 TLSB_PUT_NODEREG(node, TLFADR0, 182 TLSB_GET_NODEREG(node, TLFADR0)); 183 TLSB_PUT_NODEREG(node, TLFADR1, 184 TLSB_GET_NODEREG(node, TLFADR1)); 185 186 if (TLDEV_ISCPU(tldev)) { 187 TLSB_PUT_NODEREG(node, TLEPAERR, 188 TLSB_GET_NODEREG(node, TLEPAERR)); 189 TLSB_PUT_NODEREG(node, TLEPDERR, 190 TLSB_GET_NODEREG(node, TLEPDERR)); 191 TLSB_PUT_NODEREG(node, TLEPMERR, 192 TLSB_GET_NODEREG(node, TLEPMERR)); 193 continue; 194 } 195 /* 196 * If we're only doing CPU nodes, or this was a memory 197 * node, we're done. Onwards. 198 */ 199 if (cpuonly || TLDEV_ISMEM(tldev)) { 200 continue; 201 } 202 203 TLSB_PUT_NODEREG(node, KFT_ICCNSE, 204 TLSB_GET_NODEREG(node, KFT_ICCNSE)); 205 TLSB_PUT_NODEREG(node, KFT_IDPNSE0, 206 TLSB_GET_NODEREG(node, KFT_IDPNSE0)); 207 TLSB_PUT_NODEREG(node, KFT_IDPNSE1, 208 TLSB_GET_NODEREG(node, KFT_IDPNSE1)); 209 if (TLDEV_DTYPE(tldev) == TLDEV_DTYPE_KFTHA) { 210 TLSB_PUT_NODEREG(node, KFT_IDPNSE2, 211 TLSB_GET_NODEREG(node, KFT_IDPNSE2)); 212 TLSB_PUT_NODEREG(node, KFT_IDPNSE3, 213 TLSB_GET_NODEREG(node, KFT_IDPNSE3)); 214 } 215 /* 216 * Digital Unix cleares the Mailbox Transaction Register 217 * here. I don't think we should because we aren't using 218 * mailboxes yet, and the tech manual makes dire warnings 219 * about *not* rewriting this register. 220 */ 221 } 222 } 223 224 /* 225 * System Corrected Errors. 226 */ 227 static const char *fmt1 = " %-25s = 0x%l016x\n"; 228 229 void 230 kn8ae_harderr(unsigned long mces, unsigned long type, unsigned long logout, struct trapframe *framep) 231 { 232 int whami, cpuwerr, dof_cnt; 233 mc_hdr_ev5 *hdr; 234 mc_cc_ev5 *mptr; 235 struct tlsb_mchk_fatal *ptr; 236 237 hdr = (mc_hdr_ev5 *) logout; 238 mptr = (mc_cc_ev5 *) (logout + sizeof (*hdr)); 239 ptr = (struct tlsb_mchk_fatal *) 240 (logout + sizeof (*hdr) + sizeof (*mptr)); 241 whami = alpha_pal_whami(); 242 243 printf("kn8ae: CPU ID %d system correctable error\n", whami); 244 245 printf(" Machine Check Code 0x%lx\n", hdr->mcheck_code); 246 printf(fmt1, "EI Status", mptr->ei_stat); 247 printf(fmt1, "EI Address", mptr->ei_addr); 248 printf(fmt1, "Fill Syndrome", mptr->fill_syndrome); 249 printf(fmt1, "Interrupt Status Reg.", mptr->isr); 250 printf("\n"); 251 dof_cnt = (ptr->rsvdheader & 0xffffffff00000000) >> 32; 252 cpuwerr = ptr->rsvdheader & 0xffff; 253 254 printf(fmt1, "CPU W/Error.", cpuwerr); 255 printf(fmt1, "DOF Count.", dof_cnt); 256 printf(fmt1, "TLDEV", ptr->tldev); 257 printf(fmt1, "TLSB Bus Error", ptr->tlber); 258 printf(fmt1, "TLSB CNR", ptr->tlcnr); 259 printf(fmt1, "TLSB VID", ptr->tlvid); 260 printf(fmt1, "TLSB Error Syndrome 0", ptr->tlesr0); 261 printf(fmt1, "TLSB Error Syndrome 1", ptr->tlesr1); 262 printf(fmt1, "TLSB Error Syndrome 2", ptr->tlesr2); 263 printf(fmt1, "TLSB Error Syndrome 3", ptr->tlesr3); 264 printf(fmt1, "TLSB LEP_AERR", ptr->tlepaerr); 265 printf(fmt1, "TLSB MODCONF", ptr->tlmodconfig); 266 printf(fmt1, "TLSB LEP_MERR", ptr->tlepmerr); 267 printf(fmt1, "TLSB LEP_DERR", ptr->tlepderr); 268 printf(fmt1, "TLSB INTRMASK0", ptr->tlintrmask0); 269 printf(fmt1, "TLSB INTRMASK1", ptr->tlintrmask1); 270 printf(fmt1, "TLSB INTRSUM0", ptr->tlintrsum0); 271 printf(fmt1, "TLSB INTRSUM1", ptr->tlintrsum1); 272 printf(fmt1, "TLSB VMG", ptr->tlep_vmg); 273 274 /* CLEAN UP */ 275 /* 276 * Here's what Digital Unix says to do- 277 * 278 * 1. Log the ECC error that got us here 279 * 280 * 2. Turn off error reporting 281 * 282 * 3. Attempt to have CPU read bad memory location (specified by the 283 * tlfadr reg of the TIOP or TMEM (depending on type of error, 284 * see upcoming code branches) and write data back to location. 285 * 286 * 4. When the CPU attempts to read the location, another 620 interrupt 287 * should occur for the CPU at which instant PAL will scrub the 288 * location. Then the o.s. scrub routine finishes. If the PAL scrubs 289 * the location then the scrubbed flag should be 0 (this is what we 290 * expect). 291 * 292 * If it's a 1 then the alpha_scrub_long routine did the scrub. 293 * 294 * 5. We renable correctable error logging and continue 295 */ 296 printf("WARNING THIS IS NOT DONE YET YOU MAY GET DATA CORRUPTION"); 297 clear_tlsb_ebits(0); 298 /* 299 * Clear error by rewriting register. 300 */ 301 alpha_pal_wrmces(mces); 302 } 303 304 /* 305 * Processor Corrected Errors- BCACHE ECC errors. 306 */ 307 308 static void 309 kn8ae_softerr(unsigned long mces, unsigned long type, unsigned long logout, struct trapframe *framep) 310 { 311 int whami, cpuwerr, dof_cnt; 312 mc_hdr_ev5 *hdr; 313 mc_cc_ev5 *mptr; 314 struct tlsb_mchk_soft *ptr; 315 316 hdr = (mc_hdr_ev5 *) logout; 317 mptr = (mc_cc_ev5 *) (logout + sizeof (*hdr)); 318 ptr = (struct tlsb_mchk_soft *) 319 (logout + sizeof (*hdr) + sizeof (*mptr)); 320 whami = alpha_pal_whami(); 321 322 printf("kn8ae: CPU ID %d processor correctable error\n", whami); 323 printf(" Machine Check Code 0x%lx\n", hdr->mcheck_code); 324 printf(fmt1, "EI Status", mptr->ei_stat); 325 printf(fmt1, "EI Address", mptr->ei_addr); 326 printf(fmt1, "Fill Syndrome", mptr->fill_syndrome); 327 printf(fmt1, "Interrupt Status Reg.", mptr->isr); 328 printf("\n"); 329 dof_cnt = (ptr->rsvdheader & 0xffffffff00000000) >> 32; 330 cpuwerr = ptr->rsvdheader & 0xffff; 331 332 printf(fmt1, "CPU W/Error.", cpuwerr); 333 printf(fmt1, "DOF Count.", dof_cnt); 334 printf(fmt1, "TLDEV", ptr->tldev); 335 printf(fmt1, "TLSB Bus Error", ptr->tlber); 336 printf(fmt1, "TLSB Error Syndrome 0", ptr->tlesr0); 337 printf(fmt1, "TLSB Error Syndrome 1", ptr->tlesr1); 338 printf(fmt1, "TLSB Error Syndrome 2", ptr->tlesr2); 339 printf(fmt1, "TLSB Error Syndrome 3", ptr->tlesr3); 340 341 /* 342 * Clear TLSB bits on all CPU TLSB nodes. 343 */ 344 clear_tlsb_ebits(1); 345 346 /* 347 * Clear error by rewriting register. 348 */ 349 alpha_pal_wrmces(mces); 350 } 351 352 /* 353 * KN8AE specific machine check handler 354 */ 355 356 void 357 kn8ae_mcheck(unsigned long mces, unsigned long type, unsigned long logout, struct trapframe *framep) 358 { 359 struct mchkinfo *mcp; 360 struct tlsb_mchk_fatal mcs[TLSB_NODE_MAX+1], *ptr; 361 mc_hdr_ev5 *hdr; 362 mc_uc_ev5 *mptr; 363 364 /* 365 * If we expected a machine check, just go handle it in common code. 366 */ 367 mcp = &curcpu()->ci_mcinfo; 368 if (mcp->mc_expected) { 369 machine_check(mces, framep, type, logout); 370 return; 371 } 372 373 ptr = NULL; 374 memset(mcs, 0, sizeof (mcs)); 375 376 hdr = (mc_hdr_ev5 *) logout; 377 mptr = (mc_uc_ev5 *) (logout + sizeof (*hdr)); 378 379 /* 380 * If detected by the system, we print out some TLASER registers. 381 */ 382 if (type == ALPHA_SYS_MCHECK) { 383 #if 0 384 int get_lsb_regs = 0; 385 int get_dwlpx_regs = 0; 386 #endif 387 388 ptr = (struct tlsb_mchk_fatal *) 389 (logout + sizeof (*hdr) + sizeof (*mptr)); 390 391 #if 0 392 if (ptr->tlepaerr & TLEPAERR_WSPC_RD) { 393 get_dwlpx_regs++; 394 } 395 if ((ptr->tlepaerr & TLEPAERR_IBOX_TMO) && 396 (mptr->ic_perr_stat & EV5_IC_PERR_IBOXTMO) && 397 (ptr->tlepderr & TLEPDERR_GBTMO)) { 398 get_dwlpx_regs++; 399 } 400 #endif 401 } else { 402 /* 403 * We have a processor machine check- which doesn't 404 * have information with it about any TLSB related 405 * failures. 406 */ 407 } 408 409 /* 410 * Now we can finally print some stuff... 411 */ 412 ev5_logout_print(hdr, mptr); 413 if (type == ALPHA_SYS_MCHECK) { 414 if (ptr->tlepaerr & TLEPAERR_WSPC_RD) { 415 printf("\tWSPC READ error\n"); 416 } 417 if ((ptr->tlepaerr & TLEPAERR_IBOX_TMO) && 418 (mptr->ic_perr_stat & EV5_IC_PERR_IBOXTMO) && 419 (ptr->tlepderr & TLEPDERR_GBTMO)) { 420 printf ("\tWSPC IBOX timeout detected\n"); 421 } 422 #ifdef DIAGNOSTIC 423 printf(fmt1, "TLDEV", ptr->tldev); 424 printf(fmt1, "TLSB Bus Error", ptr->tlber); 425 printf(fmt1, "TLSB CNR", ptr->tlcnr); 426 printf(fmt1, "TLSB VID", ptr->tlvid); 427 printf(fmt1, "TLSB Error Syndrome 0", ptr->tlesr0); 428 printf(fmt1, "TLSB Error Syndrome 1", ptr->tlesr1); 429 printf(fmt1, "TLSB Error Syndrome 2", ptr->tlesr2); 430 printf(fmt1, "TLSB Error Syndrome 3", ptr->tlesr3); 431 printf(fmt1, "TLSB LEP_AERR", ptr->tlepaerr); 432 printf(fmt1, "TLSB MODCONF", ptr->tlmodconfig); 433 printf(fmt1, "TLSB LEP_MERR", ptr->tlepmerr); 434 printf(fmt1, "TLSB LEP_DERR", ptr->tlepderr); 435 printf(fmt1, "TLSB INTRMASK0", ptr->tlintrmask0); 436 printf(fmt1, "TLSB INTRMASK1", ptr->tlintrmask1); 437 printf(fmt1, "TLSB INTRSUM0", ptr->tlintrsum0); 438 printf(fmt1, "TLSB INTRSUM1", ptr->tlintrsum1); 439 printf(fmt1, "TLSB VMG", ptr->tlep_vmg); 440 #endif 441 } else { 442 } 443 444 /* 445 * Now that we've printed all sorts of useful information 446 * and have decided that we really can't do any more to 447 * respond to the error, go on to the common code for 448 * final disposition. Usually this means that we die. 449 */ 450 clear_tlsb_ebits(0); 451 452 machine_check(mces, framep, type, logout); 453 } 454 455 static void 456 dec_kn8ae_mcheck_handler(unsigned long mces, struct trapframe *framep, unsigned long vector, unsigned long param) 457 { 458 switch (vector) { 459 case ALPHA_SYS_ERROR: 460 kn8ae_harderr(mces, vector, param, framep); 461 break; 462 463 case ALPHA_PROC_ERROR: 464 kn8ae_softerr(mces, vector, param, framep); 465 break; 466 467 case ALPHA_SYS_MCHECK: 468 case ALPHA_PROC_MCHECK: 469 kn8ae_mcheck(mces, vector, param, framep); 470 break; 471 default: 472 printf("KN8AE_MCHECK: unknown check vector 0x%lx\n", vector); 473 machine_check(mces, framep, vector, param); 474 break; 475 } 476 } 477