diff options
author | Markos Chandras <markos.chandras@imgtec.com> | 2015-07-09 05:40:47 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2015-08-26 09:23:15 -0400 |
commit | 3885c2b463f6a236e47df22ef13d13433006b951 (patch) | |
tree | 1b78aa7bfd080ea95caae4935f869e1bad7396f8 /arch/mips/kernel/mips-cm.c | |
parent | 391057d915f42d4942f0c65e7d55cec6662c8a54 (diff) |
MIPS: CM: Add support for reporting CM cache errors
The CM cache error reporting code is not Malta specific and as such it
should live in the mips-cm.c file. Moreover, CM2 and CM3 differ in the
way cache errors are being recorded to the registers so extend the
previous code to add support for the CM3 as well.
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/10646/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/mips-cm.c')
-rw-r--r-- | arch/mips/kernel/mips-cm.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index c390be1cecc9..b8ceee576cdf 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c | |||
@@ -17,6 +17,125 @@ void __iomem *mips_cm_base; | |||
17 | void __iomem *mips_cm_l2sync_base; | 17 | void __iomem *mips_cm_l2sync_base; |
18 | int mips_cm_is64; | 18 | int mips_cm_is64; |
19 | 19 | ||
20 | static char *cm2_tr[8] = { | ||
21 | "mem", "gcr", "gic", "mmio", | ||
22 | "0x04", "cpc", "0x06", "0x07" | ||
23 | }; | ||
24 | |||
25 | /* CM3 Tag ECC transation type */ | ||
26 | static char *cm3_tr[16] = { | ||
27 | [0x0] = "ReqNoData", | ||
28 | [0x1] = "0x1", | ||
29 | [0x2] = "ReqWData", | ||
30 | [0x3] = "0x3", | ||
31 | [0x4] = "IReqNoResp", | ||
32 | [0x5] = "IReqWResp", | ||
33 | [0x6] = "IReqNoRespDat", | ||
34 | [0x7] = "IReqWRespDat", | ||
35 | [0x8] = "RespNoData", | ||
36 | [0x9] = "RespDataFol", | ||
37 | [0xa] = "RespWData", | ||
38 | [0xb] = "RespDataOnly", | ||
39 | [0xc] = "IRespNoData", | ||
40 | [0xd] = "IRespDataFol", | ||
41 | [0xe] = "IRespWData", | ||
42 | [0xf] = "IRespDataOnly" | ||
43 | }; | ||
44 | |||
45 | static char *cm2_cmd[32] = { | ||
46 | [0x00] = "0x00", | ||
47 | [0x01] = "Legacy Write", | ||
48 | [0x02] = "Legacy Read", | ||
49 | [0x03] = "0x03", | ||
50 | [0x04] = "0x04", | ||
51 | [0x05] = "0x05", | ||
52 | [0x06] = "0x06", | ||
53 | [0x07] = "0x07", | ||
54 | [0x08] = "Coherent Read Own", | ||
55 | [0x09] = "Coherent Read Share", | ||
56 | [0x0a] = "Coherent Read Discard", | ||
57 | [0x0b] = "Coherent Ready Share Always", | ||
58 | [0x0c] = "Coherent Upgrade", | ||
59 | [0x0d] = "Coherent Writeback", | ||
60 | [0x0e] = "0x0e", | ||
61 | [0x0f] = "0x0f", | ||
62 | [0x10] = "Coherent Copyback", | ||
63 | [0x11] = "Coherent Copyback Invalidate", | ||
64 | [0x12] = "Coherent Invalidate", | ||
65 | [0x13] = "Coherent Write Invalidate", | ||
66 | [0x14] = "Coherent Completion Sync", | ||
67 | [0x15] = "0x15", | ||
68 | [0x16] = "0x16", | ||
69 | [0x17] = "0x17", | ||
70 | [0x18] = "0x18", | ||
71 | [0x19] = "0x19", | ||
72 | [0x1a] = "0x1a", | ||
73 | [0x1b] = "0x1b", | ||
74 | [0x1c] = "0x1c", | ||
75 | [0x1d] = "0x1d", | ||
76 | [0x1e] = "0x1e", | ||
77 | [0x1f] = "0x1f" | ||
78 | }; | ||
79 | |||
80 | /* CM3 Tag ECC command type */ | ||
81 | static char *cm3_cmd[16] = { | ||
82 | [0x0] = "Legacy Read", | ||
83 | [0x1] = "Legacy Write", | ||
84 | [0x2] = "Coherent Read Own", | ||
85 | [0x3] = "Coherent Read Share", | ||
86 | [0x4] = "Coherent Read Discard", | ||
87 | [0x5] = "Coherent Evicted", | ||
88 | [0x6] = "Coherent Upgrade", | ||
89 | [0x7] = "Coherent Upgrade for Store Conditional", | ||
90 | [0x8] = "Coherent Writeback", | ||
91 | [0x9] = "Coherent Write Invalidate", | ||
92 | [0xa] = "0xa", | ||
93 | [0xb] = "0xb", | ||
94 | [0xc] = "0xc", | ||
95 | [0xd] = "0xd", | ||
96 | [0xe] = "0xe", | ||
97 | [0xf] = "0xf" | ||
98 | }; | ||
99 | |||
100 | /* CM3 Tag ECC command group */ | ||
101 | static char *cm3_cmd_group[8] = { | ||
102 | [0x0] = "Normal", | ||
103 | [0x1] = "Registers", | ||
104 | [0x2] = "TLB", | ||
105 | [0x3] = "0x3", | ||
106 | [0x4] = "L1I", | ||
107 | [0x5] = "L1D", | ||
108 | [0x6] = "L3", | ||
109 | [0x7] = "L2" | ||
110 | }; | ||
111 | |||
112 | static char *cm2_core[8] = { | ||
113 | "Invalid/OK", "Invalid/Data", | ||
114 | "Shared/OK", "Shared/Data", | ||
115 | "Modified/OK", "Modified/Data", | ||
116 | "Exclusive/OK", "Exclusive/Data" | ||
117 | }; | ||
118 | |||
119 | static char *cm2_causes[32] = { | ||
120 | "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", | ||
121 | "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", | ||
122 | "0x08", "0x09", "0x0a", "0x0b", | ||
123 | "0x0c", "0x0d", "0x0e", "0x0f", | ||
124 | "0x10", "0x11", "0x12", "0x13", | ||
125 | "0x14", "0x15", "0x16", "INTVN_WR_ERR", | ||
126 | "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", | ||
127 | "0x1c", "0x1d", "0x1e", "0x1f" | ||
128 | }; | ||
129 | |||
130 | static char *cm3_causes[32] = { | ||
131 | "0x0", "MP_CORRECTABLE_ECC_ERR", "MP_REQUEST_DECODE_ERR", | ||
132 | "MP_UNCORRECTABLE_ECC_ERR", "MP_PARITY_ERR", "MP_COHERENCE_ERR", | ||
133 | "CMBIU_REQUEST_DECODE_ERR", "CMBIU_PARITY_ERR", "CMBIU_AXI_RESP_ERR", | ||
134 | "0x9", "RBI_BUS_ERR", "0xb", "0xc", "0xd", "0xe", "0xf", "0x10", | ||
135 | "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", | ||
136 | "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" | ||
137 | }; | ||
138 | |||
20 | phys_addr_t __mips_cm_phys_base(void) | 139 | phys_addr_t __mips_cm_phys_base(void) |
21 | { | 140 | { |
22 | u32 config3 = read_c0_config3(); | 141 | u32 config3 = read_c0_config3(); |
@@ -130,3 +249,128 @@ int mips_cm_probe(void) | |||
130 | 249 | ||
131 | return 0; | 250 | return 0; |
132 | } | 251 | } |
252 | |||
253 | void mips_cm_error_report(void) | ||
254 | { | ||
255 | unsigned long revision = mips_cm_revision(); | ||
256 | /* | ||
257 | * CM3 has a 64-bit Error cause register with 0:57 containing the error | ||
258 | * info and 63:58 the error type. For old CMs, everything is contained | ||
259 | * in a single 32-bit register (0:26 and 31:27 respectively). Even | ||
260 | * though the cm_error is u64, we will simply ignore the upper word | ||
261 | * for CM2. | ||
262 | */ | ||
263 | u64 cm_error = read_gcr_error_cause(); | ||
264 | int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + | ||
265 | ((revision >= CM_REV_CM3) ? 31 : 0); | ||
266 | unsigned long cm_addr = read_gcr_error_addr(); | ||
267 | unsigned long cm_other = read_gcr_error_mult(); | ||
268 | int ocause, cause; | ||
269 | char buf[256]; | ||
270 | |||
271 | if (!mips_cm_present()) | ||
272 | return; | ||
273 | |||
274 | cause = cm_error >> cm_error_cause_sft; | ||
275 | |||
276 | if (!cause) | ||
277 | /* All good */ | ||
278 | return; | ||
279 | |||
280 | ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; | ||
281 | if (revision < CM_REV_CM3) { /* CM2 */ | ||
282 | if (cause < 16) { | ||
283 | unsigned long cca_bits = (cm_error >> 15) & 7; | ||
284 | unsigned long tr_bits = (cm_error >> 12) & 7; | ||
285 | unsigned long cmd_bits = (cm_error >> 7) & 0x1f; | ||
286 | unsigned long stag_bits = (cm_error >> 3) & 15; | ||
287 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
288 | |||
289 | snprintf(buf, sizeof(buf), | ||
290 | "CCA=%lu TR=%s MCmd=%s STag=%lu " | ||
291 | "SPort=%lu\n", cca_bits, cm2_tr[tr_bits], | ||
292 | cm2_cmd[cmd_bits], stag_bits, sport_bits); | ||
293 | } else { | ||
294 | /* glob state & sresp together */ | ||
295 | unsigned long c3_bits = (cm_error >> 18) & 7; | ||
296 | unsigned long c2_bits = (cm_error >> 15) & 7; | ||
297 | unsigned long c1_bits = (cm_error >> 12) & 7; | ||
298 | unsigned long c0_bits = (cm_error >> 9) & 7; | ||
299 | unsigned long sc_bit = (cm_error >> 8) & 1; | ||
300 | unsigned long cmd_bits = (cm_error >> 3) & 0x1f; | ||
301 | unsigned long sport_bits = (cm_error >> 0) & 7; | ||
302 | |||
303 | snprintf(buf, sizeof(buf), | ||
304 | "C3=%s C2=%s C1=%s C0=%s SC=%s " | ||
305 | "MCmd=%s SPort=%lu\n", | ||
306 | cm2_core[c3_bits], cm2_core[c2_bits], | ||
307 | cm2_core[c1_bits], cm2_core[c0_bits], | ||
308 | sc_bit ? "True" : "False", | ||
309 | cm2_cmd[cmd_bits], sport_bits); | ||
310 | } | ||
311 | pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, | ||
312 | cm2_causes[cause], buf); | ||
313 | pr_err("CM_ADDR =%08lx\n", cm_addr); | ||
314 | pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]); | ||
315 | } else { /* CM3 */ | ||
316 | /* Used by cause == {1,2,3} */ | ||
317 | unsigned long core_id_bits = (cm_error >> 22) & 0xf; | ||
318 | unsigned long vp_id_bits = (cm_error >> 18) & 0xf; | ||
319 | unsigned long cmd_bits = (cm_error >> 14) & 0xf; | ||
320 | unsigned long cmd_group_bits = (cm_error >> 11) & 0xf; | ||
321 | unsigned long cm3_cca_bits = (cm_error >> 8) & 7; | ||
322 | unsigned long mcp_bits = (cm_error >> 5) & 0xf; | ||
323 | unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf; | ||
324 | unsigned long sched_bit = cm_error & 0x1; | ||
325 | |||
326 | if (cause == 1 || cause == 3) { /* Tag ECC */ | ||
327 | unsigned long tag_ecc = (cm_error >> 57) & 0x1; | ||
328 | unsigned long tag_way_bits = (cm_error >> 29) & 0xffff; | ||
329 | unsigned long dword_bits = (cm_error >> 49) & 0xff; | ||
330 | unsigned long data_way_bits = (cm_error >> 45) & 0xf; | ||
331 | unsigned long data_sets_bits = (cm_error >> 29) & 0xfff; | ||
332 | unsigned long bank_bit = (cm_error >> 28) & 0x1; | ||
333 | snprintf(buf, sizeof(buf), | ||
334 | "%s ECC Error: Way=%lu (DWORD=%lu, Sets=%lu)" | ||
335 | "Bank=%lu CoreID=%lu VPID=%lu Command=%s" | ||
336 | "Command Group=%s CCA=%lu MCP=%d" | ||
337 | "Transaction type=%s Scheduler=%lu\n", | ||
338 | tag_ecc ? "TAG" : "DATA", | ||
339 | tag_ecc ? (unsigned long)ffs(tag_way_bits) - 1 : | ||
340 | data_way_bits, bank_bit, dword_bits, | ||
341 | data_sets_bits, | ||
342 | core_id_bits, vp_id_bits, | ||
343 | cm3_cmd[cmd_bits], | ||
344 | cm3_cmd_group[cmd_group_bits], | ||
345 | cm3_cca_bits, 1 << mcp_bits, | ||
346 | cm3_tr[cm3_tr_bits], sched_bit); | ||
347 | } else if (cause == 2) { | ||
348 | unsigned long data_error_type = (cm_error >> 41) & 0xfff; | ||
349 | unsigned long data_decode_cmd = (cm_error >> 37) & 0xf; | ||
350 | unsigned long data_decode_group = (cm_error >> 34) & 0x7; | ||
351 | unsigned long data_decode_destination_id = (cm_error >> 28) & 0x3f; | ||
352 | |||
353 | snprintf(buf, sizeof(buf), | ||
354 | "Decode Request Error: Type=%lu, Command=%lu" | ||
355 | "Command Group=%lu Destination ID=%lu" | ||
356 | "CoreID=%lu VPID=%lu Command=%s" | ||
357 | "Command Group=%s CCA=%lu MCP=%d" | ||
358 | "Transaction type=%s Scheduler=%lu\n", | ||
359 | data_error_type, data_decode_cmd, | ||
360 | data_decode_group, data_decode_destination_id, | ||
361 | core_id_bits, vp_id_bits, | ||
362 | cm3_cmd[cmd_bits], | ||
363 | cm3_cmd_group[cmd_group_bits], | ||
364 | cm3_cca_bits, 1 << mcp_bits, | ||
365 | cm3_tr[cm3_tr_bits], sched_bit); | ||
366 | } | ||
367 | |||
368 | pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, | ||
369 | cm3_causes[cause], buf); | ||
370 | pr_err("CM_ADDR =%lx\n", cm_addr); | ||
371 | pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]); | ||
372 | } | ||
373 | |||
374 | /* reprime cause register */ | ||
375 | write_gcr_error_cause(0); | ||
376 | } | ||