blob: 835d4b0095031475b66b82caa9f873b1f82d0b0d [file] [log] [blame]
Kyle Yan3a641f42016-11-21 14:00:04 -08001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/io.h>
16#include <linux/slab.h>
17#include <linux/interrupt.h>
18#include <linux/irq.h>
19#include <linux/cpu_pm.h>
20#include <linux/platform_device.h>
21#include <soc/qcom/scm.h>
22#include <linux/of.h>
23#include <linux/clk.h>
24
25#define MODULE_NAME "gladiator_error_reporting"
26
27#define INVALID_NUM 0xDEADBEEF
28
29struct reg_off {
30 unsigned int gladiator_id_coreid;
31 unsigned int gladiator_id_revisionid;
32 unsigned int gladiator_faulten;
33 unsigned int gladiator_errvld;
34 unsigned int gladiator_errclr;
35 unsigned int gladiator_errlog0;
36 unsigned int gladiator_errlog1;
37 unsigned int gladiator_errlog2;
38 unsigned int gladiator_errlog3;
39 unsigned int gladiator_errlog4;
40 unsigned int gladiator_errlog5;
41 unsigned int gladiator_errlog6;
42 unsigned int gladiator_errlog7;
43 unsigned int gladiator_errlog8;
44 unsigned int observer_0_id_coreid;
45 unsigned int observer_0_id_revisionid;
46 unsigned int observer_0_faulten;
47 unsigned int observer_0_errvld;
48 unsigned int observer_0_errclr;
49 unsigned int observer_0_errlog0;
50 unsigned int observer_0_errlog1;
51 unsigned int observer_0_errlog2;
52 unsigned int observer_0_errlog3;
53 unsigned int observer_0_errlog4;
54 unsigned int observer_0_errlog5;
55 unsigned int observer_0_errlog6;
56 unsigned int observer_0_errlog7;
57 unsigned int observer_0_errlog8;
58 unsigned int observer_0_stallen;
59};
60
61struct reg_masks_shift {
62 unsigned int gld_trans_opcode_mask;
63 unsigned int gld_trans_opcode_shift;
64 unsigned int gld_error_type_mask;
65 unsigned int gld_error_type_shift;
66 unsigned int gld_len1_mask;
67 unsigned int gld_len1_shift;
68 unsigned int gld_trans_sourceid_mask;
69 unsigned int gld_trans_sourceid_shift;
70 unsigned int gld_trans_targetid_mask;
71 unsigned int gld_trans_targetid_shift;
72 unsigned int gld_errlog_error;
73 unsigned int gld_errlog5_error_type_mask;
74 unsigned int gld_errlog5_error_type_shift;
75 unsigned int gld_ace_port_parity_mask;
76 unsigned int gld_ace_port_parity_shift;
77 unsigned int gld_ace_port_disconnect_mask;
78 unsigned int gld_ace_port_disconnect_shift;
79 unsigned int gld_ace_port_directory_mask;
80 unsigned int gld_ace_port_directory_shift;
81 unsigned int gld_index_parity_mask;
82 unsigned int gld_index_parity_shift;
83 unsigned int obs_trans_opcode_mask;
84 unsigned int obs_trans_opcode_shift;
85 unsigned int obs_error_type_mask;
86 unsigned int obs_error_type_shift;
87 unsigned int obs_len1_mask;
88 unsigned int obs_len1_shift;
89};
90
91struct msm_gladiator_data {
92 void __iomem *gladiator_virt_base;
93 int erp_irq;
94 struct notifier_block pm_notifier_block;
95 struct clk *qdss_clk;
96 struct reg_off *reg_offs;
97 struct reg_masks_shift *reg_masks_shifts;
98 bool glad_v2;
99 bool glad_v3;
100};
101
102static int enable_panic_on_error;
103module_param(enable_panic_on_error, int, 0000);
104
105enum gld_trans_opcode {
106 GLD_RD,
107 GLD_RDX,
108 GLD_RDL,
109 GLD_RESERVED,
110 GLD_WR,
111 GLD_WRC,
112 GLD_PRE,
113};
114
115enum obs_trans_opcode {
116 OBS_RD,
117 OBS_RDW,
118 OBS_RDL,
119 OBS_RDX,
120 OBS_WR,
121 OBS_WRW,
122 OBS_WRC,
123 OBS_RESERVED,
124 OBS_PRE,
125 OBS_URG,
126};
127
128enum obs_err_code {
129 OBS_SLV,
130 OBS_DEC,
131 OBS_UNS,
132 OBS_DISC,
133 OBS_SEC,
134 OBS_HIDE,
135 OBS_TMO,
136 OBS_RSV,
137};
138
139enum err_log {
140 ID_COREID,
141 ID_REVISIONID,
142 FAULTEN,
143 ERRVLD,
144 ERRCLR,
145 ERR_LOG0,
146 ERR_LOG1,
147 ERR_LOG2,
148 ERR_LOG3,
149 ERR_LOG4,
150 ERR_LOG5,
151 ERR_LOG6,
152 ERR_LOG7,
153 ERR_LOG8,
154 STALLEN,
155 MAX_NUM,
156};
157
158enum type_logger_error {
159 DATA_TRANSFER_ERROR,
160 DVM_ERROR,
161 TX_ERROR,
162 TXR_ERROR,
163 DISCONNECT_ERROR,
164 DIRECTORY_ERROR,
165 PARITY_ERROR,
166};
167
168static void clear_gladiator_error(void __iomem *gladiator_virt_base,
169 struct reg_off *offs)
170{
171 writel_relaxed(1, gladiator_virt_base + offs->gladiator_errclr);
172 writel_relaxed(1, gladiator_virt_base + offs->observer_0_errclr);
173}
174
175static inline void print_gld_transaction(unsigned int opc)
176{
177 switch (opc) {
178 case GLD_RD:
179 pr_alert("Transaction type: READ\n");
180 break;
181 case GLD_RDX:
182 pr_alert("Transaction type: EXCLUSIVE READ\n");
183 break;
184 case GLD_RDL:
185 pr_alert("Transaction type: LINKED READ\n");
186 break;
187 case GLD_WR:
188 pr_alert("Transaction type: WRITE\n");
189 break;
190 case GLD_WRC:
191 pr_alert("Transaction type: CONDITIONAL WRITE\n");
192 break;
193 case GLD_PRE:
194 pr_alert("Transaction: Preamble packet of linked sequence\n");
195 break;
196 default:
197 pr_alert("Transaction type: Unknown; value:%u\n", opc);
198 }
199}
200
201static inline void print_gld_errtype(unsigned int errtype)
202{
203 if (errtype == 0)
204 pr_alert("Error type: Snoop data transfer\n");
205 else if (errtype == 1)
206 pr_alert("Error type: DVM error\n");
207 else if (errtype == 3)
208 pr_alert("Error type: Disconnect, directory, or parity error\n");
209 else
210 pr_alert("Error type: Unknown; value:%u\n", errtype);
211}
212
213static void decode_gld_errlog0(u32 err_reg,
214 struct reg_masks_shift *mask_shifts)
215{
216 unsigned int opc, errtype, len1;
217
218 opc = (err_reg & mask_shifts->gld_trans_opcode_mask) >>
219 mask_shifts->gld_trans_opcode_shift;
220 errtype = (err_reg & mask_shifts->gld_error_type_mask) >>
221 mask_shifts->gld_error_type_shift;
222 len1 = (err_reg & mask_shifts->gld_len1_mask) >>
223 mask_shifts->gld_len1_shift;
224
225 print_gld_transaction(opc);
226 print_gld_errtype(errtype);
227 pr_alert("number of payload bytes: %d\n", len1 + 1);
228}
229
230static void decode_gld_errlog1(u32 err_reg,
231 struct reg_masks_shift *mask_shifts)
232{
233 if ((err_reg & mask_shifts->gld_errlog_error) ==
234 mask_shifts->gld_errlog_error)
235 pr_alert("Transaction issued on IO target generic interface\n");
236 else
237 pr_alert("Transaction source ID: %d\n",
238 (err_reg & mask_shifts->gld_trans_sourceid_mask)
239 >> mask_shifts->gld_trans_sourceid_shift);
240}
241
242static void decode_gld_errlog2(u32 err_reg,
243 struct reg_masks_shift *mask_shifts)
244{
245 if ((err_reg & mask_shifts->gld_errlog_error) ==
246 mask_shifts->gld_errlog_error)
247 pr_alert("Error response coming from: external DVM network\n");
248 else
249 pr_alert("Error response coming from: Target ID: %d\n",
250 (err_reg & mask_shifts->gld_trans_targetid_mask)
251 >> mask_shifts->gld_trans_targetid_shift);
252}
253
254static void decode_ace_port_index(u32 type, u32 error,
255 struct reg_masks_shift *mask_shifts)
256{
257 unsigned int port;
258
259 switch (type) {
260 case DISCONNECT_ERROR:
261 port = (error & mask_shifts->gld_ace_port_disconnect_mask)
262 >> mask_shifts->gld_ace_port_disconnect_shift;
263 pr_alert("ACE port index: %d\n", port);
264 break;
265 case DIRECTORY_ERROR:
266 port = (error & mask_shifts->gld_ace_port_directory_mask)
267 >> mask_shifts->gld_ace_port_directory_shift;
268 pr_alert("ACE port index: %d\n", port);
269 break;
270 case PARITY_ERROR:
271 port = (error & mask_shifts->gld_ace_port_parity_mask)
272 >> mask_shifts->gld_ace_port_parity_shift;
273 pr_alert("ACE port index: %d\n", port);
274 }
275}
276
277static void decode_index_parity(u32 error, struct reg_masks_shift *mask_shifts)
278{
279 pr_alert("Index: %d\n",
280 (error & mask_shifts->gld_index_parity_mask)
281 >> mask_shifts->gld_index_parity_shift);
282}
283
284static void decode_gld_logged_error(u32 err_reg5,
285 struct reg_masks_shift *mask_shifts)
286{
287 unsigned int log_err_type, i, value;
288
289 log_err_type = (err_reg5 & mask_shifts->gld_errlog5_error_type_mask)
290 >> mask_shifts->gld_errlog5_error_type_shift;
291 for (i = 0 ; i <= 6 ; i++) {
292 value = log_err_type & 0x1;
293 switch (i) {
294 case DATA_TRANSFER_ERROR:
295 if (value == 0)
296 continue;
297 pr_alert("Error type: Data transfer error\n");
298 break;
299 case DVM_ERROR:
300 if (value == 0)
301 continue;
302 pr_alert("Error type: DVM error\n");
303 break;
304 case TX_ERROR:
305 if (value == 0)
306 continue;
307 pr_alert("Error type: Tx error\n");
308 break;
309 case TXR_ERROR:
310 if (value == 0)
311 continue;
312 pr_alert("Error type: TxR error\n");
313 break;
314 case DISCONNECT_ERROR:
315 if (value == 0)
316 continue;
317 pr_alert("Error type: Disconnect error\n");
318 decode_ace_port_index(
319 DISCONNECT_ERROR,
320 err_reg5,
321 mask_shifts);
322 break;
323 case DIRECTORY_ERROR:
324 if (value == 0)
325 continue;
326 pr_alert("Error type: Directory error\n");
327 decode_ace_port_index(
328 DIRECTORY_ERROR,
329 err_reg5,
330 mask_shifts);
331 break;
332 case PARITY_ERROR:
333 if (value == 0)
334 continue;
335 pr_alert("Error type: Parity error\n");
336 decode_ace_port_index(PARITY_ERROR, err_reg5,
337 mask_shifts);
338 decode_index_parity(err_reg5, mask_shifts);
339 break;
340 }
341 log_err_type = log_err_type >> 1;
342 }
343}
344
345static void decode_gld_errlog(u32 err_reg, unsigned int err_log,
346 struct msm_gladiator_data *msm_gld_data)
347{
348 switch (err_log) {
349 case ERR_LOG0:
350 decode_gld_errlog0(err_reg, msm_gld_data->reg_masks_shifts);
351 break;
352 case ERR_LOG1:
353 decode_gld_errlog1(err_reg, msm_gld_data->reg_masks_shifts);
354 break;
355 case ERR_LOG2:
356 decode_gld_errlog2(err_reg, msm_gld_data->reg_masks_shifts);
357 break;
358 case ERR_LOG3:
359 pr_alert("Lower 32-bits of error address: %08x\n", err_reg);
360 break;
361 case ERR_LOG4:
362 pr_alert("Upper 32-bits of error address: %08x\n", err_reg);
363 break;
364 case ERR_LOG5:
365 pr_alert("Lower 32-bits of user: %08x\n", err_reg);
366 break;
367 case ERR_LOG6:
368 pr_alert("Mid 32-bits(63-32) of user: %08x\n", err_reg);
369 break;
370 case ERR_LOG7:
371 break;
372 case ERR_LOG8:
373 pr_alert("Upper 32-bits(95-64) of user: %08x\n", err_reg);
374 break;
375 default:
376 pr_alert("Invalid error register; reg num:%u\n", err_log);
377 }
378}
379
380static inline void print_obs_transaction(unsigned int opc)
381{
382 switch (opc) {
383 case OBS_RD:
384 pr_alert("Transaction type: READ\n");
385 break;
386 case OBS_RDW:
387 pr_alert("Transaction type: WRAPPED READ\n");
388 break;
389 case OBS_RDL:
390 pr_alert("Transaction type: LINKED READ\n");
391 break;
392 case OBS_RDX:
393 pr_alert("Transaction type: EXCLUSIVE READ\n");
394 break;
395 case OBS_WR:
396 pr_alert("Transaction type: WRITE\n");
397 break;
398 case OBS_WRW:
399 pr_alert("Transaction type: WRAPPED WRITE\n");
400 break;
401 case OBS_WRC:
402 pr_alert("Transaction type: CONDITIONAL WRITE\n");
403 break;
404 case OBS_PRE:
405 pr_alert("Transaction: Preamble packet of linked sequence\n");
406 break;
407 case OBS_URG:
408 pr_alert("Transaction type: Urgency Packet\n");
409 break;
410 default:
411 pr_alert("Transaction type: Unknown; value:%u\n", opc);
412 }
413}
414
415static inline void print_obs_errcode(unsigned int errcode)
416{
417 switch (errcode) {
418 case OBS_SLV:
419 pr_alert("Error code: Target error detected by slave\n");
420 pr_alert("Source: Target\n");
421 break;
422 case OBS_DEC:
423 pr_alert("Error code: Address decode error\n");
424 pr_alert("Source: Initiator NIU\n");
425 break;
426 case OBS_UNS:
427 pr_alert("Error code: Unsupported request\n");
428 pr_alert("Source: Target NIU\n");
429 break;
430 case OBS_DISC:
431 pr_alert("Error code: Disconnected target or domain\n");
432 pr_alert("Source: Power Disconnect\n");
433 break;
434 case OBS_SEC:
435 pr_alert("Error code: Security violation\n");
436 pr_alert("Source: Initiator NIU or Firewall\n");
437 break;
438 case OBS_HIDE:
439 pr_alert("Error :Hidden security violation, reported as OK\n");
440 pr_alert("Source: Firewall\n");
441 break;
442 case OBS_TMO:
443 pr_alert("Error code: Time-out\n");
444 pr_alert("Source: Target NIU\n");
445 break;
446 default:
447 pr_alert("Error code: Unknown; code:%u\n", errcode);
448 }
449}
450
451static void decode_obs_errlog0(u32 err_reg,
452 struct reg_masks_shift *mask_shifts)
453{
454 unsigned int opc, errcode;
455
456 opc = (err_reg & mask_shifts->obs_trans_opcode_mask) >>
457 mask_shifts->obs_trans_opcode_shift;
458 errcode = (err_reg & mask_shifts->obs_error_type_mask) >>
459 mask_shifts->obs_error_type_shift;
460
461 print_obs_transaction(opc);
462 print_obs_errcode(errcode);
463}
464
465static void decode_obs_errlog0_len(u32 err_reg,
466 struct reg_masks_shift *mask_shifts)
467{
468 unsigned int len1;
469
470 len1 = (err_reg & mask_shifts->obs_len1_mask) >>
471 mask_shifts->obs_len1_shift;
472 pr_alert("number of payload bytes: %d\n", len1 + 1);
473}
474
475static void decode_obs_errlog(u32 err_reg, unsigned int err_log,
476 struct msm_gladiator_data *msm_gld_data)
477{
478 switch (err_log) {
479 case ERR_LOG0:
480 decode_obs_errlog0(err_reg, msm_gld_data->reg_masks_shifts);
481 decode_obs_errlog0_len(err_reg, msm_gld_data->reg_masks_shifts);
482 break;
483 case ERR_LOG1:
484 pr_alert("RouteId of the error: %08x\n", err_reg);
485 break;
486 case ERR_LOG2:
487 /* reserved error log register */
488 break;
489 case ERR_LOG3:
490 pr_alert("Lower 32-bits of error address: %08x\n", err_reg);
491 break;
492 case ERR_LOG4:
493 pr_alert("Upper 12-bits of error address: %08x\n", err_reg);
494 break;
495 case ERR_LOG5:
496 pr_alert("Lower 13-bits of user: %08x\n", err_reg);
497 break;
498 case ERR_LOG6:
499 /* reserved error log register */
500 break;
501 case ERR_LOG7:
502 pr_alert("Security filed of the logged error: %08x\n", err_reg);
503 break;
504 case ERR_LOG8:
505 /* reserved error log register */
506 break;
507 case STALLEN:
508 pr_alert("stall mode of the error logger: %08x\n",
509 err_reg & 0x1);
510 break;
511 default:
512 pr_alert("Invalid error register; reg num:%u\n", err_log);
513 }
514}
515
516static void decode_obs_errlog_v3(u32 err_reg, unsigned int err_log,
517 struct msm_gladiator_data *msm_gld_data)
518{
519 switch (err_log) {
520 case ERR_LOG0:
521 decode_obs_errlog0(err_reg, msm_gld_data->reg_masks_shifts);
522 break;
523 case ERR_LOG1:
524 decode_obs_errlog0_len(err_reg, msm_gld_data->reg_masks_shifts);
525 break;
526 case ERR_LOG2:
527 pr_alert("Path of the error: %08x\n", err_reg);
528 break;
529 case ERR_LOG3:
530 pr_alert("ExtID of the error: %08x\n", err_reg);
531 break;
532 case ERR_LOG4:
533 pr_alert("ERRLOG2_LSB: %08x\n", err_reg);
534 break;
535 case ERR_LOG5:
536 pr_alert("ERRLOG2_MSB: %08x\n", err_reg);
537 break;
538 case ERR_LOG6:
539 pr_alert("ERRLOG3_LSB: %08x\n", err_reg);
540 break;
541 case ERR_LOG7:
542 pr_alert("ERRLOG3_MSB: %08x\n", err_reg);
543 break;
544 case FAULTEN:
545 pr_alert("stall mode of the error logger: %08x\n",
546 err_reg & 0x3);
547 break;
548 default:
549 pr_alert("Invalid error register; reg num:%u\n", err_log);
550 }
551}
552
553static u32 get_gld_offset(unsigned int err_log, struct reg_off *offs)
554{
555 u32 offset = 0;
556
557 switch (err_log) {
558 case FAULTEN:
559 offset = offs->gladiator_faulten;
560 break;
561 case ERRVLD:
562 offset = offs->gladiator_errvld;
563 break;
564 case ERRCLR:
565 offset = offs->gladiator_errclr;
566 break;
567 case ERR_LOG0:
568 offset = offs->gladiator_errlog0;
569 break;
570 case ERR_LOG1:
571 offset = offs->gladiator_errlog1;
572 break;
573 case ERR_LOG2:
574 offset = offs->gladiator_errlog2;
575 break;
576 case ERR_LOG3:
577 offset = offs->gladiator_errlog3;
578 break;
579 case ERR_LOG4:
580 offset = offs->gladiator_errlog4;
581 break;
582 case ERR_LOG5:
583 offset = offs->gladiator_errlog5;
584 break;
585 case ERR_LOG6:
586 offset = offs->gladiator_errlog6;
587 break;
588 case ERR_LOG7:
589 offset = offs->gladiator_errlog7;
590 break;
591 case ERR_LOG8:
592 offset = offs->gladiator_errlog8;
593 break;
594 default:
595 pr_alert("Invalid gladiator error register; reg num:%u\n",
596 err_log);
597 }
598 return offset;
599}
600
601static u32 get_obs_offset(unsigned int err_log, struct reg_off *offs)
602{
603 u32 offset = 0;
604
605 switch (err_log) {
606 case FAULTEN:
607 offset = offs->observer_0_faulten;
608 break;
609 case ERRVLD:
610 offset = offs->observer_0_errvld;
611 break;
612 case ERRCLR:
613 offset = offs->observer_0_errclr;
614 break;
615 case ERR_LOG0:
616 offset = offs->observer_0_errlog0;
617 break;
618 case ERR_LOG1:
619 offset = offs->observer_0_errlog1;
620 break;
621 case ERR_LOG2:
622 offset = offs->observer_0_errlog2;
623 break;
624 case ERR_LOG3:
625 offset = offs->observer_0_errlog3;
626 break;
627 case ERR_LOG4:
628 offset = offs->observer_0_errlog4;
629 break;
630 case ERR_LOG5:
631 offset = offs->observer_0_errlog5;
632 break;
633 case ERR_LOG6:
634 offset = offs->observer_0_errlog6;
635 break;
636 case ERR_LOG7:
637 offset = offs->observer_0_errlog7;
638 break;
639 case ERR_LOG8:
640 offset = offs->observer_0_errlog8;
641 break;
642 case STALLEN:
643 offset = offs->observer_0_stallen;
644 break;
645 default:
646 pr_alert("Invalid observer error register; reg num:%u\n",
647 err_log);
648 }
649 return offset;
650}
651
652static void decode_gld_errlog5(struct msm_gladiator_data *msm_gld_data)
653{
654 unsigned int errtype;
655 u32 err_reg0, err_reg5;
656 struct reg_masks_shift *mask_shifts = msm_gld_data->reg_masks_shifts;
657
658 err_reg0 = readl_relaxed(msm_gld_data->gladiator_virt_base +
659 get_gld_offset(ERR_LOG0, msm_gld_data->reg_offs));
660 err_reg5 = readl_relaxed(msm_gld_data->gladiator_virt_base +
661 get_gld_offset(ERR_LOG5, msm_gld_data->reg_offs));
662
663 errtype = (err_reg0 & mask_shifts->gld_error_type_mask) >>
664 mask_shifts->gld_error_type_shift;
665 if (errtype == 3)
666 decode_gld_logged_error(err_reg5, mask_shifts);
667 else if (errtype == 0 || errtype == 1)
668 pr_alert("Lower 32-bits of user: %08x\n", err_reg5);
669 else
670 pr_alert("Error type: Unknown; value:%u\n", errtype);
671}
672
673static void dump_gld_err_regs(struct msm_gladiator_data *msm_gld_data,
674 unsigned int err_buf[MAX_NUM])
675{
676 unsigned int err_log;
677 unsigned int start = FAULTEN;
678 unsigned int end = ERR_LOG8;
679
680 if (msm_gld_data->glad_v2 || msm_gld_data->glad_v3) {
681 start = FAULTEN;
682 end = ERR_LOG8;
683 }
684
685 pr_alert("Main log register data:\n");
686 for (err_log = start; err_log <= end; err_log++) {
687 err_buf[err_log] = readl_relaxed(
688 msm_gld_data->gladiator_virt_base +
689 get_gld_offset(err_log,
690 msm_gld_data->reg_offs));
691 pr_alert("%08x ", err_buf[err_log]);
692 }
693}
694
695static void dump_obsrv_err_regs(struct msm_gladiator_data *msm_gld_data,
696 unsigned int err_buf[MAX_NUM])
697{
698 unsigned int err_log;
699 unsigned int start = ID_COREID;
700 unsigned int end = STALLEN;
701
702 if (msm_gld_data->glad_v2) {
703 start = ID_COREID;
704 end = STALLEN;
705 } else if (msm_gld_data->glad_v3) {
706 start = FAULTEN;
707 end = ERR_LOG7;
708 }
709
710 pr_alert("Observer log register data:\n");
711 for (err_log = start; err_log <= end; err_log++) {
712 err_buf[err_log] = readl_relaxed(
713 msm_gld_data->gladiator_virt_base +
714 get_obs_offset(
715 err_log,
716 msm_gld_data->reg_offs)
717 );
718 pr_alert("%08x ", err_buf[err_log]);
719 }
720}
721
722static void parse_gld_err_regs(struct msm_gladiator_data *msm_gld_data,
723 unsigned int err_buf[MAX_NUM])
724{
725 unsigned int err_log;
726
727 pr_alert("Main error log register data:\n");
728 for (err_log = ERR_LOG0; err_log <= ERR_LOG8; err_log++) {
729 /* skip log register 7 as its reserved */
730 if (err_log == ERR_LOG7)
731 continue;
732 if (err_log == ERR_LOG5) {
733 decode_gld_errlog5(msm_gld_data);
734 continue;
735 }
736 decode_gld_errlog(err_buf[err_log], err_log,
737 msm_gld_data);
738 }
739}
740
741static void parse_obsrv_err_regs(struct msm_gladiator_data *msm_gld_data,
742 unsigned int err_buf[MAX_NUM])
743{
744 unsigned int err_log;
745
746 pr_alert("Observor error log register data:\n");
747 if (msm_gld_data->glad_v2) {
748 for (err_log = ERR_LOG0; err_log <= STALLEN; err_log++) {
749 /* skip log register 2, 6 and 8 as they are reserved */
750 if ((err_log == ERR_LOG2) || (err_log == ERR_LOG6)
751 || (err_log == ERR_LOG8))
752 continue;
753 decode_obs_errlog(err_buf[err_log], err_log,
754 msm_gld_data);
755 }
756 } else if (msm_gld_data->glad_v3) {
757 decode_obs_errlog_v3(err_buf[STALLEN], STALLEN,
758 msm_gld_data);
759 for (err_log = ERR_LOG0; err_log <= ERR_LOG7; err_log++) {
760 decode_obs_errlog_v3(err_buf[err_log], err_log,
761 msm_gld_data);
762 }
763 }
764
765}
766
767static irqreturn_t msm_gladiator_isr(int irq, void *dev_id)
768{
769 unsigned int gld_err_buf[MAX_NUM], obs_err_buf[MAX_NUM];
770
771 struct msm_gladiator_data *msm_gld_data = dev_id;
772
773 /* Check validity */
774 bool gld_err_valid = readl_relaxed(msm_gld_data->gladiator_virt_base +
775 msm_gld_data->reg_offs->gladiator_errvld);
776
777 bool obsrv_err_valid = readl_relaxed(
778 msm_gld_data->gladiator_virt_base +
779 msm_gld_data->reg_offs->observer_0_errvld);
780
781 if (!gld_err_valid && !obsrv_err_valid) {
782 pr_err("%s Invalid Gladiator error reported, clear it\n",
783 __func__);
784 /* Clear IRQ */
785 clear_gladiator_error(msm_gld_data->gladiator_virt_base,
786 msm_gld_data->reg_offs);
787 return IRQ_HANDLED;
788 }
789 pr_alert("Gladiator Error Detected:\n");
790 if (gld_err_valid)
791 dump_gld_err_regs(msm_gld_data, gld_err_buf);
792
793 if (obsrv_err_valid)
794 dump_obsrv_err_regs(msm_gld_data, obs_err_buf);
795
796 if (gld_err_valid)
797 parse_gld_err_regs(msm_gld_data, gld_err_buf);
798
799 if (obsrv_err_valid)
800 parse_obsrv_err_regs(msm_gld_data, obs_err_buf);
801
802 /* Clear IRQ */
803 clear_gladiator_error(msm_gld_data->gladiator_virt_base,
804 msm_gld_data->reg_offs);
805 if (enable_panic_on_error)
806 panic("Gladiator Cache Interconnect Error Detected!\n");
807 else
808 WARN(1, "Gladiator Cache Interconnect Error Detected\n");
809
810 return IRQ_HANDLED;
811}
812
813static const struct of_device_id gladiator_erp_match_table[] = {
814 { .compatible = "qcom,msm-gladiator-v2" },
815 { .compatible = "qcom,msm-gladiator-v3" },
816 {},
817};
818
819static int parse_dt_node(struct platform_device *pdev,
820 struct msm_gladiator_data *msm_gld_data)
821{
822 int ret = 0;
823 struct resource *res;
824
825 res = platform_get_resource_byname(pdev,
826 IORESOURCE_MEM, "gladiator_base");
827 if (!res)
828 return -ENODEV;
829 if (!devm_request_mem_region(&pdev->dev, res->start,
830 resource_size(res),
831 "msm-gladiator-erp")) {
832
833 dev_err(&pdev->dev, "%s cannot reserve gladiator erp region\n",
834 __func__);
835 return -ENXIO;
836 }
837 msm_gld_data->gladiator_virt_base = devm_ioremap(&pdev->dev,
838 res->start, resource_size(res));
839 if (!msm_gld_data->gladiator_virt_base) {
840 dev_err(&pdev->dev, "%s cannot map gladiator register space\n",
841 __func__);
842 return -ENXIO;
843 }
844 msm_gld_data->erp_irq = platform_get_irq(pdev, 0);
845 if (!msm_gld_data->erp_irq)
846 return -ENODEV;
847
848 /* clear existing errors before enabling the interrupt */
849 clear_gladiator_error(msm_gld_data->gladiator_virt_base,
850 msm_gld_data->reg_offs);
851 ret = devm_request_irq(&pdev->dev, msm_gld_data->erp_irq,
852 msm_gladiator_isr, IRQF_TRIGGER_HIGH,
853 "gladiator-error", msm_gld_data);
854 if (ret)
855 dev_err(&pdev->dev, "Failed to register irq handler\n");
856
857 return ret;
858}
859
860static inline void gladiator_irq_init(void __iomem *gladiator_virt_base,
861 struct reg_off *offs)
862{
863 writel_relaxed(1, gladiator_virt_base + offs->gladiator_faulten);
864 writel_relaxed(1, gladiator_virt_base + offs->observer_0_faulten);
865}
866
867#define CCI_LEVEL 2
868static int gladiator_erp_pm_callback(struct notifier_block *nb,
869 unsigned long val, void *data)
870{
871 unsigned int level = (unsigned long) data;
872 struct msm_gladiator_data *msm_gld_data = container_of(nb,
873 struct msm_gladiator_data, pm_notifier_block);
874
875 if (level != CCI_LEVEL)
876 return NOTIFY_DONE;
877
878 switch (val) {
879 case CPU_CLUSTER_PM_EXIT:
880 gladiator_irq_init(msm_gld_data->gladiator_virt_base,
881 msm_gld_data->reg_offs);
882 break;
883 default:
884 return NOTIFY_DONE;
885 }
886
887 return NOTIFY_OK;
888}
889
890static void init_offsets_and_masks_v2(struct msm_gladiator_data *msm_gld_data)
891{
892 msm_gld_data->reg_offs->gladiator_id_coreid = 0x0;
893 msm_gld_data->reg_offs->gladiator_id_revisionid = 0x4;
894 msm_gld_data->reg_offs->gladiator_faulten = 0x1010;
895 msm_gld_data->reg_offs->gladiator_errvld = 0x1014;
896 msm_gld_data->reg_offs->gladiator_errclr = 0x1018;
897 msm_gld_data->reg_offs->gladiator_errlog0 = 0x101C;
898 msm_gld_data->reg_offs->gladiator_errlog1 = 0x1020;
899 msm_gld_data->reg_offs->gladiator_errlog2 = 0x1024;
900 msm_gld_data->reg_offs->gladiator_errlog3 = 0x1028;
901 msm_gld_data->reg_offs->gladiator_errlog4 = 0x102C;
902 msm_gld_data->reg_offs->gladiator_errlog5 = 0x1030;
903 msm_gld_data->reg_offs->gladiator_errlog6 = 0x1034;
904 msm_gld_data->reg_offs->gladiator_errlog7 = 0x1038;
905 msm_gld_data->reg_offs->gladiator_errlog8 = 0x103C;
906 msm_gld_data->reg_offs->observer_0_id_coreid = 0x8000;
907 msm_gld_data->reg_offs->observer_0_id_revisionid = 0x8004;
908 msm_gld_data->reg_offs->observer_0_faulten = 0x8008;
909 msm_gld_data->reg_offs->observer_0_errvld = 0x800C;
910 msm_gld_data->reg_offs->observer_0_errclr = 0x8010;
911 msm_gld_data->reg_offs->observer_0_errlog0 = 0x8014;
912 msm_gld_data->reg_offs->observer_0_errlog1 = 0x8018;
913 msm_gld_data->reg_offs->observer_0_errlog2 = 0x801C;
914 msm_gld_data->reg_offs->observer_0_errlog3 = 0x8020;
915 msm_gld_data->reg_offs->observer_0_errlog4 = 0x8024;
916 msm_gld_data->reg_offs->observer_0_errlog5 = 0x8028;
917 msm_gld_data->reg_offs->observer_0_errlog6 = 0x802C;
918 msm_gld_data->reg_offs->observer_0_errlog7 = 0x8030;
919 msm_gld_data->reg_offs->observer_0_errlog8 = 0x8034;
920 msm_gld_data->reg_offs->observer_0_stallen = 0x8038;
921
922 msm_gld_data->reg_masks_shifts->gld_trans_opcode_mask = 0xE;
923 msm_gld_data->reg_masks_shifts->gld_trans_opcode_shift = 1;
924 msm_gld_data->reg_masks_shifts->gld_error_type_mask = 0x700;
925 msm_gld_data->reg_masks_shifts->gld_error_type_shift = 8;
926 msm_gld_data->reg_masks_shifts->gld_len1_mask = 0xFFF;
927 msm_gld_data->reg_masks_shifts->gld_len1_shift = 16;
928 msm_gld_data->reg_masks_shifts->gld_trans_sourceid_mask = 0x7;
929 msm_gld_data->reg_masks_shifts->gld_trans_sourceid_shift = 0;
930 msm_gld_data->reg_masks_shifts->gld_trans_targetid_mask = 0x7;
931 msm_gld_data->reg_masks_shifts->gld_trans_targetid_shift = 0;
932 msm_gld_data->reg_masks_shifts->gld_errlog_error = 0x7;
933 msm_gld_data->reg_masks_shifts->gld_errlog5_error_type_mask =
934 0xFF000000;
935 msm_gld_data->reg_masks_shifts->gld_errlog5_error_type_shift = 24;
936 msm_gld_data->reg_masks_shifts->gld_ace_port_parity_mask = 0xc000;
937 msm_gld_data->reg_masks_shifts->gld_ace_port_parity_shift = 14;
938 msm_gld_data->reg_masks_shifts->gld_ace_port_disconnect_mask = 0xf0000;
939 msm_gld_data->reg_masks_shifts->gld_ace_port_disconnect_shift = 16;
940 msm_gld_data->reg_masks_shifts->gld_ace_port_directory_mask = 0xf00000;
941 msm_gld_data->reg_masks_shifts->gld_ace_port_directory_shift = 20;
942 msm_gld_data->reg_masks_shifts->gld_index_parity_mask = 0x1FFF;
943 msm_gld_data->reg_masks_shifts->gld_index_parity_shift = 0;
944 msm_gld_data->reg_masks_shifts->obs_trans_opcode_mask = 0x1E;
945 msm_gld_data->reg_masks_shifts->obs_trans_opcode_shift = 1;
946 msm_gld_data->reg_masks_shifts->obs_error_type_mask = 0x700;
947 msm_gld_data->reg_masks_shifts->obs_error_type_shift = 8;
948 msm_gld_data->reg_masks_shifts->obs_len1_mask = 0x7F0;
949 msm_gld_data->reg_masks_shifts->obs_len1_shift = 16;
950}
951
952static void init_offsets_and_masks_v3(struct msm_gladiator_data *msm_gld_data)
953{
954 msm_gld_data->reg_offs->gladiator_id_coreid = 0x0;
955 msm_gld_data->reg_offs->gladiator_id_revisionid = 0x4;
956 msm_gld_data->reg_offs->gladiator_faulten = 0x1010;
957 msm_gld_data->reg_offs->gladiator_errvld = 0x1014;
958 msm_gld_data->reg_offs->gladiator_errclr = 0x1018;
959 msm_gld_data->reg_offs->gladiator_errlog0 = 0x101C;
960 msm_gld_data->reg_offs->gladiator_errlog1 = 0x1020;
961 msm_gld_data->reg_offs->gladiator_errlog2 = 0x1024;
962 msm_gld_data->reg_offs->gladiator_errlog3 = 0x1028;
963 msm_gld_data->reg_offs->gladiator_errlog4 = 0x102C;
964 msm_gld_data->reg_offs->gladiator_errlog5 = 0x1030;
965 msm_gld_data->reg_offs->gladiator_errlog6 = 0x1034;
966 msm_gld_data->reg_offs->gladiator_errlog7 = 0x1038;
967 msm_gld_data->reg_offs->gladiator_errlog8 = 0x103C;
968 msm_gld_data->reg_offs->observer_0_id_coreid = INVALID_NUM;
969 msm_gld_data->reg_offs->observer_0_id_revisionid = INVALID_NUM;
970 msm_gld_data->reg_offs->observer_0_faulten = 0x2008;
971 msm_gld_data->reg_offs->observer_0_errvld = 0x2010;
972 msm_gld_data->reg_offs->observer_0_errclr = 0x2018;
973 msm_gld_data->reg_offs->observer_0_errlog0 = 0x2020;
974 msm_gld_data->reg_offs->observer_0_errlog1 = 0x2024;
975 msm_gld_data->reg_offs->observer_0_errlog2 = 0x2028;
976 msm_gld_data->reg_offs->observer_0_errlog3 = 0x202C;
977 msm_gld_data->reg_offs->observer_0_errlog4 = 0x2030;
978 msm_gld_data->reg_offs->observer_0_errlog5 = 0x2034;
979 msm_gld_data->reg_offs->observer_0_errlog6 = 0x2038;
980 msm_gld_data->reg_offs->observer_0_errlog7 = 0x203C;
981 msm_gld_data->reg_offs->observer_0_errlog8 = INVALID_NUM;
982 msm_gld_data->reg_offs->observer_0_stallen = INVALID_NUM;
983
984 msm_gld_data->reg_masks_shifts->gld_trans_opcode_mask = 0xE;
985 msm_gld_data->reg_masks_shifts->gld_trans_opcode_shift = 1;
986 msm_gld_data->reg_masks_shifts->gld_error_type_mask = 0x700;
987 msm_gld_data->reg_masks_shifts->gld_error_type_shift = 8;
988 msm_gld_data->reg_masks_shifts->gld_len1_mask = 0xFFF0000;
989 msm_gld_data->reg_masks_shifts->gld_len1_shift = 16;
990 msm_gld_data->reg_masks_shifts->gld_trans_sourceid_mask = 0x7;
991 msm_gld_data->reg_masks_shifts->gld_trans_sourceid_shift = 0;
992 msm_gld_data->reg_masks_shifts->gld_trans_targetid_mask = 0x7;
993 msm_gld_data->reg_masks_shifts->gld_trans_targetid_shift = 0;
994 msm_gld_data->reg_masks_shifts->gld_errlog_error = 0x7;
995 msm_gld_data->reg_masks_shifts->gld_errlog5_error_type_mask =
996 0xFF000000;
997 msm_gld_data->reg_masks_shifts->gld_errlog5_error_type_shift = 24;
998 msm_gld_data->reg_masks_shifts->gld_ace_port_parity_mask = 0xc000;
999 msm_gld_data->reg_masks_shifts->gld_ace_port_parity_shift = 14;
1000 msm_gld_data->reg_masks_shifts->gld_ace_port_disconnect_mask = 0xf0000;
1001 msm_gld_data->reg_masks_shifts->gld_ace_port_disconnect_shift = 16;
1002 msm_gld_data->reg_masks_shifts->gld_ace_port_directory_mask = 0xf00000;
1003 msm_gld_data->reg_masks_shifts->gld_ace_port_directory_shift = 20;
1004 msm_gld_data->reg_masks_shifts->gld_index_parity_mask = 0x1FFF;
1005 msm_gld_data->reg_masks_shifts->gld_index_parity_shift = 0;
1006 msm_gld_data->reg_masks_shifts->obs_trans_opcode_mask = 0x70;
1007 msm_gld_data->reg_masks_shifts->obs_trans_opcode_shift = 4;
1008 msm_gld_data->reg_masks_shifts->obs_error_type_mask = 0x700;
1009 msm_gld_data->reg_masks_shifts->obs_error_type_shift = 8;
1010 msm_gld_data->reg_masks_shifts->obs_len1_mask = 0x1FF;
1011 msm_gld_data->reg_masks_shifts->obs_len1_shift = 0;
1012}
1013
1014static int gladiator_erp_probe(struct platform_device *pdev)
1015{
1016 int ret = -1;
1017 struct msm_gladiator_data *msm_gld_data;
1018
1019 msm_gld_data = devm_kzalloc(&pdev->dev,
1020 sizeof(struct msm_gladiator_data), GFP_KERNEL);
1021 if (!msm_gld_data) {
1022 ret = -ENOMEM;
1023 goto bail;
1024 }
1025
1026 msm_gld_data->reg_offs = devm_kzalloc(&pdev->dev,
1027 sizeof(struct reg_off), GFP_KERNEL);
1028 msm_gld_data->reg_masks_shifts = devm_kzalloc(&pdev->dev,
1029 sizeof(struct reg_masks_shift), GFP_KERNEL);
1030
1031 if (!msm_gld_data->reg_offs || !msm_gld_data->reg_masks_shifts) {
1032 ret = -ENOMEM;
1033 goto bail;
1034 }
1035
1036 msm_gld_data->glad_v2 = of_device_is_compatible(pdev->dev.of_node,
1037 "qcom,msm-gladiator-v2");
1038 msm_gld_data->glad_v3 = of_device_is_compatible(pdev->dev.of_node,
1039 "qcom,msm-gladiator-v3");
1040
1041 if (msm_gld_data->glad_v2)
1042 init_offsets_and_masks_v2(msm_gld_data);
1043 else if (msm_gld_data->glad_v3)
1044 init_offsets_and_masks_v3(msm_gld_data);
1045
1046 if (msm_gld_data->glad_v2) {
1047 if (of_property_match_string(pdev->dev.of_node,
1048 "clock-names", "atb_clk") >= 0) {
1049 msm_gld_data->qdss_clk = devm_clk_get(&pdev->dev,
1050 "atb_clk");
1051 if (IS_ERR(msm_gld_data->qdss_clk)) {
1052 dev_err(&pdev->dev, "Failed to get QDSS ATB clock\n");
1053 goto bail;
1054 }
1055 } else {
1056 dev_err(&pdev->dev, "No matching string of QDSS ATB clock\n");
1057 goto bail;
1058 }
1059
1060 ret = clk_prepare_enable(msm_gld_data->qdss_clk);
1061 if (ret)
1062 goto err_atb_clk;
1063 }
1064
1065 ret = parse_dt_node(pdev, msm_gld_data);
1066 if (ret)
1067 goto bail;
1068 msm_gld_data->pm_notifier_block.notifier_call =
1069 gladiator_erp_pm_callback;
1070
1071 gladiator_irq_init(msm_gld_data->gladiator_virt_base,
1072 msm_gld_data->reg_offs);
1073 platform_set_drvdata(pdev, msm_gld_data);
1074 cpu_pm_register_notifier(&msm_gld_data->pm_notifier_block);
1075#ifdef CONFIG_PANIC_ON_GLADIATOR_ERROR
1076 enable_panic_on_error = 1;
1077#endif
1078 dev_info(&pdev->dev, "MSM Gladiator Error Reporting Initialized\n");
1079 return ret;
1080
1081err_atb_clk:
1082 clk_disable_unprepare(msm_gld_data->qdss_clk);
1083
1084bail:
1085 dev_err(&pdev->dev, "Probe failed bailing out\n");
1086 return ret;
1087}
1088
1089static int gladiator_erp_remove(struct platform_device *pdev)
1090{
1091 struct msm_gladiator_data *msm_gld_data = platform_get_drvdata(pdev);
1092
1093 platform_set_drvdata(pdev, NULL);
1094 cpu_pm_unregister_notifier(&msm_gld_data->pm_notifier_block);
1095 clk_disable_unprepare(msm_gld_data->qdss_clk);
1096 return 0;
1097}
1098
1099static struct platform_driver gladiator_erp_driver = {
1100 .probe = gladiator_erp_probe,
1101 .remove = gladiator_erp_remove,
1102 .driver = {
1103 .name = MODULE_NAME,
1104 .owner = THIS_MODULE,
1105 .of_match_table = gladiator_erp_match_table,
1106 },
1107};
1108
1109static int __init init_gladiator_erp(void)
1110{
1111 int ret;
1112
1113 ret = scm_is_secure_device();
1114 if (ret == 0) {
1115 pr_info("Gladiator Error Reporting not available\n");
1116 return -ENODEV;
1117 }
1118
1119 return platform_driver_register(&gladiator_erp_driver);
1120}
1121module_init(init_gladiator_erp);
1122
1123static void __exit exit_gladiator_erp(void)
1124{
1125 return platform_driver_unregister(&gladiator_erp_driver);
1126}
1127module_exit(exit_gladiator_erp);
1128
1129MODULE_DESCRIPTION("Gladiator Error Reporting");
1130MODULE_LICENSE("GPL v2");