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