0001
0002
0003
0004
0005 #include <linux/sched.h>
0006 #include <asm/mipsregs.h>
0007 #include <asm/sibyte/sb1250.h>
0008 #include <asm/sibyte/sb1250_regs.h>
0009
0010 #if !defined(CONFIG_SIBYTE_BUS_WATCHER) || defined(CONFIG_SIBYTE_BW_TRACE)
0011 #include <asm/io.h>
0012 #include <asm/sibyte/sb1250_scd.h>
0013 #endif
0014
0015
0016
0017
0018
0019 #undef DUMP_L2_ECC_TAG_ON_ERROR
0020
0021
0022
0023
0024 #define SB1_CACHE_INDEX_MASK 0x1fe0
0025
0026 #define CP0_ERRCTL_RECOVERABLE (1 << 31)
0027 #define CP0_ERRCTL_DCACHE (1 << 30)
0028 #define CP0_ERRCTL_ICACHE (1 << 29)
0029 #define CP0_ERRCTL_MULTIBUS (1 << 23)
0030 #define CP0_ERRCTL_MC_TLB (1 << 15)
0031 #define CP0_ERRCTL_MC_TIMEOUT (1 << 14)
0032
0033 #define CP0_CERRI_TAG_PARITY (1 << 29)
0034 #define CP0_CERRI_DATA_PARITY (1 << 28)
0035 #define CP0_CERRI_EXTERNAL (1 << 26)
0036
0037 #define CP0_CERRI_IDX_VALID(c) (!((c) & CP0_CERRI_EXTERNAL))
0038 #define CP0_CERRI_DATA (CP0_CERRI_DATA_PARITY)
0039
0040 #define CP0_CERRD_MULTIPLE (1 << 31)
0041 #define CP0_CERRD_TAG_STATE (1 << 30)
0042 #define CP0_CERRD_TAG_ADDRESS (1 << 29)
0043 #define CP0_CERRD_DATA_SBE (1 << 28)
0044 #define CP0_CERRD_DATA_DBE (1 << 27)
0045 #define CP0_CERRD_EXTERNAL (1 << 26)
0046 #define CP0_CERRD_LOAD (1 << 25)
0047 #define CP0_CERRD_STORE (1 << 24)
0048 #define CP0_CERRD_FILLWB (1 << 23)
0049 #define CP0_CERRD_COHERENCY (1 << 22)
0050 #define CP0_CERRD_DUPTAG (1 << 21)
0051
0052 #define CP0_CERRD_DPA_VALID(c) (!((c) & CP0_CERRD_EXTERNAL))
0053 #define CP0_CERRD_IDX_VALID(c) \
0054 (((c) & (CP0_CERRD_LOAD | CP0_CERRD_STORE)) ? (!((c) & CP0_CERRD_EXTERNAL)) : 0)
0055 #define CP0_CERRD_CAUSES \
0056 (CP0_CERRD_LOAD | CP0_CERRD_STORE | CP0_CERRD_FILLWB | CP0_CERRD_COHERENCY | CP0_CERRD_DUPTAG)
0057 #define CP0_CERRD_TYPES \
0058 (CP0_CERRD_TAG_STATE | CP0_CERRD_TAG_ADDRESS | CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE | CP0_CERRD_EXTERNAL)
0059 #define CP0_CERRD_DATA (CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE)
0060
0061 static uint32_t extract_ic(unsigned short addr, int data);
0062 static uint32_t extract_dc(unsigned short addr, int data);
0063
0064 static inline void breakout_errctl(unsigned int val)
0065 {
0066 if (val & CP0_ERRCTL_RECOVERABLE)
0067 printk(" recoverable");
0068 if (val & CP0_ERRCTL_DCACHE)
0069 printk(" dcache");
0070 if (val & CP0_ERRCTL_ICACHE)
0071 printk(" icache");
0072 if (val & CP0_ERRCTL_MULTIBUS)
0073 printk(" multiple-buserr");
0074 printk("\n");
0075 }
0076
0077 static inline void breakout_cerri(unsigned int val)
0078 {
0079 if (val & CP0_CERRI_TAG_PARITY)
0080 printk(" tag-parity");
0081 if (val & CP0_CERRI_DATA_PARITY)
0082 printk(" data-parity");
0083 if (val & CP0_CERRI_EXTERNAL)
0084 printk(" external");
0085 printk("\n");
0086 }
0087
0088 static inline void breakout_cerrd(unsigned int val)
0089 {
0090 switch (val & CP0_CERRD_CAUSES) {
0091 case CP0_CERRD_LOAD:
0092 printk(" load,");
0093 break;
0094 case CP0_CERRD_STORE:
0095 printk(" store,");
0096 break;
0097 case CP0_CERRD_FILLWB:
0098 printk(" fill/wb,");
0099 break;
0100 case CP0_CERRD_COHERENCY:
0101 printk(" coherency,");
0102 break;
0103 case CP0_CERRD_DUPTAG:
0104 printk(" duptags,");
0105 break;
0106 default:
0107 printk(" NO CAUSE,");
0108 break;
0109 }
0110 if (!(val & CP0_CERRD_TYPES))
0111 printk(" NO TYPE");
0112 else {
0113 if (val & CP0_CERRD_MULTIPLE)
0114 printk(" multi-err");
0115 if (val & CP0_CERRD_TAG_STATE)
0116 printk(" tag-state");
0117 if (val & CP0_CERRD_TAG_ADDRESS)
0118 printk(" tag-address");
0119 if (val & CP0_CERRD_DATA_SBE)
0120 printk(" data-SBE");
0121 if (val & CP0_CERRD_DATA_DBE)
0122 printk(" data-DBE");
0123 if (val & CP0_CERRD_EXTERNAL)
0124 printk(" external");
0125 }
0126 printk("\n");
0127 }
0128
0129 #ifndef CONFIG_SIBYTE_BUS_WATCHER
0130
0131 static void check_bus_watcher(void)
0132 {
0133 uint32_t status, l2_err, memio_err;
0134 #ifdef DUMP_L2_ECC_TAG_ON_ERROR
0135 uint64_t l2_tag;
0136 #endif
0137
0138
0139 status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
0140
0141 if (status & ~(1UL << 31)) {
0142 l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
0143 #ifdef DUMP_L2_ECC_TAG_ON_ERROR
0144 l2_tag = in64(IOADDR(A_L2_ECC_TAG));
0145 #endif
0146 memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
0147 printk("Bus watcher error counters: %08x %08x\n", l2_err, memio_err);
0148 printk("\nLast recorded signature:\n");
0149 printk("Request %02x from %d, answered by %d with Dcode %d\n",
0150 (unsigned int)(G_SCD_BERR_TID(status) & 0x3f),
0151 (int)(G_SCD_BERR_TID(status) >> 6),
0152 (int)G_SCD_BERR_RID(status),
0153 (int)G_SCD_BERR_DCODE(status));
0154 #ifdef DUMP_L2_ECC_TAG_ON_ERROR
0155 printk("Last L2 tag w/ bad ECC: %016llx\n", l2_tag);
0156 #endif
0157 } else {
0158 printk("Bus watcher indicates no error\n");
0159 }
0160 }
0161 #else
0162 extern void check_bus_watcher(void);
0163 #endif
0164
0165 asmlinkage void sb1_cache_error(void)
0166 {
0167 uint32_t errctl, cerr_i, cerr_d, dpalo, dpahi, eepc, res;
0168 unsigned long long cerr_dpa;
0169
0170 #ifdef CONFIG_SIBYTE_BW_TRACE
0171
0172 csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
0173 printk("Trace buffer frozen\n");
0174 #endif
0175
0176 printk("Cache error exception on CPU %x:\n",
0177 (read_c0_prid() >> 25) & 0x7);
0178
0179 __asm__ __volatile__ (
0180 " .set push\n\t"
0181 " .set mips64\n\t"
0182 " .set noat\n\t"
0183 " mfc0 %0, $26\n\t"
0184 " mfc0 %1, $27\n\t"
0185 " mfc0 %2, $27, 1\n\t"
0186 " dmfc0 $1, $27, 3\n\t"
0187 " dsrl32 %3, $1, 0 \n\t"
0188 " sll %4, $1, 0 \n\t"
0189 " mfc0 %5, $30\n\t"
0190 " .set pop"
0191 : "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d),
0192 "=r" (dpahi), "=r" (dpalo), "=r" (eepc));
0193
0194 cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo;
0195 printk(" c0_errorepc == %08x\n", eepc);
0196 printk(" c0_errctl == %08x", errctl);
0197 breakout_errctl(errctl);
0198 if (errctl & CP0_ERRCTL_ICACHE) {
0199 printk(" c0_cerr_i == %08x", cerr_i);
0200 breakout_cerri(cerr_i);
0201 if (CP0_CERRI_IDX_VALID(cerr_i)) {
0202
0203 if (((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK)) &&
0204 ((eepc & SB1_CACHE_INDEX_MASK) != ((cerr_i & SB1_CACHE_INDEX_MASK) - 4)))
0205 printk(" cerr_i idx doesn't match eepc\n");
0206 else {
0207 res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
0208 (cerr_i & CP0_CERRI_DATA) != 0);
0209 if (!(res & cerr_i))
0210 printk("...didn't see indicated icache problem\n");
0211 }
0212 }
0213 }
0214 if (errctl & CP0_ERRCTL_DCACHE) {
0215 printk(" c0_cerr_d == %08x", cerr_d);
0216 breakout_cerrd(cerr_d);
0217 if (CP0_CERRD_DPA_VALID(cerr_d)) {
0218 printk(" c0_cerr_dpa == %010llx\n", cerr_dpa);
0219 if (!CP0_CERRD_IDX_VALID(cerr_d)) {
0220 res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK,
0221 (cerr_d & CP0_CERRD_DATA) != 0);
0222 if (!(res & cerr_d))
0223 printk("...didn't see indicated dcache problem\n");
0224 } else {
0225 if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
0226 printk(" cerr_d idx doesn't match cerr_dpa\n");
0227 else {
0228 res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
0229 (cerr_d & CP0_CERRD_DATA) != 0);
0230 if (!(res & cerr_d))
0231 printk("...didn't see indicated problem\n");
0232 }
0233 }
0234 }
0235 }
0236
0237 check_bus_watcher();
0238
0239
0240
0241
0242
0243
0244
0245
0246 #ifdef CONFIG_SB1_CERR_STALL
0247 while (1)
0248 ;
0249 #else
0250 panic("unhandled cache error");
0251 #endif
0252 }
0253
0254
0255
0256 static const uint8_t parity[256] = {
0257 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0258 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0259 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0260 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0261 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0262 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0263 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0264 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0265 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0266 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0267 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0268 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0269 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0270 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0271 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
0272 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
0273 };
0274
0275
0276 static const uint64_t mask_72_64[8] = {
0277 0x0738C808099264FFULL,
0278 0x38C808099264FF07ULL,
0279 0xC808099264FF0738ULL,
0280 0x08099264FF0738C8ULL,
0281 0x099264FF0738C808ULL,
0282 0x9264FF0738C80809ULL,
0283 0x64FF0738C8080992ULL,
0284 0xFF0738C808099264ULL
0285 };
0286
0287
0288 static char range_parity(uint64_t dword, int max, int min)
0289 {
0290 char parity = 0;
0291 int i;
0292 dword >>= min;
0293 for (i=max-min; i>=0; i--) {
0294 if (dword & 0x1)
0295 parity = !parity;
0296 dword >>= 1;
0297 }
0298 return parity;
0299 }
0300
0301
0302 static unsigned char inst_parity(uint32_t word)
0303 {
0304 int i, j;
0305 char parity = 0;
0306 for (j=0; j<4; j++) {
0307 char byte_parity = 0;
0308 for (i=0; i<8; i++) {
0309 if (word & 0x80000000)
0310 byte_parity = !byte_parity;
0311 word <<= 1;
0312 }
0313 parity <<= 1;
0314 parity |= byte_parity;
0315 }
0316 return parity;
0317 }
0318
0319 static uint32_t extract_ic(unsigned short addr, int data)
0320 {
0321 unsigned short way;
0322 int valid;
0323 uint32_t taghi, taglolo, taglohi;
0324 unsigned long long taglo, va;
0325 uint64_t tlo_tmp;
0326 uint8_t lru;
0327 int res = 0;
0328
0329 printk("Icache index 0x%04x ", addr);
0330 for (way = 0; way < 4; way++) {
0331
0332 __asm__ __volatile__ (
0333 " .set push \n\t"
0334 " .set noreorder \n\t"
0335 " .set mips64 \n\t"
0336 " .set noat \n\t"
0337 " cache 4, 0(%3) \n\t"
0338 " mfc0 %0, $29 \n\t"
0339 " dmfc0 $1, $28 \n\t"
0340 " dsrl32 %1, $1, 0 \n\t"
0341 " sll %2, $1, 0 \n\t"
0342 " .set pop"
0343 : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
0344 : "r" ((way << 13) | addr));
0345
0346 taglo = ((unsigned long long)taglohi << 32) | taglolo;
0347 if (way == 0) {
0348 lru = (taghi >> 14) & 0xff;
0349 printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
0350 ((addr >> 5) & 0x3),
0351 ((addr >> 7) & 0x3f),
0352 (lru & 0x3),
0353 ((lru >> 2) & 0x3),
0354 ((lru >> 4) & 0x3),
0355 ((lru >> 6) & 0x3));
0356 }
0357 va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
0358 if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
0359 va |= 0x3FFFF00000000000ULL;
0360 valid = ((taghi >> 29) & 1);
0361 if (valid) {
0362 tlo_tmp = taglo & 0xfff3ff;
0363 if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) {
0364 printk(" ** bad parity in VTag0/G/ASID\n");
0365 res |= CP0_CERRI_TAG_PARITY;
0366 }
0367 if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
0368 printk(" ** bad parity in R/VTag1\n");
0369 res |= CP0_CERRI_TAG_PARITY;
0370 }
0371 }
0372 if (valid ^ ((taghi >> 27) & 1)) {
0373 printk(" ** bad parity for valid bit\n");
0374 res |= CP0_CERRI_TAG_PARITY;
0375 }
0376 printk(" %d [VA %016llx] [Vld? %d] raw tags: %08X-%016llX\n",
0377 way, va, valid, taghi, taglo);
0378
0379 if (data) {
0380 uint32_t datahi, insta, instb;
0381 uint8_t predecode;
0382 int offset;
0383
0384
0385 for (offset = 0; offset < 4; offset++) {
0386
0387 __asm__ __volatile__ (
0388 " .set push\n\t"
0389 " .set noreorder\n\t"
0390 " .set mips64\n\t"
0391 " .set noat\n\t"
0392 " cache 6, 0(%3) \n\t"
0393 " mfc0 %0, $29, 1\n\t"
0394 " dmfc0 $1, $28, 1\n\t"
0395 " dsrl32 %1, $1, 0 \n\t"
0396 " sll %2, $1, 0 \n\t"
0397 " .set pop \n"
0398 : "=r" (datahi), "=r" (insta), "=r" (instb)
0399 : "r" ((way << 13) | addr | (offset << 3)));
0400 predecode = (datahi >> 8) & 0xff;
0401 if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) {
0402 printk(" ** bad parity in predecode\n");
0403 res |= CP0_CERRI_DATA_PARITY;
0404 }
0405
0406 if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
0407 printk(" ** bad parity in instruction a\n");
0408 res |= CP0_CERRI_DATA_PARITY;
0409 }
0410 if ((datahi & 0xf) ^ inst_parity(instb)) {
0411 printk(" ** bad parity in instruction b\n");
0412 res |= CP0_CERRI_DATA_PARITY;
0413 }
0414 printk(" %05X-%08X%08X", datahi, insta, instb);
0415 }
0416 printk("\n");
0417 }
0418 }
0419 return res;
0420 }
0421
0422
0423 static uint8_t dc_ecc(uint64_t dword)
0424 {
0425 uint64_t t;
0426 uint32_t w;
0427 uint8_t p;
0428 int i;
0429
0430 p = 0;
0431 for (i = 7; i >= 0; i--)
0432 {
0433 p <<= 1;
0434 t = dword & mask_72_64[i];
0435 w = (uint32_t)(t >> 32);
0436 p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
0437 ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
0438 w = (uint32_t)(t & 0xFFFFFFFF);
0439 p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
0440 ^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
0441 }
0442 return p;
0443 }
0444
0445 struct dc_state {
0446 unsigned char val;
0447 char *name;
0448 };
0449
0450 static struct dc_state dc_states[] = {
0451 { 0x00, "INVALID" },
0452 { 0x0f, "COH-SHD" },
0453 { 0x13, "NCO-E-C" },
0454 { 0x19, "NCO-E-D" },
0455 { 0x16, "COH-E-C" },
0456 { 0x1c, "COH-E-D" },
0457 { 0xff, "*ERROR*" }
0458 };
0459
0460 #define DC_TAG_VALID(state) \
0461 (((state) == 0x0) || ((state) == 0xf) || ((state) == 0x13) || \
0462 ((state) == 0x19) || ((state) == 0x16) || ((state) == 0x1c))
0463
0464 static char *dc_state_str(unsigned char state)
0465 {
0466 struct dc_state *dsc = dc_states;
0467 while (dsc->val != 0xff) {
0468 if (dsc->val == state)
0469 break;
0470 dsc++;
0471 }
0472 return dsc->name;
0473 }
0474
0475 static uint32_t extract_dc(unsigned short addr, int data)
0476 {
0477 int valid, way;
0478 unsigned char state;
0479 uint32_t taghi, taglolo, taglohi;
0480 unsigned long long taglo, pa;
0481 uint8_t ecc, lru;
0482 int res = 0;
0483
0484 printk("Dcache index 0x%04x ", addr);
0485 for (way = 0; way < 4; way++) {
0486 __asm__ __volatile__ (
0487 " .set push\n\t"
0488 " .set noreorder\n\t"
0489 " .set mips64\n\t"
0490 " .set noat\n\t"
0491 " cache 5, 0(%3)\n\t"
0492 " mfc0 %0, $29, 2\n\t"
0493 " dmfc0 $1, $28, 2\n\t"
0494 " dsrl32 %1, $1, 0\n\t"
0495 " sll %2, $1, 0\n\t"
0496 " .set pop"
0497 : "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
0498 : "r" ((way << 13) | addr));
0499
0500 taglo = ((unsigned long long)taglohi << 32) | taglolo;
0501 pa = (taglo & 0xFFFFFFE000ULL) | addr;
0502 if (way == 0) {
0503 lru = (taghi >> 14) & 0xff;
0504 printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
0505 ((addr >> 11) & 0x2) | ((addr >> 5) & 1),
0506 ((addr >> 6) & 0x3f),
0507 (lru & 0x3),
0508 ((lru >> 2) & 0x3),
0509 ((lru >> 4) & 0x3),
0510 ((lru >> 6) & 0x3));
0511 }
0512 state = (taghi >> 25) & 0x1f;
0513 valid = DC_TAG_VALID(state);
0514 printk(" %d [PA %010llx] [state %s (%02x)] raw tags: %08X-%016llX\n",
0515 way, pa, dc_state_str(state), state, taghi, taglo);
0516 if (valid) {
0517 if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
0518 printk(" ** bad parity in PTag1\n");
0519 res |= CP0_CERRD_TAG_ADDRESS;
0520 }
0521 if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
0522 printk(" ** bad parity in PTag0\n");
0523 res |= CP0_CERRD_TAG_ADDRESS;
0524 }
0525 } else {
0526 res |= CP0_CERRD_TAG_STATE;
0527 }
0528
0529 if (data) {
0530 uint32_t datalohi, datalolo, datahi;
0531 unsigned long long datalo;
0532 int offset;
0533 char bad_ecc = 0;
0534
0535 for (offset = 0; offset < 4; offset++) {
0536
0537 __asm__ __volatile__ (
0538 " .set push\n\t"
0539 " .set noreorder\n\t"
0540 " .set mips64\n\t"
0541 " .set noat\n\t"
0542 " cache 7, 0(%3)\n\t"
0543 " mfc0 %0, $29, 3\n\t"
0544 " dmfc0 $1, $28, 3\n\t"
0545 " dsrl32 %1, $1, 0 \n\t"
0546 " sll %2, $1, 0 \n\t"
0547 " .set pop"
0548 : "=r" (datahi), "=r" (datalohi), "=r" (datalolo)
0549 : "r" ((way << 13) | addr | (offset << 3)));
0550 datalo = ((unsigned long long)datalohi << 32) | datalolo;
0551 ecc = dc_ecc(datalo);
0552 if (ecc != datahi) {
0553 int bits;
0554 bad_ecc |= 1 << (3-offset);
0555 ecc ^= datahi;
0556 bits = hweight8(ecc);
0557 res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
0558 }
0559 printk(" %02X-%016llX", datahi, datalo);
0560 }
0561 printk("\n");
0562 if (bad_ecc)
0563 printk(" dwords w/ bad ECC: %d %d %d %d\n",
0564 !!(bad_ecc & 8), !!(bad_ecc & 4),
0565 !!(bad_ecc & 2), !!(bad_ecc & 1));
0566 }
0567 }
0568 return res;
0569 }