1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2013 Imagination Technologies |
4 | * Author: Paul Burton <paul.burton@mips.com> |
5 | */ |
6 | |
7 | #include <linux/errno.h> |
8 | #include <linux/percpu.h> |
9 | #include <linux/spinlock.h> |
10 | |
11 | #include <asm/mips-cps.h> |
12 | #include <asm/mipsregs.h> |
13 | |
14 | void __iomem *mips_gcr_base; |
15 | void __iomem *mips_cm_l2sync_base; |
16 | int mips_cm_is64; |
17 | |
18 | static char *cm2_tr[8] = { |
19 | "mem" , "gcr" , "gic" , "mmio" , |
20 | "0x04" , "cpc" , "0x06" , "0x07" |
21 | }; |
22 | |
23 | /* CM3 Tag ECC transaction type */ |
24 | static char *cm3_tr[16] = { |
25 | [0x0] = "ReqNoData" , |
26 | [0x1] = "0x1" , |
27 | [0x2] = "ReqWData" , |
28 | [0x3] = "0x3" , |
29 | [0x4] = "IReqNoResp" , |
30 | [0x5] = "IReqWResp" , |
31 | [0x6] = "IReqNoRespDat" , |
32 | [0x7] = "IReqWRespDat" , |
33 | [0x8] = "RespNoData" , |
34 | [0x9] = "RespDataFol" , |
35 | [0xa] = "RespWData" , |
36 | [0xb] = "RespDataOnly" , |
37 | [0xc] = "IRespNoData" , |
38 | [0xd] = "IRespDataFol" , |
39 | [0xe] = "IRespWData" , |
40 | [0xf] = "IRespDataOnly" |
41 | }; |
42 | |
43 | static char *cm2_cmd[32] = { |
44 | [0x00] = "0x00" , |
45 | [0x01] = "Legacy Write" , |
46 | [0x02] = "Legacy Read" , |
47 | [0x03] = "0x03" , |
48 | [0x04] = "0x04" , |
49 | [0x05] = "0x05" , |
50 | [0x06] = "0x06" , |
51 | [0x07] = "0x07" , |
52 | [0x08] = "Coherent Read Own" , |
53 | [0x09] = "Coherent Read Share" , |
54 | [0x0a] = "Coherent Read Discard" , |
55 | [0x0b] = "Coherent Ready Share Always" , |
56 | [0x0c] = "Coherent Upgrade" , |
57 | [0x0d] = "Coherent Writeback" , |
58 | [0x0e] = "0x0e" , |
59 | [0x0f] = "0x0f" , |
60 | [0x10] = "Coherent Copyback" , |
61 | [0x11] = "Coherent Copyback Invalidate" , |
62 | [0x12] = "Coherent Invalidate" , |
63 | [0x13] = "Coherent Write Invalidate" , |
64 | [0x14] = "Coherent Completion Sync" , |
65 | [0x15] = "0x15" , |
66 | [0x16] = "0x16" , |
67 | [0x17] = "0x17" , |
68 | [0x18] = "0x18" , |
69 | [0x19] = "0x19" , |
70 | [0x1a] = "0x1a" , |
71 | [0x1b] = "0x1b" , |
72 | [0x1c] = "0x1c" , |
73 | [0x1d] = "0x1d" , |
74 | [0x1e] = "0x1e" , |
75 | [0x1f] = "0x1f" |
76 | }; |
77 | |
78 | /* CM3 Tag ECC command type */ |
79 | static char *cm3_cmd[16] = { |
80 | [0x0] = "Legacy Read" , |
81 | [0x1] = "Legacy Write" , |
82 | [0x2] = "Coherent Read Own" , |
83 | [0x3] = "Coherent Read Share" , |
84 | [0x4] = "Coherent Read Discard" , |
85 | [0x5] = "Coherent Evicted" , |
86 | [0x6] = "Coherent Upgrade" , |
87 | [0x7] = "Coherent Upgrade for Store Conditional" , |
88 | [0x8] = "Coherent Writeback" , |
89 | [0x9] = "Coherent Write Invalidate" , |
90 | [0xa] = "0xa" , |
91 | [0xb] = "0xb" , |
92 | [0xc] = "0xc" , |
93 | [0xd] = "0xd" , |
94 | [0xe] = "0xe" , |
95 | [0xf] = "0xf" |
96 | }; |
97 | |
98 | /* CM3 Tag ECC command group */ |
99 | static char *cm3_cmd_group[8] = { |
100 | [0x0] = "Normal" , |
101 | [0x1] = "Registers" , |
102 | [0x2] = "TLB" , |
103 | [0x3] = "0x3" , |
104 | [0x4] = "L1I" , |
105 | [0x5] = "L1D" , |
106 | [0x6] = "L3" , |
107 | [0x7] = "L2" |
108 | }; |
109 | |
110 | static char *cm2_core[8] = { |
111 | "Invalid/OK" , "Invalid/Data" , |
112 | "Shared/OK" , "Shared/Data" , |
113 | "Modified/OK" , "Modified/Data" , |
114 | "Exclusive/OK" , "Exclusive/Data" |
115 | }; |
116 | |
117 | static char *cm2_l2_type[4] = { |
118 | [0x0] = "None" , |
119 | [0x1] = "Tag RAM single/double ECC error" , |
120 | [0x2] = "Data RAM single/double ECC error" , |
121 | [0x3] = "WS RAM uncorrectable dirty parity" |
122 | }; |
123 | |
124 | static char *cm2_l2_instr[32] = { |
125 | [0x00] = "L2_NOP" , |
126 | [0x01] = "L2_ERR_CORR" , |
127 | [0x02] = "L2_TAG_INV" , |
128 | [0x03] = "L2_WS_CLEAN" , |
129 | [0x04] = "L2_RD_MDYFY_WR" , |
130 | [0x05] = "L2_WS_MRU" , |
131 | [0x06] = "L2_EVICT_LN2" , |
132 | [0x07] = "0x07" , |
133 | [0x08] = "L2_EVICT" , |
134 | [0x09] = "L2_REFL" , |
135 | [0x0a] = "L2_RD" , |
136 | [0x0b] = "L2_WR" , |
137 | [0x0c] = "L2_EVICT_MRU" , |
138 | [0x0d] = "L2_SYNC" , |
139 | [0x0e] = "L2_REFL_ERR" , |
140 | [0x0f] = "0x0f" , |
141 | [0x10] = "L2_INDX_WB_INV" , |
142 | [0x11] = "L2_INDX_LD_TAG" , |
143 | [0x12] = "L2_INDX_ST_TAG" , |
144 | [0x13] = "L2_INDX_ST_DATA" , |
145 | [0x14] = "L2_INDX_ST_ECC" , |
146 | [0x15] = "0x15" , |
147 | [0x16] = "0x16" , |
148 | [0x17] = "0x17" , |
149 | [0x18] = "L2_FTCH_AND_LCK" , |
150 | [0x19] = "L2_HIT_INV" , |
151 | [0x1a] = "L2_HIT_WB_INV" , |
152 | [0x1b] = "L2_HIT_WB" , |
153 | [0x1c] = "0x1c" , |
154 | [0x1d] = "0x1d" , |
155 | [0x1e] = "0x1e" , |
156 | [0x1f] = "0x1f" |
157 | }; |
158 | |
159 | static char *cm2_causes[32] = { |
160 | "None" , "GC_WR_ERR" , "GC_RD_ERR" , "COH_WR_ERR" , |
161 | "COH_RD_ERR" , "MMIO_WR_ERR" , "MMIO_RD_ERR" , "0x07" , |
162 | "0x08" , "0x09" , "0x0a" , "0x0b" , |
163 | "0x0c" , "0x0d" , "0x0e" , "0x0f" , |
164 | "0x10" , "INTVN_WR_ERR" , "INTVN_RD_ERR" , "0x13" , |
165 | "0x14" , "0x15" , "0x16" , "0x17" , |
166 | "L2_RD_UNCORR" , "L2_WR_UNCORR" , "L2_CORR" , "0x1b" , |
167 | "0x1c" , "0x1d" , "0x1e" , "0x1f" |
168 | }; |
169 | |
170 | static char *cm3_causes[32] = { |
171 | "0x0" , "MP_CORRECTABLE_ECC_ERR" , "MP_REQUEST_DECODE_ERR" , |
172 | "MP_UNCORRECTABLE_ECC_ERR" , "MP_PARITY_ERR" , "MP_COHERENCE_ERR" , |
173 | "CMBIU_REQUEST_DECODE_ERR" , "CMBIU_PARITY_ERR" , "CMBIU_AXI_RESP_ERR" , |
174 | "0x9" , "RBI_BUS_ERR" , "0xb" , "0xc" , "0xd" , "0xe" , "0xf" , "0x10" , |
175 | "0x11" , "0x12" , "0x13" , "0x14" , "0x15" , "0x16" , "0x17" , "0x18" , |
176 | "0x19" , "0x1a" , "0x1b" , "0x1c" , "0x1d" , "0x1e" , "0x1f" |
177 | }; |
178 | |
179 | static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock); |
180 | static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags); |
181 | |
182 | phys_addr_t __mips_cm_phys_base(void) |
183 | { |
184 | unsigned long cmgcr; |
185 | |
186 | /* Check the CMGCRBase register is implemented */ |
187 | if (!(read_c0_config() & MIPS_CONF_M)) |
188 | return 0; |
189 | |
190 | if (!(read_c0_config2() & MIPS_CONF_M)) |
191 | return 0; |
192 | |
193 | if (!(read_c0_config3() & MIPS_CONF3_CMGCR)) |
194 | return 0; |
195 | |
196 | /* Read the address from CMGCRBase */ |
197 | cmgcr = read_c0_cmgcrbase(); |
198 | return (cmgcr & MIPS_CMGCRF_BASE) << (36 - 32); |
199 | } |
200 | |
201 | phys_addr_t mips_cm_phys_base(void) |
202 | __attribute__((weak, alias("__mips_cm_phys_base" ))); |
203 | |
204 | phys_addr_t __mips_cm_l2sync_phys_base(void) |
205 | { |
206 | u32 base_reg; |
207 | |
208 | /* |
209 | * If the L2-only sync region is already enabled then leave it at it's |
210 | * current location. |
211 | */ |
212 | base_reg = read_gcr_l2_only_sync_base(); |
213 | if (base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN) |
214 | return base_reg & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE; |
215 | |
216 | /* Default to following the CM */ |
217 | return mips_cm_phys_base() + MIPS_CM_GCR_SIZE; |
218 | } |
219 | |
220 | phys_addr_t mips_cm_l2sync_phys_base(void) |
221 | __attribute__((weak, alias("__mips_cm_l2sync_phys_base" ))); |
222 | |
223 | static void mips_cm_probe_l2sync(void) |
224 | { |
225 | unsigned major_rev; |
226 | phys_addr_t addr; |
227 | |
228 | /* L2-only sync was introduced with CM major revision 6 */ |
229 | major_rev = FIELD_GET(CM_GCR_REV_MAJOR, read_gcr_rev()); |
230 | if (major_rev < 6) |
231 | return; |
232 | |
233 | /* Find a location for the L2 sync region */ |
234 | addr = mips_cm_l2sync_phys_base(); |
235 | BUG_ON((addr & CM_GCR_L2_ONLY_SYNC_BASE_SYNCBASE) != addr); |
236 | if (!addr) |
237 | return; |
238 | |
239 | /* Set the region base address & enable it */ |
240 | write_gcr_l2_only_sync_base(addr | CM_GCR_L2_ONLY_SYNC_BASE_SYNCEN); |
241 | |
242 | /* Map the region */ |
243 | mips_cm_l2sync_base = ioremap(addr, MIPS_CM_L2SYNC_SIZE); |
244 | } |
245 | |
246 | int mips_cm_probe(void) |
247 | { |
248 | phys_addr_t addr; |
249 | u32 base_reg; |
250 | unsigned cpu; |
251 | |
252 | /* |
253 | * No need to probe again if we have already been |
254 | * here before. |
255 | */ |
256 | if (mips_gcr_base) |
257 | return 0; |
258 | |
259 | addr = mips_cm_phys_base(); |
260 | BUG_ON((addr & CM_GCR_BASE_GCRBASE) != addr); |
261 | if (!addr) |
262 | return -ENODEV; |
263 | |
264 | mips_gcr_base = ioremap(addr, MIPS_CM_GCR_SIZE); |
265 | if (!mips_gcr_base) |
266 | return -ENXIO; |
267 | |
268 | /* sanity check that we're looking at a CM */ |
269 | base_reg = read_gcr_base(); |
270 | if ((base_reg & CM_GCR_BASE_GCRBASE) != addr) { |
271 | pr_err("GCRs appear to have been moved (expected them at 0x%08lx)!\n" , |
272 | (unsigned long)addr); |
273 | iounmap(mips_gcr_base); |
274 | mips_gcr_base = NULL; |
275 | return -ENODEV; |
276 | } |
277 | |
278 | /* set default target to memory */ |
279 | change_gcr_base(CM_GCR_BASE_CMDEFTGT, CM_GCR_BASE_CMDEFTGT_MEM); |
280 | |
281 | /* disable CM regions */ |
282 | write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR); |
283 | write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK); |
284 | write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR); |
285 | write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK); |
286 | write_gcr_reg2_base(CM_GCR_REGn_BASE_BASEADDR); |
287 | write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK); |
288 | write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR); |
289 | write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK); |
290 | |
291 | /* probe for an L2-only sync region */ |
292 | mips_cm_probe_l2sync(); |
293 | |
294 | /* determine register width for this CM */ |
295 | mips_cm_is64 = IS_ENABLED(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3); |
296 | |
297 | for_each_possible_cpu(cpu) |
298 | spin_lock_init(&per_cpu(cm_core_lock, cpu)); |
299 | |
300 | return 0; |
301 | } |
302 | |
303 | void mips_cm_lock_other(unsigned int cluster, unsigned int core, |
304 | unsigned int vp, unsigned int block) |
305 | { |
306 | unsigned int curr_core, cm_rev; |
307 | u32 val; |
308 | |
309 | cm_rev = mips_cm_revision(); |
310 | preempt_disable(); |
311 | |
312 | if (cm_rev >= CM_REV_CM3) { |
313 | val = FIELD_PREP(CM3_GCR_Cx_OTHER_CORE, core) | |
314 | FIELD_PREP(CM3_GCR_Cx_OTHER_VP, vp); |
315 | |
316 | if (cm_rev >= CM_REV_CM3_5) { |
317 | val |= CM_GCR_Cx_OTHER_CLUSTER_EN; |
318 | val |= FIELD_PREP(CM_GCR_Cx_OTHER_CLUSTER, cluster); |
319 | val |= FIELD_PREP(CM_GCR_Cx_OTHER_BLOCK, block); |
320 | } else { |
321 | WARN_ON(cluster != 0); |
322 | WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL); |
323 | } |
324 | |
325 | /* |
326 | * We need to disable interrupts in SMP systems in order to |
327 | * ensure that we don't interrupt the caller with code which |
328 | * may modify the redirect register. We do so here in a |
329 | * slightly obscure way by using a spin lock, since this has |
330 | * the neat property of also catching any nested uses of |
331 | * mips_cm_lock_other() leading to a deadlock or a nice warning |
332 | * with lockdep enabled. |
333 | */ |
334 | spin_lock_irqsave(this_cpu_ptr(&cm_core_lock), |
335 | *this_cpu_ptr(&cm_core_lock_flags)); |
336 | } else { |
337 | WARN_ON(cluster != 0); |
338 | WARN_ON(block != CM_GCR_Cx_OTHER_BLOCK_LOCAL); |
339 | |
340 | /* |
341 | * We only have a GCR_CL_OTHER per core in systems with |
342 | * CM 2.5 & older, so have to ensure other VP(E)s don't |
343 | * race with us. |
344 | */ |
345 | curr_core = cpu_core(¤t_cpu_data); |
346 | spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core), |
347 | per_cpu(cm_core_lock_flags, curr_core)); |
348 | |
349 | val = FIELD_PREP(CM_GCR_Cx_OTHER_CORENUM, core); |
350 | } |
351 | |
352 | write_gcr_cl_other(val); |
353 | |
354 | /* |
355 | * Ensure the core-other region reflects the appropriate core & |
356 | * VP before any accesses to it occur. |
357 | */ |
358 | mb(); |
359 | } |
360 | |
361 | void mips_cm_unlock_other(void) |
362 | { |
363 | unsigned int curr_core; |
364 | |
365 | if (mips_cm_revision() < CM_REV_CM3) { |
366 | curr_core = cpu_core(¤t_cpu_data); |
367 | spin_unlock_irqrestore(lock: &per_cpu(cm_core_lock, curr_core), |
368 | per_cpu(cm_core_lock_flags, curr_core)); |
369 | } else { |
370 | spin_unlock_irqrestore(this_cpu_ptr(&cm_core_lock), |
371 | flags: *this_cpu_ptr(&cm_core_lock_flags)); |
372 | } |
373 | |
374 | preempt_enable(); |
375 | } |
376 | |
377 | void mips_cm_error_report(void) |
378 | { |
379 | u64 cm_error, cm_addr, cm_other; |
380 | unsigned long revision; |
381 | int ocause, cause; |
382 | char buf[256]; |
383 | |
384 | if (!mips_cm_present()) |
385 | return; |
386 | |
387 | revision = mips_cm_revision(); |
388 | cm_error = read_gcr_error_cause(); |
389 | cm_addr = read_gcr_error_addr(); |
390 | cm_other = read_gcr_error_mult(); |
391 | |
392 | if (revision < CM_REV_CM3) { /* CM2 */ |
393 | cause = FIELD_GET(CM_GCR_ERROR_CAUSE_ERRTYPE, cm_error); |
394 | ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other); |
395 | |
396 | if (!cause) |
397 | return; |
398 | |
399 | if (cause < 16) { |
400 | unsigned long cca_bits = (cm_error >> 15) & 7; |
401 | unsigned long tr_bits = (cm_error >> 12) & 7; |
402 | unsigned long cmd_bits = (cm_error >> 7) & 0x1f; |
403 | unsigned long stag_bits = (cm_error >> 3) & 15; |
404 | unsigned long sport_bits = (cm_error >> 0) & 7; |
405 | |
406 | snprintf(buf, size: sizeof(buf), |
407 | fmt: "CCA=%lu TR=%s MCmd=%s STag=%lu " |
408 | "SPort=%lu\n" , cca_bits, cm2_tr[tr_bits], |
409 | cm2_cmd[cmd_bits], stag_bits, sport_bits); |
410 | } else if (cause < 24) { |
411 | /* glob state & sresp together */ |
412 | unsigned long c3_bits = (cm_error >> 18) & 7; |
413 | unsigned long c2_bits = (cm_error >> 15) & 7; |
414 | unsigned long c1_bits = (cm_error >> 12) & 7; |
415 | unsigned long c0_bits = (cm_error >> 9) & 7; |
416 | unsigned long sc_bit = (cm_error >> 8) & 1; |
417 | unsigned long cmd_bits = (cm_error >> 3) & 0x1f; |
418 | unsigned long sport_bits = (cm_error >> 0) & 7; |
419 | |
420 | snprintf(buf, size: sizeof(buf), |
421 | fmt: "C3=%s C2=%s C1=%s C0=%s SC=%s " |
422 | "MCmd=%s SPort=%lu\n" , |
423 | cm2_core[c3_bits], cm2_core[c2_bits], |
424 | cm2_core[c1_bits], cm2_core[c0_bits], |
425 | sc_bit ? "True" : "False" , |
426 | cm2_cmd[cmd_bits], sport_bits); |
427 | } else { |
428 | unsigned long muc_bit = (cm_error >> 23) & 1; |
429 | unsigned long ins_bits = (cm_error >> 18) & 0x1f; |
430 | unsigned long arr_bits = (cm_error >> 16) & 3; |
431 | unsigned long dw_bits = (cm_error >> 12) & 15; |
432 | unsigned long way_bits = (cm_error >> 9) & 7; |
433 | unsigned long mway_bit = (cm_error >> 8) & 1; |
434 | unsigned long syn_bits = (cm_error >> 0) & 0xFF; |
435 | |
436 | snprintf(buf, size: sizeof(buf), |
437 | fmt: "Type=%s%s Instr=%s DW=%lu Way=%lu " |
438 | "MWay=%s Syndrome=0x%02lx" , |
439 | muc_bit ? "Multi-UC " : "" , |
440 | cm2_l2_type[arr_bits], |
441 | cm2_l2_instr[ins_bits], dw_bits, way_bits, |
442 | mway_bit ? "True" : "False" , syn_bits); |
443 | } |
444 | pr_err("CM_ERROR=%08llx %s <%s>\n" , cm_error, |
445 | cm2_causes[cause], buf); |
446 | pr_err("CM_ADDR =%08llx\n" , cm_addr); |
447 | pr_err("CM_OTHER=%08llx %s\n" , cm_other, cm2_causes[ocause]); |
448 | } else { /* CM3 */ |
449 | ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits; |
450 | ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit; |
451 | |
452 | cause = FIELD_GET(CM3_GCR_ERROR_CAUSE_ERRTYPE, cm_error); |
453 | ocause = FIELD_GET(CM_GCR_ERROR_MULT_ERR2ND, cm_other); |
454 | |
455 | if (!cause) |
456 | return; |
457 | |
458 | /* Used by cause == {1,2,3} */ |
459 | core_id_bits = (cm_error >> 22) & 0xf; |
460 | vp_id_bits = (cm_error >> 18) & 0xf; |
461 | cmd_bits = (cm_error >> 14) & 0xf; |
462 | cmd_group_bits = (cm_error >> 11) & 0xf; |
463 | cm3_cca_bits = (cm_error >> 8) & 7; |
464 | mcp_bits = (cm_error >> 5) & 0xf; |
465 | cm3_tr_bits = (cm_error >> 1) & 0xf; |
466 | sched_bit = cm_error & 0x1; |
467 | |
468 | if (cause == 1 || cause == 3) { /* Tag ECC */ |
469 | unsigned long tag_ecc = (cm_error >> 57) & 0x1; |
470 | unsigned long tag_way_bits = (cm_error >> 29) & 0xffff; |
471 | unsigned long dword_bits = (cm_error >> 49) & 0xff; |
472 | unsigned long data_way_bits = (cm_error >> 45) & 0xf; |
473 | unsigned long data_sets_bits = (cm_error >> 29) & 0xfff; |
474 | unsigned long bank_bit = (cm_error >> 28) & 0x1; |
475 | snprintf(buf, size: sizeof(buf), |
476 | fmt: "%s ECC Error: Way=%lu (DWORD=%lu, Sets=%lu)" |
477 | "Bank=%lu CoreID=%lu VPID=%lu Command=%s" |
478 | "Command Group=%s CCA=%lu MCP=%d" |
479 | "Transaction type=%s Scheduler=%lu\n" , |
480 | tag_ecc ? "TAG" : "DATA" , |
481 | tag_ecc ? (unsigned long)ffs(tag_way_bits) - 1 : |
482 | data_way_bits, bank_bit, dword_bits, |
483 | data_sets_bits, |
484 | core_id_bits, vp_id_bits, |
485 | cm3_cmd[cmd_bits], |
486 | cm3_cmd_group[cmd_group_bits], |
487 | cm3_cca_bits, 1 << mcp_bits, |
488 | cm3_tr[cm3_tr_bits], sched_bit); |
489 | } else if (cause == 2) { |
490 | unsigned long data_error_type = (cm_error >> 41) & 0xfff; |
491 | unsigned long data_decode_cmd = (cm_error >> 37) & 0xf; |
492 | unsigned long data_decode_group = (cm_error >> 34) & 0x7; |
493 | unsigned long data_decode_destination_id = (cm_error >> 28) & 0x3f; |
494 | |
495 | snprintf(buf, size: sizeof(buf), |
496 | fmt: "Decode Request Error: Type=%lu, Command=%lu" |
497 | "Command Group=%lu Destination ID=%lu" |
498 | "CoreID=%lu VPID=%lu Command=%s" |
499 | "Command Group=%s CCA=%lu MCP=%d" |
500 | "Transaction type=%s Scheduler=%lu\n" , |
501 | data_error_type, data_decode_cmd, |
502 | data_decode_group, data_decode_destination_id, |
503 | core_id_bits, vp_id_bits, |
504 | cm3_cmd[cmd_bits], |
505 | cm3_cmd_group[cmd_group_bits], |
506 | cm3_cca_bits, 1 << mcp_bits, |
507 | cm3_tr[cm3_tr_bits], sched_bit); |
508 | } else { |
509 | buf[0] = 0; |
510 | } |
511 | |
512 | pr_err("CM_ERROR=%llx %s <%s>\n" , cm_error, |
513 | cm3_causes[cause], buf); |
514 | pr_err("CM_ADDR =%llx\n" , cm_addr); |
515 | pr_err("CM_OTHER=%llx %s\n" , cm_other, cm3_causes[ocause]); |
516 | } |
517 | |
518 | /* reprime cause register */ |
519 | write_gcr_error_cause(cm_error); |
520 | } |
521 | |