[RAMEN9610-20413][9610] wlbt: SCSC Driver version 10.6.1.0
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / drivers / misc / samsung / scsc / fw_panic_record.c
1 /****************************************************************************
2 *
3 * Copyright (c) 2014 - 2016 Samsung Electronics Co., Ltd. All rights reserved
4 *
5 ****************************************************************************/
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <scsc/scsc_logring.h>
9 #include "panic_record_r4_defs.h"
10
11 #define PANIC_RECORD_CKSUM_SEED 0xa5a5a5a5
12 /*
13 * version 2 r4 panic record defs
14 */
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
18
19 /*
20 * version 1 mr4 panic record defs
21 */
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
26
27 #define R4_PANIC_RECORD_V2_SYMPATHETIC_PANIC_FLAG_INDEX 51
28 #define M4_PANIC_RECORD_SYMPATHETIC_PANIC_FLAG_INDEX 39
29
30 /**
31 * Compute 32bit xor of specified seed value and data.
32 *
33 * @param seed Initial seed value.
34 * @param data Array of uint32s to be xored
35 * @param len Number of uint32s to be xored
36 *
37 * @return Computed 32bit xor of specified seed value and data.
38 */
39 static u32 xor32(uint32_t seed, const u32 data[], size_t len)
40 {
41 const u32 *i;
42 u32 xor = seed;
43
44 for (i = data; i != data + len; ++i)
45 xor ^= *i;
46 return xor;
47 }
48
49 static void panic_record_dump(u32 *panic_record, u32 panic_record_length, bool r4)
50 {
51 int i;
52
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]);
58 }
59
60 static bool fw_parse_r4_panic_record_v2(u32 *r4_panic_record, u32 *r4_panic_record_length)
61 {
62 u32 panic_record_cksum;
63 u32 calculated_cksum;
64 u32 panic_record_length = *(r4_panic_record + R4_PANIC_RECORD_LENGTH_INDEX_V2) / 4;
65
66 SCSC_TAG_INFO(FW_PANIC, "panic_record_length: %d\n", panic_record_length);
67
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",
73 calculated_cksum);
74 panic_record_dump(r4_panic_record, panic_record_length, true);
75 *r4_panic_record_length = panic_record_length;
76 return true;
77 } else {
78 SCSC_TAG_ERR(FW_PANIC, "BAD panic_record_cksum: 0x%x calculated_cksum: 0x%x\n",
79 panic_record_cksum, calculated_cksum);
80 }
81 } else {
82 SCSC_TAG_ERR(FW_PANIC, "BAD panic_record_length: %d\n",
83 panic_record_length);
84 }
85 return false;
86 }
87
88 static bool fw_parse_m4_panic_record_v1(u32 *m4_panic_record, u32 *m4_panic_record_length)
89 {
90 u32 panic_record_cksum;
91 u32 calculated_cksum;
92 u32 panic_record_length = *(m4_panic_record + M4_PANIC_RECORD_LENGTH_INDEX) / 4;
93
94 SCSC_TAG_INFO(FW_PANIC, "panic_record_length: %d\n", panic_record_length);
95
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",
101 calculated_cksum);
102 panic_record_dump(m4_panic_record, panic_record_length, false);
103 *m4_panic_record_length = panic_record_length;
104 return true;
105 } else {
106 SCSC_TAG_ERR(FW_PANIC, "BAD panic_record_cksum: 0x%x calculated_cksum: 0x%x\n",
107 panic_record_cksum, calculated_cksum);
108 }
109 } else {
110 SCSC_TAG_ERR(FW_PANIC, "BAD panic_record_length: %d\n",
111 panic_record_length);
112 }
113 return false;
114 }
115
116 bool fw_parse_r4_panic_record(u32 *r4_panic_record, u32 *r4_panic_record_length)
117 {
118 u32 panic_record_version = *(r4_panic_record + PANIC_RECORD_R4_VERSION_INDEX);
119
120 SCSC_TAG_INFO(FW_PANIC, "panic_record_version: %d\n", panic_record_version);
121
122 switch (panic_record_version) {
123 default:
124 SCSC_TAG_ERR(FW_PANIC, "BAD panic_record_version: %d\n",
125 panic_record_version);
126 break;
127 case R4_PANIC_RECORD_VERSION_2:
128 return fw_parse_r4_panic_record_v2(r4_panic_record, r4_panic_record_length);
129 }
130 return false;
131 }
132
133 bool fw_parse_m4_panic_record(u32 *m4_panic_record, u32 *m4_panic_record_length)
134 {
135 u32 panic_record_version = *(m4_panic_record + M4_PANIC_RECORD_VERSION_INDEX);
136
137 SCSC_TAG_INFO(FW_PANIC, "panic_record_version: %d\n", panic_record_version);
138 switch (panic_record_version) {
139 default:
140 SCSC_TAG_ERR(FW_PANIC, "BAD panic_record_version: %d\n",
141 panic_record_version);
142 break;
143 case M4_PANIC_RECORD_VERSION_1:
144 return fw_parse_m4_panic_record_v1(m4_panic_record, m4_panic_record_length);
145 }
146 return false;
147 }
148
149 bool fw_parse_get_r4_sympathetic_panic_flag(u32 *r4_panic_record)
150 {
151 bool sympathetic_panic_flag = *(r4_panic_record + R4_PANIC_RECORD_V2_SYMPATHETIC_PANIC_FLAG_INDEX);
152
153 return sympathetic_panic_flag;
154 }
155
156 bool fw_parse_get_m4_sympathetic_panic_flag(u32 *m4_panic_record)
157 {
158 bool sympathetic_panic_flag = *(m4_panic_record + M4_PANIC_RECORD_SYMPATHETIC_PANIC_FLAG_INDEX);
159
160 return sympathetic_panic_flag;
161 }
162
163 int panic_record_dump_buffer(char *processor, u32 *panic_record,
164 u32 panic_record_length, char *buffer, size_t blen)
165 {
166 int i, used;
167
168 if (!processor)
169 processor = "WLBT";
170
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]);
176
177 return used;
178 }