1 /****************************************************************************
3 * Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved
5 ****************************************************************************/
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <scsc/scsc_logring.h>
9 #include "panic_record_r4_defs.h"
11 #define PANIC_RECORD_CKSUM_SEED 0xa5a5a5a5
13 * version 2 r4 panic record defs
15 #define R4_PANIC_RECORD_VERSION_2 2
16 #define R4_PANIC_RECORD_LENGTH_INDEX_V2 1
17 #define R4_PANIC_RECORD_MAX_LENGTH_V2 256
20 * version 1 mr4 panic record defs
22 #define M4_PANIC_RECORD_VERSION_1 1
23 #define M4_PANIC_RECORD_VERSION_INDEX 0
24 #define M4_PANIC_RECORD_LENGTH_INDEX 1
25 #define M4_PANIC_RECORD_MAX_LENGTH 256
27 #define R4_PANIC_RECORD_V2_SYMPATHETIC_PANIC_FLAG_INDEX 51
28 #define M4_PANIC_RECORD_SYMPATHETIC_PANIC_FLAG_INDEX 39
31 * Compute 32bit xor of specified seed value and data.
33 * @param seed Initial seed value.
34 * @param data Array of uint32s to be xored
35 * @param len Number of uint32s to be xored
37 * @return Computed 32bit xor of specified seed value and data.
39 static u32
xor32(uint32_t seed
, const u32 data
[], size_t len
)
44 for (i
= data
; i
!= data
+ len
; ++i
)
49 static void panic_record_dump(u32
*panic_record
, u32 panic_record_length
, bool r4
)
53 SCSC_TAG_INFO(FW_PANIC
, "%s panic record dump(length=%d):\n",
54 r4
? "R4" : "M4", panic_record_length
);
55 for (i
= 0; i
< panic_record_length
; i
++)
56 SCSC_TAG_INFO(FW_PANIC
, "%s_panic_record[%d] = %08x\n",
57 r4
? "r4" : "m4", i
, panic_record
[i
]);
60 static bool fw_parse_r4_panic_record_v2(u32
*r4_panic_record
, u32
*r4_panic_record_length
)
62 u32 panic_record_cksum
;
64 u32 panic_record_length
= *(r4_panic_record
+ R4_PANIC_RECORD_LENGTH_INDEX_V2
) / 4;
66 SCSC_TAG_INFO(FW_PANIC
, "panic_record_length: %d\n", panic_record_length
);
68 if (panic_record_length
< R4_PANIC_RECORD_MAX_LENGTH_V2
) {
69 panic_record_cksum
= *(r4_panic_record
+ panic_record_length
- 1);
70 calculated_cksum
= xor32(PANIC_RECORD_CKSUM_SEED
, r4_panic_record
, panic_record_length
- 1);
71 if (calculated_cksum
== panic_record_cksum
) {
72 SCSC_TAG_INFO(FW_PANIC
, "panic_record_cksum OK: %08x\n",
74 panic_record_dump(r4_panic_record
, panic_record_length
, true);
75 *r4_panic_record_length
= panic_record_length
;
78 SCSC_TAG_ERR(FW_PANIC
, "BAD panic_record_cksum: 0x%x calculated_cksum: 0x%x\n",
79 panic_record_cksum
, calculated_cksum
);
82 SCSC_TAG_ERR(FW_PANIC
, "BAD panic_record_length: %d\n",
88 static bool fw_parse_m4_panic_record_v1(u32
*m4_panic_record
, u32
*m4_panic_record_length
)
90 u32 panic_record_cksum
;
92 u32 panic_record_length
= *(m4_panic_record
+ M4_PANIC_RECORD_LENGTH_INDEX
) / 4;
94 SCSC_TAG_INFO(FW_PANIC
, "panic_record_length: %d\n", panic_record_length
);
96 if (panic_record_length
< M4_PANIC_RECORD_MAX_LENGTH
) {
97 panic_record_cksum
= *(m4_panic_record
+ panic_record_length
- 1);
98 calculated_cksum
= xor32(PANIC_RECORD_CKSUM_SEED
, m4_panic_record
, panic_record_length
- 1);
99 if (calculated_cksum
== panic_record_cksum
) {
100 SCSC_TAG_INFO(FW_PANIC
, "panic_record_cksum OK: %08x\n",
102 panic_record_dump(m4_panic_record
, panic_record_length
, false);
103 *m4_panic_record_length
= panic_record_length
;
106 SCSC_TAG_ERR(FW_PANIC
, "BAD panic_record_cksum: 0x%x calculated_cksum: 0x%x\n",
107 panic_record_cksum
, calculated_cksum
);
110 SCSC_TAG_ERR(FW_PANIC
, "BAD panic_record_length: %d\n",
111 panic_record_length
);
116 bool fw_parse_r4_panic_record(u32
*r4_panic_record
, u32
*r4_panic_record_length
)
118 u32 panic_record_version
= *(r4_panic_record
+ PANIC_RECORD_R4_VERSION_INDEX
);
120 SCSC_TAG_INFO(FW_PANIC
, "panic_record_version: %d\n", panic_record_version
);
122 switch (panic_record_version
) {
124 SCSC_TAG_ERR(FW_PANIC
, "BAD panic_record_version: %d\n",
125 panic_record_version
);
127 case R4_PANIC_RECORD_VERSION_2
:
128 return fw_parse_r4_panic_record_v2(r4_panic_record
, r4_panic_record_length
);
133 bool fw_parse_m4_panic_record(u32
*m4_panic_record
, u32
*m4_panic_record_length
)
135 u32 panic_record_version
= *(m4_panic_record
+ M4_PANIC_RECORD_VERSION_INDEX
);
137 SCSC_TAG_INFO(FW_PANIC
, "panic_record_version: %d\n", panic_record_version
);
138 switch (panic_record_version
) {
140 SCSC_TAG_ERR(FW_PANIC
, "BAD panic_record_version: %d\n",
141 panic_record_version
);
143 case M4_PANIC_RECORD_VERSION_1
:
144 return fw_parse_m4_panic_record_v1(m4_panic_record
, m4_panic_record_length
);
149 bool fw_parse_get_r4_sympathetic_panic_flag(u32
*r4_panic_record
)
151 bool sympathetic_panic_flag
= *(r4_panic_record
+ R4_PANIC_RECORD_V2_SYMPATHETIC_PANIC_FLAG_INDEX
);
153 return sympathetic_panic_flag
;
156 bool fw_parse_get_m4_sympathetic_panic_flag(u32
*m4_panic_record
)
158 bool sympathetic_panic_flag
= *(m4_panic_record
+ M4_PANIC_RECORD_SYMPATHETIC_PANIC_FLAG_INDEX
);
160 return sympathetic_panic_flag
;
163 int panic_record_dump_buffer(char *processor
, u32
*panic_record
,
164 u32 panic_record_length
, char *buffer
, size_t blen
)
171 used
= snprintf(buffer
, blen
, "%s panic record dump(length=%d):\n",
172 processor
, panic_record_length
);
173 for (i
= 0; i
< panic_record_length
&& used
< blen
; i
++)
174 used
+= snprintf(buffer
+ used
, blen
- used
, "%s_panic_record[%d] = %08x\n",
175 processor
, i
, panic_record
[i
]);