Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/mm/cerr-sb1.c
10818 views
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
/* XXX should come from config1 XXX */
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
74
static uint32_t extract_ic(unsigned short addr, int data);
75
static uint32_t extract_dc(unsigned short addr, int data);
76
77
static 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
90
static 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
101
static 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
144
static 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
/* Destructive read, clears register and interrupt */
152
status = csr_in32(IOADDR(A_SCD_BUS_ERR_STATUS));
153
/* Bit 31 is always on, but there's no #define for that */
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
175
extern void check_bus_watcher(void);
176
#endif
177
178
asmlinkage 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
/* Freeze the trace buffer now */
185
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
186
csr_out32(M_BCM1480_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
187
#else
188
csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
189
#endif
190
printk("Trace buffer frozen\n");
191
#endif
192
193
printk("Cache error exception on CPU %x:\n",
194
(read_c0_prid() >> 25) & 0x7);
195
196
__asm__ __volatile__ (
197
" .set push\n\t"
198
" .set mips64\n\t"
199
" .set noat\n\t"
200
" mfc0 %0, $26\n\t"
201
" mfc0 %1, $27\n\t"
202
" mfc0 %2, $27, 1\n\t"
203
" dmfc0 $1, $27, 3\n\t"
204
" dsrl32 %3, $1, 0 \n\t"
205
" sll %4, $1, 0 \n\t"
206
" mfc0 %5, $30\n\t"
207
" .set pop"
208
: "=r" (errctl), "=r" (cerr_i), "=r" (cerr_d),
209
"=r" (dpahi), "=r" (dpalo), "=r" (eepc));
210
211
cerr_dpa = (((uint64_t)dpahi) << 32) | dpalo;
212
printk(" c0_errorepc == %08x\n", eepc);
213
printk(" c0_errctl == %08x", errctl);
214
breakout_errctl(errctl);
215
if (errctl & CP0_ERRCTL_ICACHE) {
216
printk(" c0_cerr_i == %08x", cerr_i);
217
breakout_cerri(cerr_i);
218
if (CP0_CERRI_IDX_VALID(cerr_i)) {
219
/* Check index of EPC, allowing for delay slot */
220
if (((eepc & SB1_CACHE_INDEX_MASK) != (cerr_i & SB1_CACHE_INDEX_MASK)) &&
221
((eepc & SB1_CACHE_INDEX_MASK) != ((cerr_i & SB1_CACHE_INDEX_MASK) - 4)))
222
printk(" cerr_i idx doesn't match eepc\n");
223
else {
224
res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
225
(cerr_i & CP0_CERRI_DATA) != 0);
226
if (!(res & cerr_i))
227
printk("...didn't see indicated icache problem\n");
228
}
229
}
230
}
231
if (errctl & CP0_ERRCTL_DCACHE) {
232
printk(" c0_cerr_d == %08x", cerr_d);
233
breakout_cerrd(cerr_d);
234
if (CP0_CERRD_DPA_VALID(cerr_d)) {
235
printk(" c0_cerr_dpa == %010llx\n", cerr_dpa);
236
if (!CP0_CERRD_IDX_VALID(cerr_d)) {
237
res = extract_dc(cerr_dpa & SB1_CACHE_INDEX_MASK,
238
(cerr_d & CP0_CERRD_DATA) != 0);
239
if (!(res & cerr_d))
240
printk("...didn't see indicated dcache problem\n");
241
} else {
242
if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
243
printk(" cerr_d idx doesn't match cerr_dpa\n");
244
else {
245
res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
246
(cerr_d & CP0_CERRD_DATA) != 0);
247
if (!(res & cerr_d))
248
printk("...didn't see indicated problem\n");
249
}
250
}
251
}
252
}
253
254
check_bus_watcher();
255
256
/*
257
* Calling panic() when a fatal cache error occurs scrambles the
258
* state of the system (and the cache), making it difficult to
259
* investigate after the fact. However, if you just stall the CPU,
260
* the other CPU may keep on running, which is typically very
261
* undesirable.
262
*/
263
#ifdef CONFIG_SB1_CERR_STALL
264
while (1)
265
;
266
#else
267
panic("unhandled cache error");
268
#endif
269
}
270
271
272
/* Parity lookup table. */
273
static const uint8_t parity[256] = {
274
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,
276
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
277
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
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
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
283
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
284
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
285
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
286
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
287
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
288
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
289
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
290
};
291
292
/* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
293
static const uint64_t mask_72_64[8] = {
294
0x0738C808099264FFULL,
295
0x38C808099264FF07ULL,
296
0xC808099264FF0738ULL,
297
0x08099264FF0738C8ULL,
298
0x099264FF0738C808ULL,
299
0x9264FF0738C80809ULL,
300
0x64FF0738C8080992ULL,
301
0xFF0738C808099264ULL
302
};
303
304
/* Calculate the parity on a range of bits */
305
static char range_parity(uint64_t dword, int max, int min)
306
{
307
char parity = 0;
308
int i;
309
dword >>= min;
310
for (i=max-min; i>=0; i--) {
311
if (dword & 0x1)
312
parity = !parity;
313
dword >>= 1;
314
}
315
return parity;
316
}
317
318
/* Calculate the 4-bit even byte-parity for an instruction */
319
static unsigned char inst_parity(uint32_t word)
320
{
321
int i, j;
322
char parity = 0;
323
for (j=0; j<4; j++) {
324
char byte_parity = 0;
325
for (i=0; i<8; i++) {
326
if (word & 0x80000000)
327
byte_parity = !byte_parity;
328
word <<= 1;
329
}
330
parity <<= 1;
331
parity |= byte_parity;
332
}
333
return parity;
334
}
335
336
static uint32_t extract_ic(unsigned short addr, int data)
337
{
338
unsigned short way;
339
int valid;
340
uint32_t taghi, taglolo, taglohi;
341
unsigned long long taglo, va;
342
uint64_t tlo_tmp;
343
uint8_t lru;
344
int res = 0;
345
346
printk("Icache index 0x%04x ", addr);
347
for (way = 0; way < 4; way++) {
348
/* Index-load-tag-I */
349
__asm__ __volatile__ (
350
" .set push \n\t"
351
" .set noreorder \n\t"
352
" .set mips64 \n\t"
353
" .set noat \n\t"
354
" cache 4, 0(%3) \n\t"
355
" mfc0 %0, $29 \n\t"
356
" dmfc0 $1, $28 \n\t"
357
" dsrl32 %1, $1, 0 \n\t"
358
" sll %2, $1, 0 \n\t"
359
" .set pop"
360
: "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
361
: "r" ((way << 13) | addr));
362
363
taglo = ((unsigned long long)taglohi << 32) | taglolo;
364
if (way == 0) {
365
lru = (taghi >> 14) & 0xff;
366
printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
367
((addr >> 5) & 0x3), /* bank */
368
((addr >> 7) & 0x3f), /* index */
369
(lru & 0x3),
370
((lru >> 2) & 0x3),
371
((lru >> 4) & 0x3),
372
((lru >> 6) & 0x3));
373
}
374
va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
375
if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
376
va |= 0x3FFFF00000000000ULL;
377
valid = ((taghi >> 29) & 1);
378
if (valid) {
379
tlo_tmp = taglo & 0xfff3ff;
380
if (((taglo >> 10) & 1) ^ range_parity(tlo_tmp, 23, 0)) {
381
printk(" ** bad parity in VTag0/G/ASID\n");
382
res |= CP0_CERRI_TAG_PARITY;
383
}
384
if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
385
printk(" ** bad parity in R/VTag1\n");
386
res |= CP0_CERRI_TAG_PARITY;
387
}
388
}
389
if (valid ^ ((taghi >> 27) & 1)) {
390
printk(" ** bad parity for valid bit\n");
391
res |= CP0_CERRI_TAG_PARITY;
392
}
393
printk(" %d [VA %016llx] [Vld? %d] raw tags: %08X-%016llX\n",
394
way, va, valid, taghi, taglo);
395
396
if (data) {
397
uint32_t datahi, insta, instb;
398
uint8_t predecode;
399
int offset;
400
401
/* (hit all banks and ways) */
402
for (offset = 0; offset < 4; offset++) {
403
/* Index-load-data-I */
404
__asm__ __volatile__ (
405
" .set push\n\t"
406
" .set noreorder\n\t"
407
" .set mips64\n\t"
408
" .set noat\n\t"
409
" cache 6, 0(%3) \n\t"
410
" mfc0 %0, $29, 1\n\t"
411
" dmfc0 $1, $28, 1\n\t"
412
" dsrl32 %1, $1, 0 \n\t"
413
" sll %2, $1, 0 \n\t"
414
" .set pop \n"
415
: "=r" (datahi), "=r" (insta), "=r" (instb)
416
: "r" ((way << 13) | addr | (offset << 3)));
417
predecode = (datahi >> 8) & 0xff;
418
if (((datahi >> 16) & 1) != (uint32_t)range_parity(predecode, 7, 0)) {
419
printk(" ** bad parity in predecode\n");
420
res |= CP0_CERRI_DATA_PARITY;
421
}
422
/* XXXKW should/could check predecode bits themselves */
423
if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
424
printk(" ** bad parity in instruction a\n");
425
res |= CP0_CERRI_DATA_PARITY;
426
}
427
if ((datahi & 0xf) ^ inst_parity(instb)) {
428
printk(" ** bad parity in instruction b\n");
429
res |= CP0_CERRI_DATA_PARITY;
430
}
431
printk(" %05X-%08X%08X", datahi, insta, instb);
432
}
433
printk("\n");
434
}
435
}
436
return res;
437
}
438
439
/* Compute the ECC for a data doubleword */
440
static uint8_t dc_ecc(uint64_t dword)
441
{
442
uint64_t t;
443
uint32_t w;
444
uint8_t p;
445
int i;
446
447
p = 0;
448
for (i = 7; i >= 0; i--)
449
{
450
p <<= 1;
451
t = dword & mask_72_64[i];
452
w = (uint32_t)(t >> 32);
453
p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
454
^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
455
w = (uint32_t)(t & 0xFFFFFFFF);
456
p ^= (parity[w>>24] ^ parity[(w>>16) & 0xFF]
457
^ parity[(w>>8) & 0xFF] ^ parity[w & 0xFF]);
458
}
459
return p;
460
}
461
462
struct dc_state {
463
unsigned char val;
464
char *name;
465
};
466
467
static struct dc_state dc_states[] = {
468
{ 0x00, "INVALID" },
469
{ 0x0f, "COH-SHD" },
470
{ 0x13, "NCO-E-C" },
471
{ 0x19, "NCO-E-D" },
472
{ 0x16, "COH-E-C" },
473
{ 0x1c, "COH-E-D" },
474
{ 0xff, "*ERROR*" }
475
};
476
477
#define DC_TAG_VALID(state) \
478
(((state) == 0x0) || ((state) == 0xf) || ((state) == 0x13) || \
479
((state) == 0x19) || ((state) == 0x16) || ((state) == 0x1c))
480
481
static char *dc_state_str(unsigned char state)
482
{
483
struct dc_state *dsc = dc_states;
484
while (dsc->val != 0xff) {
485
if (dsc->val == state)
486
break;
487
dsc++;
488
}
489
return dsc->name;
490
}
491
492
static uint32_t extract_dc(unsigned short addr, int data)
493
{
494
int valid, way;
495
unsigned char state;
496
uint32_t taghi, taglolo, taglohi;
497
unsigned long long taglo, pa;
498
uint8_t ecc, lru;
499
int res = 0;
500
501
printk("Dcache index 0x%04x ", addr);
502
for (way = 0; way < 4; way++) {
503
__asm__ __volatile__ (
504
" .set push\n\t"
505
" .set noreorder\n\t"
506
" .set mips64\n\t"
507
" .set noat\n\t"
508
" cache 5, 0(%3)\n\t" /* Index-load-tag-D */
509
" mfc0 %0, $29, 2\n\t"
510
" dmfc0 $1, $28, 2\n\t"
511
" dsrl32 %1, $1, 0\n\t"
512
" sll %2, $1, 0\n\t"
513
" .set pop"
514
: "=r" (taghi), "=r" (taglohi), "=r" (taglolo)
515
: "r" ((way << 13) | addr));
516
517
taglo = ((unsigned long long)taglohi << 32) | taglolo;
518
pa = (taglo & 0xFFFFFFE000ULL) | addr;
519
if (way == 0) {
520
lru = (taghi >> 14) & 0xff;
521
printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
522
((addr >> 11) & 0x2) | ((addr >> 5) & 1), /* bank */
523
((addr >> 6) & 0x3f), /* index */
524
(lru & 0x3),
525
((lru >> 2) & 0x3),
526
((lru >> 4) & 0x3),
527
((lru >> 6) & 0x3));
528
}
529
state = (taghi >> 25) & 0x1f;
530
valid = DC_TAG_VALID(state);
531
printk(" %d [PA %010llx] [state %s (%02x)] raw tags: %08X-%016llX\n",
532
way, pa, dc_state_str(state), state, taghi, taglo);
533
if (valid) {
534
if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
535
printk(" ** bad parity in PTag1\n");
536
res |= CP0_CERRD_TAG_ADDRESS;
537
}
538
if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
539
printk(" ** bad parity in PTag0\n");
540
res |= CP0_CERRD_TAG_ADDRESS;
541
}
542
} else {
543
res |= CP0_CERRD_TAG_STATE;
544
}
545
546
if (data) {
547
uint32_t datalohi, datalolo, datahi;
548
unsigned long long datalo;
549
int offset;
550
char bad_ecc = 0;
551
552
for (offset = 0; offset < 4; offset++) {
553
/* Index-load-data-D */
554
__asm__ __volatile__ (
555
" .set push\n\t"
556
" .set noreorder\n\t"
557
" .set mips64\n\t"
558
" .set noat\n\t"
559
" cache 7, 0(%3)\n\t" /* Index-load-data-D */
560
" mfc0 %0, $29, 3\n\t"
561
" dmfc0 $1, $28, 3\n\t"
562
" dsrl32 %1, $1, 0 \n\t"
563
" sll %2, $1, 0 \n\t"
564
" .set pop"
565
: "=r" (datahi), "=r" (datalohi), "=r" (datalolo)
566
: "r" ((way << 13) | addr | (offset << 3)));
567
datalo = ((unsigned long long)datalohi << 32) | datalolo;
568
ecc = dc_ecc(datalo);
569
if (ecc != datahi) {
570
int bits;
571
bad_ecc |= 1 << (3-offset);
572
ecc ^= datahi;
573
bits = hweight8(ecc);
574
res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
575
}
576
printk(" %02X-%016llX", datahi, datalo);
577
}
578
printk("\n");
579
if (bad_ecc)
580
printk(" dwords w/ bad ECC: %d %d %d %d\n",
581
!!(bad_ecc & 8), !!(bad_ecc & 4),
582
!!(bad_ecc & 2), !!(bad_ecc & 1));
583
}
584
}
585
return res;
586
}
587
588