blob: a3c02df19f6faedb02846b4bf416e14d67685fb3 [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Copyright (C) 2001,2002,2003 Broadcom Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005#include <linux/sched.h>
6#include <asm/mipsregs.h>
7#include <asm/sibyte/sb1250.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <asm/sibyte/sb1250_regs.h>
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -07009
10#if !defined(CONFIG_SIBYTE_BUS_WATCHER) || defined(CONFIG_SIBYTE_BW_TRACE)
11#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <asm/sibyte/sb1250_scd.h>
13#endif
Ralf Baechle42a3b4f2005-09-03 15:56:17 -070014
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -070015/*
16 * We'd like to dump the L2_ECC_TAG register on errors, but errata make
Ralf Baechle70342282013-01-22 12:59:30 +010017 * that unsafe... So for now we don't. (BCM1250/BCM112x erratum SOC-48.)
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -070018 */
19#undef DUMP_L2_ECC_TAG_ON_ERROR
20
Linus Torvalds1da177e2005-04-16 15:20:36 -070021/* 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))
Ralf Baechle70342282013-01-22 12:59:30 +010038#define CP0_CERRI_DATA (CP0_CERRI_DATA_PARITY)
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
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)
Ralf Baechle70342282013-01-22 12:59:30 +010046#define CP0_CERRD_LOAD (1 << 25)
47#define CP0_CERRD_STORE (1 << 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#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)
Ralf Baechle70342282013-01-22 12:59:30 +010059#define CP0_CERRD_DATA (CP0_CERRD_DATA_SBE | CP0_CERRD_DATA_DBE)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Ralf Baechle70342282013-01-22 12:59:30 +010061static uint32_t extract_ic(unsigned short addr, int data);
62static uint32_t extract_dc(unsigned short addr, int data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64static inline void breakout_errctl(unsigned int val)
65{
66 if (val & CP0_ERRCTL_RECOVERABLE)
Ralf Baechle36a88532007-03-01 11:56:43 +000067 printk(" recoverable");
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 if (val & CP0_ERRCTL_DCACHE)
Ralf Baechle36a88532007-03-01 11:56:43 +000069 printk(" dcache");
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 if (val & CP0_ERRCTL_ICACHE)
Ralf Baechle36a88532007-03-01 11:56:43 +000071 printk(" icache");
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 if (val & CP0_ERRCTL_MULTIBUS)
Ralf Baechle36a88532007-03-01 11:56:43 +000073 printk(" multiple-buserr");
74 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070075}
76
77static inline void breakout_cerri(unsigned int val)
78{
79 if (val & CP0_CERRI_TAG_PARITY)
Ralf Baechle36a88532007-03-01 11:56:43 +000080 printk(" tag-parity");
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 if (val & CP0_CERRI_DATA_PARITY)
Ralf Baechle36a88532007-03-01 11:56:43 +000082 printk(" data-parity");
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 if (val & CP0_CERRI_EXTERNAL)
Ralf Baechle36a88532007-03-01 11:56:43 +000084 printk(" external");
85 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
88static inline void breakout_cerrd(unsigned int val)
89{
90 switch (val & CP0_CERRD_CAUSES) {
91 case CP0_CERRD_LOAD:
Ralf Baechle36a88532007-03-01 11:56:43 +000092 printk(" load,");
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 break;
94 case CP0_CERRD_STORE:
Ralf Baechle36a88532007-03-01 11:56:43 +000095 printk(" store,");
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 break;
97 case CP0_CERRD_FILLWB:
Ralf Baechle36a88532007-03-01 11:56:43 +000098 printk(" fill/wb,");
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 break;
100 case CP0_CERRD_COHERENCY:
Ralf Baechle36a88532007-03-01 11:56:43 +0000101 printk(" coherency,");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 break;
103 case CP0_CERRD_DUPTAG:
Ralf Baechle36a88532007-03-01 11:56:43 +0000104 printk(" duptags,");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 break;
106 default:
Ralf Baechle36a88532007-03-01 11:56:43 +0000107 printk(" NO CAUSE,");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 break;
109 }
110 if (!(val & CP0_CERRD_TYPES))
Ralf Baechle36a88532007-03-01 11:56:43 +0000111 printk(" NO TYPE");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 else {
113 if (val & CP0_CERRD_MULTIPLE)
Ralf Baechle36a88532007-03-01 11:56:43 +0000114 printk(" multi-err");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 if (val & CP0_CERRD_TAG_STATE)
Ralf Baechle36a88532007-03-01 11:56:43 +0000116 printk(" tag-state");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 if (val & CP0_CERRD_TAG_ADDRESS)
Ralf Baechle36a88532007-03-01 11:56:43 +0000118 printk(" tag-address");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 if (val & CP0_CERRD_DATA_SBE)
Ralf Baechle36a88532007-03-01 11:56:43 +0000120 printk(" data-SBE");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 if (val & CP0_CERRD_DATA_DBE)
Ralf Baechle36a88532007-03-01 11:56:43 +0000122 printk(" data-DBE");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 if (val & CP0_CERRD_EXTERNAL)
Ralf Baechle36a88532007-03-01 11:56:43 +0000124 printk(" external");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 }
Ralf Baechle36a88532007-03-01 11:56:43 +0000126 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
129#ifndef CONFIG_SIBYTE_BUS_WATCHER
130
Ralf Baechle42a3b4f2005-09-03 15:56:17 -0700131static void check_bus_watcher(void)
132{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 uint32_t status, l2_err, memio_err;
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700134#ifdef DUMP_L2_ECC_TAG_ON_ERROR
135 uint64_t l2_tag;
136#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
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 */
Ralf Baechle42a3b4f2005-09-03 15:56:17 -0700141 if (status & ~(1UL << 31)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 l2_err = csr_in32(IOADDR(A_BUS_L2_ERRORS));
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700143#ifdef DUMP_L2_ECC_TAG_ON_ERROR
Ralf Baechle33b75e5c2007-11-06 00:43:51 +0000144 l2_tag = in64(IOADDR(A_L2_ECC_TAG));
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700145#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 memio_err = csr_in32(IOADDR(A_BUS_MEM_IO_ERRORS));
Ralf Baechle36a88532007-03-01 11:56:43 +0000147 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",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 (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));
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700154#ifdef DUMP_L2_ECC_TAG_ON_ERROR
Ralf Baechle36a88532007-03-01 11:56:43 +0000155 printk("Last L2 tag w/ bad ECC: %016llx\n", l2_tag);
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700156#endif
Ralf Baechle42a3b4f2005-09-03 15:56:17 -0700157 } else {
Ralf Baechle36a88532007-03-01 11:56:43 +0000158 printk("Bus watcher indicates no error\n");
Ralf Baechle42a3b4f2005-09-03 15:56:17 -0700159 }
160}
161#else
162extern void check_bus_watcher(void);
163#endif
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165asmlinkage void sb1_cache_error(void)
166{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 uint32_t errctl, cerr_i, cerr_d, dpalo, dpahi, eepc, res;
Ralf Baechle41a81982007-03-24 14:09:59 +0000168 unsigned long long cerr_dpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700170#ifdef CONFIG_SIBYTE_BW_TRACE
171 /* Freeze the trace buffer now */
Ralf Baechle33b75e5c2007-11-06 00:43:51 +0000172 csr_out32(M_SCD_TRACE_CFG_FREEZE, IOADDR(A_SCD_TRACE_CFG));
Ralf Baechle36a88532007-03-01 11:56:43 +0000173 printk("Trace buffer frozen\n");
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700174#endif
175
Ralf Baechle36a88532007-03-01 11:56:43 +0000176 printk("Cache error exception on CPU %x:\n",
177 (read_c0_prid() >> 25) & 0x7);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
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;
Ralf Baechle70342282013-01-22 12:59:30 +0100195 printk(" c0_errorepc == %08x\n", eepc);
196 printk(" c0_errctl == %08x", errctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 breakout_errctl(errctl);
198 if (errctl & CP0_ERRCTL_ICACHE) {
Ralf Baechle70342282013-01-22 12:59:30 +0100199 printk(" c0_cerr_i == %08x", cerr_i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 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)))
Ralf Baechle36a88532007-03-01 11:56:43 +0000205 printk(" cerr_i idx doesn't match eepc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 else {
207 res = extract_ic(cerr_i & SB1_CACHE_INDEX_MASK,
208 (cerr_i & CP0_CERRI_DATA) != 0);
209 if (!(res & cerr_i))
Ralf Baechle36a88532007-03-01 11:56:43 +0000210 printk("...didn't see indicated icache problem\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
212 }
213 }
214 if (errctl & CP0_ERRCTL_DCACHE) {
Ralf Baechle70342282013-01-22 12:59:30 +0100215 printk(" c0_cerr_d == %08x", cerr_d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 breakout_cerrd(cerr_d);
217 if (CP0_CERRD_DPA_VALID(cerr_d)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000218 printk(" c0_cerr_dpa == %010llx\n", cerr_dpa);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 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))
Ralf Baechle36a88532007-03-01 11:56:43 +0000223 printk("...didn't see indicated dcache problem\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 } else {
225 if ((cerr_dpa & SB1_CACHE_INDEX_MASK) != (cerr_d & SB1_CACHE_INDEX_MASK))
Ralf Baechle36a88532007-03-01 11:56:43 +0000226 printk(" cerr_d idx doesn't match cerr_dpa\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 else {
228 res = extract_dc(cerr_d & SB1_CACHE_INDEX_MASK,
229 (cerr_d & CP0_CERRD_DATA) != 0);
230 if (!(res & cerr_d))
Ralf Baechle36a88532007-03-01 11:56:43 +0000231 printk("...didn't see indicated problem\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
233 }
234 }
235 }
236
237 check_bus_watcher();
238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 /*
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700240 * Calling panic() when a fatal cache error occurs scrambles the
241 * state of the system (and the cache), making it difficult to
Ralf Baechle70342282013-01-22 12:59:30 +0100242 * investigate after the fact. However, if you just stall the CPU,
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700243 * the other CPU may keep on running, which is typically very
244 * undesirable.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 */
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700246#ifdef CONFIG_SB1_CERR_STALL
247 while (1)
248 ;
249#else
250 panic("unhandled cache error");
251#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
254
255/* Parity lookup table. */
256static const uint8_t parity[256] = {
Ralf Baechle21a151d2007-10-11 23:46:15 +0100257 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273};
274
275/* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
276static 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 */
288static 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 */
302static 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
319static uint32_t extract_ic(unsigned short addr, int data)
320{
321 unsigned short way;
322 int valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 uint32_t taghi, taglolo, taglohi;
Ralf Baechle41a81982007-03-24 14:09:59 +0000324 unsigned long long taglo, va;
325 uint64_t tlo_tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 uint8_t lru;
327 int res = 0;
328
Ralf Baechle36a88532007-03-01 11:56:43 +0000329 printk("Icache index 0x%04x ", addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 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;
Ralf Baechle36a88532007-03-01 11:56:43 +0000349 printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 ((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)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000364 printk(" ** bad parity in VTag0/G/ASID\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 res |= CP0_CERRI_TAG_PARITY;
366 }
367 if (((taglo >> 11) & 1) ^ range_parity(taglo, 63, 24)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000368 printk(" ** bad parity in R/VTag1\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 res |= CP0_CERRI_TAG_PARITY;
370 }
371 }
372 if (valid ^ ((taghi >> 27) & 1)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000373 printk(" ** bad parity for valid bit\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 res |= CP0_CERRI_TAG_PARITY;
375 }
Ralf Baechle36a88532007-03-01 11:56:43 +0000376 printk(" %d [VA %016llx] [Vld? %d] raw tags: %08X-%016llX\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 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"
Ralf Baechle70342282013-01-22 12:59:30 +0100397 " .set pop \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 : "=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)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000402 printk(" ** bad parity in predecode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 res |= CP0_CERRI_DATA_PARITY;
404 }
405 /* XXXKW should/could check predecode bits themselves */
406 if (((datahi >> 4) & 0xf) ^ inst_parity(insta)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000407 printk(" ** bad parity in instruction a\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 res |= CP0_CERRI_DATA_PARITY;
409 }
410 if ((datahi & 0xf) ^ inst_parity(instb)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000411 printk(" ** bad parity in instruction b\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 res |= CP0_CERRI_DATA_PARITY;
413 }
Ralf Baechle36a88532007-03-01 11:56:43 +0000414 printk(" %05X-%08X%08X", datahi, insta, instb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 }
Ralf Baechle36a88532007-03-01 11:56:43 +0000416 printk("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
418 }
419 return res;
420}
421
422/* Compute the ECC for a data doubleword */
423static uint8_t dc_ecc(uint64_t dword)
424{
425 uint64_t t;
426 uint32_t w;
Ralf Baechle70342282013-01-22 12:59:30 +0100427 uint8_t p;
428 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
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
445struct dc_state {
446 unsigned char val;
447 char *name;
448};
449
450static 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) \
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700461 (((state) == 0x0) || ((state) == 0xf) || ((state) == 0x13) || \
462 ((state) == 0x19) || ((state) == 0x16) || ((state) == 0x1c))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464static 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
475static uint32_t extract_dc(unsigned short addr, int data)
476{
477 int valid, way;
478 unsigned char state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 uint32_t taghi, taglolo, taglohi;
Ralf Baechle41a81982007-03-24 14:09:59 +0000480 unsigned long long taglo, pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 uint8_t ecc, lru;
482 int res = 0;
483
Ralf Baechle36a88532007-03-01 11:56:43 +0000484 printk("Dcache index 0x%04x ", addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 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;
Ralf Baechle36a88532007-03-01 11:56:43 +0000504 printk("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ((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);
Ralf Baechle36a88532007-03-01 11:56:43 +0000514 printk(" %d [PA %010llx] [state %s (%02x)] raw tags: %08X-%016llX\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 way, pa, dc_state_str(state), state, taghi, taglo);
516 if (valid) {
517 if (((taglo >> 11) & 1) ^ range_parity(taglo, 39, 26)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000518 printk(" ** bad parity in PTag1\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 res |= CP0_CERRD_TAG_ADDRESS;
520 }
521 if (((taglo >> 10) & 1) ^ range_parity(taglo, 25, 13)) {
Ralf Baechle36a88532007-03-01 11:56:43 +0000522 printk(" ** bad parity in PTag0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 res |= CP0_CERRD_TAG_ADDRESS;
524 }
525 } else {
526 res |= CP0_CERRD_TAG_STATE;
527 }
528
529 if (data) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 uint32_t datalohi, datalolo, datahi;
Ralf Baechle41a81982007-03-24 14:09:59 +0000531 unsigned long long datalo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 int offset;
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700533 char bad_ecc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
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) {
Akinobu Mita13e79b42009-11-13 16:04:53 +0900553 int bits;
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700554 bad_ecc |= 1 << (3-offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 ecc ^= datahi;
Akinobu Mita13e79b42009-11-13 16:04:53 +0900556 bits = hweight8(ecc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 res |= (bits == 1) ? CP0_CERRD_DATA_SBE : CP0_CERRD_DATA_DBE;
558 }
Ralf Baechle36a88532007-03-01 11:56:43 +0000559 printk(" %02X-%016llX", datahi, datalo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
Ralf Baechle36a88532007-03-01 11:56:43 +0000561 printk("\n");
Andrew Isaacsona4b5bd92005-10-19 23:57:40 -0700562 if (bad_ecc)
Ralf Baechle36a88532007-03-01 11:56:43 +0000563 printk(" dwords w/ bad ECC: %d %d %d %d\n",
564 !!(bad_ecc & 8), !!(bad_ecc & 4),
565 !!(bad_ecc & 2), !!(bad_ecc & 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 }
567 }
568 return res;
569}