1/* 2 * Copyright (C) 2001,2002,2003 Broadcom Corporation 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18#include <linux/sched.h> 19#include <asm/mipsregs.h> 20#include <asm/sibyte/sb1250.h> 21#include <asm/sibyte/sb1250_regs.h> 22 23#if !defined(CONFIG_SIBYTE_BUS_WATCHER) || defined(CONFIG_SIBYTE_BW_TRACE) 24#include <asm/io.h> 25#include <asm/sibyte/sb1250_scd.h> 26#endif 27 28/* 29 * We'd like to dump the L2_ECC_TAG register on errors, but errata make 30 * that unsafe... So for now we don't. (BCM1250/BCM112x erratum SOC-48.) 31 */ 32#undef DUMP_L2_ECC_TAG_ON_ERROR 33 34/* SB1 definitions */ 35 36#define SB1_CACHE_INDEX_MASK 0x1fe0 37 38#define CP0_ERRCTL_RECOVERABLE (1 << 31) 39#define CP0_ERRCTL_DCACHE (1 << 30) 40#define CP0_ERRCTL_ICACHE (1 << 29) 41#define CP0_ERRCTL_MULTIBUS (1 << 23) 42#define CP0_ERRCTL_MC_TLB (1 << 15) 43#define CP0_ERRCTL_MC_TIMEOUT (1 << 14) 44 45#define CP0_CERRI_TAG_PARITY (1 << 29) 46#define CP0_CERRI_DATA_PARITY (1 << 28) 47#define CP0_CERRI_EXTERNAL (1 << 26) 48 49#define CP0_CERRI_IDX_VALID(c) (!((c) & CP0_CERRI_EXTERNAL)) 50#define CP0_CERRI_DATA (CP0_CERRI_DATA_PARITY) 51 52#define CP0_CERRD_MULTIPLE (1 << 31) 53#define CP0_CERRD_TAG_STATE (1 << 30) 54#define CP0_CERRD_TAG_ADDRESS (1 << 29) 55#define CP0_CERRD_DATA_SBE (1 << 28) 56#define CP0_CERRD_DATA_DBE (1 << 27) 57#define CP0_CERRD_EXTERNAL (1 << 26) 58#define CP0_CERRD_LOAD (1 << 25) 59#define CP0_CERRD_STORE (1 << 24) 60#define CP0_CERRD_FILLWB (1 << 23) 61#define CP0_CERRD_COHERENCY (1 << 22) 62#define CP0_CERRD_DUPTAG (1 << 21) 63 64#define CP0_CERRD_DPA_VALID(c) (!((c) & CP0_CERRD_EXTERNAL)) 65#define CP0_CERRD_IDX_VALID(c) \ 66 (((c) & (CP0_CERRD_LOAD | CP0_CERRD_STORE)) ? (!((c) & CP0_CERRD_EXTERNAL)) : 0) 67#define CP0_CERRD_CAUSES \ 68 (CP0_CERRD_LOAD | CP0_CERRD_STORE | CP0_CERRD_FILLWB | CP0_CERRD_COHERENCY | CP0_CERRD_DUPTAG) 69#define CP0_CERRD_TYPES \ 70 (CP0_CERRD_TAG_STATE | CP0_CERRD_TAG_ADDRESS | CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE | CP0_CERRD_EXTERNAL) 71#define CP0_CERRD_DATA (CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE) 72 73static uint32_t extract_ic(unsigned short addr, int data); 74static uint32_t extract_dc(unsigned short addr, int data); 75 76static inline void breakout_errctl(unsigned int val) 77{ 78 if (val & CP0_ERRCTL_RECOVERABLE) 79 printk(" recoverable"); 80 if (val & CP0_ERRCTL_DCACHE) 81 printk(" dcache"); 82 if (val & CP0_ERRCTL_ICACHE) 83 printk(" icache"); 84 if (val & CP0_ERRCTL_MULTIBUS) 85 printk(" multiple-buserr"); 86 printk("\n"); 87} 88 89static inline void breakout_cerri(unsigned int val) 90{ 91 if (val & CP0_CERRI_TAG_PARITY) 92 printk(" tag-parity"); 93 if (val & CP0_CERRI_DATA_PARITY) 94 printk(" data-parity"); 95 if (val & CP0_CERRI_EXTERNAL) 96 printk(" external"); 97 printk("\n"); 98} 99 100static inline void breakout_cerrd(unsigned int val) 101{ 102 switch (val & CP0_CERRD_CAUSES) { 103 case CP0_CERRD_LOAD: 104 printk(" load,"); 105 break; 106 case CP0_CERRD_STORE: 107 printk(" store,"); 108 break; 109 case CP0_CERRD_FILLWB: 110 printk(" fill/wb,"); 111 break; 112 case CP0_CERRD_COHERENCY: 113 printk(" coherency,"); 114 break; 115 case CP0_CERRD_DUPTAG: 116 printk(" duptags,"); 117 break; 118 default: 119 printk(" NO CAUSE,"); 120 break; 121 } 122 if (!(val & CP0_CERRD_TYPES)) 123 printk(" NO TYPE"); 124 else { 125 if (val & CP0_CERRD_MULTIPLE) 126 printk(" multi-err"); 127 if (val & CP0_CERRD_TAG_STATE) 128 printk(" tag-state"); 129 if (val & CP0_CERRD_TAG_ADDRESS) 130 printk(" tag-address"); 131 if (val & CP0_CERRD_DATA_SBE) 132 printk(" data-SBE"); 133 if (val & CP0_CERRD_DATA_DBE) 134 printk(" data-DBE"); 135 if (val & CP0_CERRD_EXTERNAL) 136 printk(" external"); 137 } 138 printk("\n"); 139} 140 141#ifndef CONFIG_SIBYTE_BUS_WATCHER 142 143static void check_bus_watcher(void) 144{ 145 uint32_t status, l2_err, memio_err; 146#ifdef DUMP_L2_ECC_TAG_ON_ERROR 147 uint64_t l2_tag; 148#endif 149 150 /* Destructive read, clears register and interrupt */ 151 status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS)); 152 /* Bit 31 is always on, but there's no #define for that */ 153 if (status & ~(1UL << 31)) { 154 l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS)); 155#ifdef DUMP_L2_ECC_TAG_ON_ERROR 156 l2_tag = in64(IO_SPACE_BASE | A_L2_ECC_TAG); 157#endif 158 memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS)); 159 printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err); 160 printk("\nLast recorded signature:\n"); 161 printk("Request %02x from %d, answered by %d with Dcode %d\n", 162 (unsigned int)(G_SCD_BERR_TID(status) & 0x3f), 163 (int)(G_SCD_BERR_TID(status) >> 6), 164 (int)G_SCD_BERR_RID(status), 165 (int)G_SCD_BERR_DCODE(status)); 166#ifdef DUMP_L2_ECC_TAG_ON_ERROR 167 printk("Last L2 tag w/ bad ECC: %016llx\n", l2_tag); 168#endif 169 } else { 170 printk("Bus watcher indicates no error\n"); 171 } 172} 173#else 174extern void check_bus_watcher(void); 175#endif 176 177asmlinkage void sb1_cache_error(void) 178{ 179 uint32_t errctl, cerr_i, cerr_d, dpalo, dpahi, eepc, res; 180 unsigned long long cerr_dpa; 181 182#ifdef CONFIG_SIBYTE_BW_TRACE 183 /* Freeze the trace buffer now */ 184#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) 185 csr_out32(M_BCM1480_SCD_TRACE_CFG_FREEZE, IO_SPACE_BASE | A_SCD_TRACE_CFG); 186#else 187 csr_out32(M_SCD_TRACE_CFG_FREEZE, IO_SPACE_BASE | A_SCD_TRACE_CFG); 188#endif 189 printk("Trace buffer frozen\n"); 190#endif 191 192 printk("Cache error exception on CPU %x:\n", 193 (read_c0_prid() >> 25) & 0x7); 194 195 __asm__ __volatile__ ( 196 " .set push\n\t" 197 " .set mips64\n\t" 198 " .set noat\n\t" 199 " mfc0 %0, $26\n\t" 200 " mfc0 %1, $27\n\t" 201 " mfc0 %2, $27, 1\n\t" 202 " dmfc0 $1, $27, 3\n\t" 203 " dsrl32 %3, $1, 0 \n\t" 204 " sll %4, $1, 0 \n\t" 205 " mfc0 %5, $30\n\t" 206 " .set pop" 207 : "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d), 208 "=r" (dpahi), "=r" (dpalo), "=r" (eepc)); 209 210 cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo; 211 printk(" c0_errorepc == %08x\n", eepc); 212 printk(" c0_errctl == %08x", errctl); 213 breakout_errctl(errctl); 214 if (errctl & CP0_ERRCTL_ICACHE) { 215 printk(" c0_cerr_i == %08x", cerr_i); 216 breakout_cerri(cerr_i); 217 if (CP0_CERRI_IDX_VALID(cerr_i)) { 218 /* Check index of EPC, allowing for delay slot */ 219 if (((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK)) && 220 ((eepc & SB1_CACHE_INDEX_MASK) != ((cerr_i & SB1_CACHE_INDEX_MASK) - 4))) 221 printk(" cerr_i idx doesn't match eepc\n"); 222 else { 223 res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK, 224 (cerr_i & CP0_CERRI_DATA) != 0); 225 if (!(res & cerr_i)) 226 printk("...didn't see indicated icache problem\n"); 227 } 228 } 229 } 230 if (errctl & CP0_ERRCTL_DCACHE) { 231 printk(" c0_cerr_d == %08x", cerr_d); 232 breakout_cerrd(cerr_d); 233 if (CP0_CERRD_DPA_VALID(cerr_d)) { 234 printk(" c0_cerr_dpa == %010llx\n", cerr_dpa); 235 if (!CP0_CERRD_IDX_VALID(cerr_d)) { 236 res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK, 237 (cerr_d & CP0_CERRD_DATA) != 0); 238 if (!(res & cerr_d)) 239 printk("...didn't see indicated dcache problem\n"); 240 } else { 241 if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK)) 242 printk(" cerr_d idx doesn't match cerr_dpa\n"); 243 else { 244 res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK, 245 (cerr_d & CP0_CERRD_DATA) != 0); 246 if (!(res & cerr_d)) 247 printk("...didn't see indicated problem\n"); 248 } 249 } 250 } 251 } 252 253 check_bus_watcher(); 254 255 /* 256 * Calling panic() when a fatal cache error occurs scrambles the 257 * state of the system (and the cache), making it difficult to 258 * investigate after the fact. However, if you just stall the CPU, 259 * the other CPU may keep on running, which is typically very 260 * undesirable. 261 */ 262#ifdef CONFIG_SB1_CERR_STALL 263 while (1) 264 ; 265#else 266 panic("unhandled cache error"); 267#endif 268} 269 270 271/* Parity lookup table. */ 272static const uint8_t parity[256] = { 273 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, 274 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 275 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 276 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, 277 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, 278 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, 279 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, 280 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0 281}; 282 283/* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */ 284static const uint64_t mask_72_64[8] = { 285 0x0738C808099264FFULL, 286 0x38C808099264FF07ULL, 287 0xC808099264FF0738ULL, 288 0x08099264FF0738C8ULL, 289 0x099264FF0738C808ULL, 290 0x9264FF0738C80809ULL, 291 0x64FF0738C8080992ULL, 292 0xFF0738C808099264ULL 293}; 294 295/* Calculate the parity on a range of bits */ 296static char range_parity(uint64_t dword, int max, int min) 297{ 298 char parity = 0; 299 int i; 300 dword >>= min; 301 for (i=max-min; i>=0; i--) { 302 if (dword & 0x1) 303 parity = !parity; 304 dword >>= 1; 305 } 306 return parity; 307} 308 309/* Calculate the 4-bit even byte-parity for an instruction */ 310static unsigned char inst_parity(uint32_t word) 311{ 312 int i, j; 313 char parity = 0; 314 for (j=0; j<4; j++) { 315 char byte_parity = 0; 316 for (i=0; i<8; i++) { 317 if (word & 0x80000000) 318 byte_parity = !byte_parity; 319 word <<= 1; 320 } 321 parity <<= 1; 322 parity |= byte_parity; 323 } 324 return parity; 325} 326 327static uint32_t extract_ic(unsigned short addr, int data) 328{ 329 unsigned short way; 330 int valid; 331 uint32_t taghi, taglolo, taglohi; 332 unsigned long long taglo, va; 333 uint64_t tlo_tmp; 334 uint8_t lru; 335 int res = 0; 336 337 printk("Icache index 0x%04x ", addr); 338 for (way = 0; way < 4; way++) { 339 /* Index-load-tag-I */ 340 __asm__ __volatile__ ( 341 " .set push \n\t" 342 " .set noreorder \n\t" 343 " .set mips64 \n\t" 344 " .set noat \n\t" 345 " cache 4, 0(%3) \n\t" 346 " mfc0 %0, $29 \n\t" 347 " dmfc0 $1, $28 \n\t" 348 " dsrl32 %1, $1, 0 \n\t" 349 " sll %2, $1, 0 \n\t" 350 " .set pop" 351 : "=r" (taghi), "=r" (taglohi), "=r" (taglolo) 352 : "r" ((way << 13) | addr)); 353 354 taglo = ((unsigned long long)taglohi << 32) | taglolo; 355 if (way == 0) { 356 lru = (taghi >> 14) & 0xff; 357 printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n", 358 ((addr >> 5) & 0x3), /* bank */ 359 ((addr >> 7) & 0x3f), /* index */ 360 (lru & 0x3), 361 ((lru >> 2) & 0x3), 362 ((lru >> 4) & 0x3), 363 ((lru >> 6) & 0x3)); 364 } 365 va = (taglo & 0xC0000FFFFFFFE000ULL) | addr; 366 if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3)) 367 va |= 0x3FFFF00000000000ULL; 368 valid = ((taghi >> 29) & 1); 369 if (valid) { 370 tlo_tmp = taglo & 0xfff3ff; 371 if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) { 372 printk(" ** bad parity in VTag0/G/ASID\n"); 373 res |= CP0_CERRI_TAG_PARITY; 374 } 375 if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) { 376 printk(" ** bad parity in R/VTag1\n"); 377 res |= CP0_CERRI_TAG_PARITY; 378 } 379 } 380 if (valid ^ ((taghi >> 27) & 1)) { 381 printk(" ** bad parity for valid bit\n"); 382 res |= CP0_CERRI_TAG_PARITY; 383 } 384 printk(" %d [VA %016llx] [Vld? %d] raw tags: %08X-%016llX\n", 385 way, va, valid, taghi, taglo); 386 387 if (data) { 388 uint32_t datahi, insta, instb; 389 uint8_t predecode; 390 int offset; 391 392 /* (hit all banks and ways) */ 393 for (offset = 0; offset < 4; offset++) { 394 /* Index-load-data-I */ 395 __asm__ __volatile__ ( 396 " .set push\n\t" 397 " .set noreorder\n\t" 398 " .set mips64\n\t" 399 " .set noat\n\t" 400 " cache 6, 0(%3) \n\t" 401 " mfc0 %0, $29, 1\n\t" 402 " dmfc0 $1, $28, 1\n\t" 403 " dsrl32 %1, $1, 0 \n\t" 404 " sll %2, $1, 0 \n\t" 405 " .set pop \n" 406 : "=r" (datahi), "=r" (insta), "=r" (instb) 407 : "r" ((way << 13) | addr | (offset << 3))); 408 predecode = (datahi >> 8) & 0xff; 409 if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) { 410 printk(" ** bad parity in predecode\n"); 411 res |= CP0_CERRI_DATA_PARITY; 412 } 413 /* XXXKW should/could check predecode bits themselves */ 414 if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) { 415 printk(" ** bad parity in instruction a\n"); 416 res |= CP0_CERRI_DATA_PARITY; 417 } 418 if ((datahi & 0xf) ^ inst_parity(instb)) { 419 printk(" ** bad parity in instruction b\n"); 420 res |= CP0_CERRI_DATA_PARITY; 421 } 422 printk(" %05X-%08X%08X", datahi, insta, instb); 423 } 424 printk("\n"); 425 } 426 } 427 return res; 428} 429 430/* Compute the ECC for a data doubleword */ 431static uint8_t dc_ecc(uint64_t dword) 432{ 433 uint64_t t; 434 uint32_t w; 435 uint8_t p; 436 int i; 437 438 p = 0; 439 for (i = 7; i >= 0; i--) 440 { 441 p <<= 1; 442 t = dword & mask_72_64[i]; 443 w = (uint32_t)(t >> 32); 444 p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF] 445 ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]); 446 w = (uint32_t)(t & 0xFFFFFFFF); 447 p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF] 448 ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]); 449 } 450 return p; 451} 452 453struct dc_state { 454 unsigned char val; 455 char *name; 456}; 457 458static struct dc_state dc_states[] = { 459 { 0x00, "INVALID" }, 460 { 0x0f, "COH-SHD" }, 461 { 0x13, "NCO-E-C" }, 462 { 0x19, "NCO-E-D" }, 463 { 0x16, "COH-E-C" }, 464 { 0x1c, "COH-E-D" }, 465 { 0xff, "*ERROR*" } 466}; 467 468#define DC_TAG_VALID(state) \ 469 (((state) == 0x0) || ((state) == 0xf) || ((state) == 0x13) || \ 470 ((state) == 0x19) || ((state) == 0x16) || ((state) == 0x1c)) 471 472static char *dc_state_str(unsigned char state) 473{ 474 struct dc_state *dsc = dc_states; 475 while (dsc->val != 0xff) { 476 if (dsc->val == state) 477 break; 478 dsc++; 479 } 480 return dsc->name; 481} 482 483static uint32_t extract_dc(unsigned short addr, int data) 484{ 485 int valid, way; 486 unsigned char state; 487 uint32_t taghi, taglolo, taglohi; 488 unsigned long long taglo, pa; 489 uint8_t ecc, lru; 490 int res = 0; 491 492 printk("Dcache index 0x%04x ", addr); 493 for (way = 0; way < 4; way++) { 494 __asm__ __volatile__ ( 495 " .set push\n\t" 496 " .set noreorder\n\t" 497 " .set mips64\n\t" 498 " .set noat\n\t" 499 " cache 5, 0(%3)\n\t" /* Index-load-tag-D */ 500 " mfc0 %0, $29, 2\n\t" 501 " dmfc0 $1, $28, 2\n\t" 502 " dsrl32 %1, $1, 0\n\t" 503 " sll %2, $1, 0\n\t" 504 " .set pop" 505 : "=r" (taghi), "=r" (taglohi), "=r" (taglolo) 506 : "r" ((way << 13) | addr)); 507 508 taglo = ((unsigned long long)taglohi << 32) | taglolo; 509 pa = (taglo & 0xFFFFFFE000ULL) | addr; 510 if (way == 0) { 511 lru = (taghi >> 14) & 0xff; 512 printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n", 513 ((addr >> 11) & 0x2) | ((addr >> 5) & 1), /* bank */ 514 ((addr >> 6) & 0x3f), /* index */ 515 (lru & 0x3), 516 ((lru >> 2) & 0x3), 517 ((lru >> 4) & 0x3), 518 ((lru >> 6) & 0x3)); 519 } 520 state = (taghi >> 25) & 0x1f; 521 valid = DC_TAG_VALID(state); 522 printk(" %d [PA %010llx] [state %s (%02x)] raw tags: %08X-%016llX\n", 523 way, pa, dc_state_str(state), state, taghi, taglo); 524 if (valid) { 525 if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) { 526 printk(" ** bad parity in PTag1\n"); 527 res |= CP0_CERRD_TAG_ADDRESS; 528 } 529 if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) { 530 printk(" ** bad parity in PTag0\n"); 531 res |= CP0_CERRD_TAG_ADDRESS; 532 } 533 } else { 534 res |= CP0_CERRD_TAG_STATE; 535 } 536 537 if (data) { 538 uint32_t datalohi, datalolo, datahi; 539 unsigned long long datalo; 540 int offset; 541 char bad_ecc = 0; 542 543 for (offset = 0; offset < 4; offset++) { 544 /* Index-load-data-D */ 545 __asm__ __volatile__ ( 546 " .set push\n\t" 547 " .set noreorder\n\t" 548 " .set mips64\n\t" 549 " .set noat\n\t" 550 " cache 7, 0(%3)\n\t" /* Index-load-data-D */ 551 " mfc0 %0, $29, 3\n\t" 552 " dmfc0 $1, $28, 3\n\t" 553 " dsrl32 %1, $1, 0 \n\t" 554 " sll %2, $1, 0 \n\t" 555 " .set pop" 556 : "=r" (datahi), "=r" (datalohi), "=r" (datalolo) 557 : "r" ((way << 13) | addr | (offset << 3))); 558 datalo = ((unsigned long long)datalohi << 32) | datalolo; 559 ecc = dc_ecc(datalo); 560 if (ecc != datahi) { 561 int bits = 0; 562 bad_ecc |= 1 << (3-offset); 563 ecc ^= datahi; 564 while (ecc) { 565 if (ecc & 1) bits++; 566 ecc >>= 1; 567 } 568 res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE; 569 } 570 printk(" %02X-%016llX", datahi, datalo); 571 } 572 printk("\n"); 573 if (bad_ecc) 574 printk(" dwords w/ bad ECC: %d %d %d %d\n", 575 !!(bad_ecc & 8), !!(bad_ecc & 4), 576 !!(bad_ecc & 2), !!(bad_ecc & 1)); 577 } 578 } 579 return res; 580} 581