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