import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / aee / common / reboot-reason.c
1 #include <linux/kobject.h>
2 #include <linux/string.h>
3 #include <linux/sysfs.h>
4 #include <linux/init.h>
5 #include <linux/sched.h>
6 #include <linux/module.h>
7 #include <linux/proc_fs.h>
8 #include <linux/seq_file.h>
9 #include <linux/delay.h>
10 #include <linux/mm.h>
11 #include <linux/stacktrace.h>
12 #include <linux/sched.h>
13 #include <asm/stacktrace.h>
14 #include <asm/memory.h>
15 #include <asm/traps.h>
16 #include <asm/elf.h>
17 #include <mach/wd_api.h>
18 #include <mach/smp.h>
19 #include <linux/aee.h>
20 #include <linux/mrdump.h>
21 #include "aee-common.h"
22
23 #define RR_PROC_NAME "reboot-reason"
24 extern int aee_rr_last_fiq_step(void);
25
26 static struct proc_dir_entry *aee_rr_file;
27
28 #define WDT_NORMAL_BOOT 0
29 #define WDT_HW_REBOOT 1
30 #define WDT_SW_REBOOT 2
31
32 typedef enum {
33 BR_POWER_KEY = 0,
34 BR_USB,
35 BR_RTC,
36 BR_WDT,
37 BR_WDT_BY_PASS_PWK,
38 BR_TOOL_BY_PASS_PWK,
39 BR_2SEC_REBOOT,
40 BR_UNKNOWN,
41 BR_KE_REBOOT
42 } boot_reason_t;
43
44 char boot_reason[][16] =
45 { "keypad", "usb_chg", "rtc", "wdt", "reboot", "tool reboot", "smpl", "others", "kpanic" };
46
47 extern int aee_rr_reboot_reason_show(struct seq_file *m, void *v);
48 int __weak aee_rr_reboot_reason_show(struct seq_file *m, void *v)
49 {
50 seq_printf(m, "mtk_ram_console not enabled.");
51 return 0;
52 }
53
54 static int aee_rr_reboot_reason_proc_open(struct inode *inode, struct file *file)
55 {
56 return single_open(file, aee_rr_reboot_reason_show, NULL);
57 }
58
59 static const struct file_operations aee_rr_reboot_reason_proc_fops = {
60 .open = aee_rr_reboot_reason_proc_open,
61 .read = seq_read,
62 .llseek = seq_lseek,
63 .release = single_release,
64 };
65
66
67 void aee_rr_proc_init(struct proc_dir_entry *aed_proc_dir)
68 {
69 aee_rr_file = proc_create(RR_PROC_NAME,
70 0444, aed_proc_dir, &aee_rr_reboot_reason_proc_fops);
71 if (aee_rr_file == NULL) {
72 LOGE("%s: Can't create rr proc entry\n", __func__);
73 }
74 }
75 EXPORT_SYMBOL(aee_rr_proc_init);
76
77 void aee_rr_proc_done(struct proc_dir_entry *aed_proc_dir)
78 {
79 remove_proc_entry(RR_PROC_NAME, aed_proc_dir);
80 }
81 EXPORT_SYMBOL(aee_rr_proc_done);
82
83 /* define /sys/bootinfo/powerup_reason */
84 static ssize_t powerup_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
85 {
86 int g_boot_reason = 0;
87 char *br_ptr;
88 if ((br_ptr = strstr(saved_command_line, "boot_reason=")) != 0) {
89 /* get boot reason */
90 g_boot_reason = br_ptr[12] - '0';
91 LOGE("g_boot_reason=%d\n", g_boot_reason);
92 #ifdef CONFIG_MTK_RAM_CONSOLE
93 if (aee_rr_last_fiq_step() != 0)
94 g_boot_reason = BR_KE_REBOOT;
95 #endif
96 return sprintf(buf, "%s\n", boot_reason[g_boot_reason]);
97 } else
98 return 0;
99
100 }
101
102 static struct kobj_attribute powerup_reason_attr = __ATTR_RO(powerup_reason);
103
104 struct kobject *bootinfo_kobj;
105 EXPORT_SYMBOL(bootinfo_kobj);
106
107 static struct attribute *bootinfo_attrs[] = {
108 &powerup_reason_attr.attr,
109 NULL
110 };
111
112 static struct attribute_group bootinfo_attr_group = {
113 .attrs = bootinfo_attrs,
114 };
115
116 int ksysfs_bootinfo_init(void)
117 {
118 int error;
119
120 bootinfo_kobj = kobject_create_and_add("bootinfo", NULL);
121 if (!bootinfo_kobj) {
122 return -ENOMEM;
123 }
124
125 error = sysfs_create_group(bootinfo_kobj, &bootinfo_attr_group);
126 if (error)
127 kobject_put(bootinfo_kobj);
128
129 return error;
130 }
131
132 void ksysfs_bootinfo_exit(void)
133 {
134 kobject_put(bootinfo_kobj);
135 }
136
137 /* end sysfs bootinfo */
138
139 static inline unsigned int get_linear_memory_size(void)
140 {
141 return (unsigned long)high_memory - PAGE_OFFSET;
142 }
143
144 static char nested_panic_buf[1024];
145 int aee_nested_printf(const char *fmt, ...)
146 {
147 va_list args;
148 static int total_len;
149 va_start(args, fmt);
150 total_len += vsnprintf(nested_panic_buf, sizeof(nested_panic_buf), fmt, args);
151 va_end(args);
152
153 aee_sram_fiq_log(nested_panic_buf);
154
155 return total_len;
156 }
157
158 static void print_error_msg(int len)
159 {
160 static char error_msg[][50] = { "Bottom unaligned", "Bottom out of kernel addr",
161 "Top out of kernel addr", "Buf len not enough"
162 };
163 int tmp = (-len) - 1;
164 aee_sram_fiq_log(error_msg[tmp]);
165 }
166
167 /*save stack as binary into buf,
168 *return value
169
170 -1: bottom unaligned
171 -2: bottom out of kernel addr space
172 -3 top out of kernel addr addr
173 -4: buff len not enough
174 >0: used length of the buf
175 */
176 int aee_dump_stack_top_binary(char *buf, int buf_len, unsigned long bottom, unsigned long top)
177 {
178 /*should check stack address in kernel range */
179 if (bottom & 3) {
180 return -1;
181 }
182 if (!((bottom >= (PAGE_OFFSET + THREAD_SIZE)) &&
183 (bottom <= (PAGE_OFFSET + get_linear_memory_size())))) {
184 return -2;
185 }
186
187 if (!((top >= (PAGE_OFFSET + THREAD_SIZE)) &&
188 (top <= (PAGE_OFFSET + get_linear_memory_size())))) {
189 return -3;
190 }
191
192 if (buf_len < top - bottom) {
193 return -4;
194 }
195
196 memcpy((void *)buf, (void *)bottom, top - bottom);
197
198 return top - bottom;
199 }
200
201 /* extern void mt_fiq_printf(const char *fmt, ...); */
202 void *aee_excp_regs;
203 static atomic_t nested_panic_time = ATOMIC_INIT(0);
204
205 #ifdef __aarch64__
206 #define FORMAT_LONG "%016lx "
207 #else
208 #define FORMAT_LONG "%08lx "
209 #endif
210 inline void aee_print_regs(struct pt_regs *regs)
211 {
212 int i;
213 aee_nested_printf("[pt_regs]");
214 for (i = 0; i < ELF_NGREG; i++) {
215 aee_nested_printf(FORMAT_LONG, ((unsigned long *)regs)[i]);
216 }
217 aee_nested_printf("\n");
218 }
219
220 #define AEE_MAX_EXCP_FRAME 32
221 inline void aee_print_bt(struct pt_regs *regs)
222 {
223 int i;
224 unsigned long high, bottom, fp;
225 struct stackframe cur_frame;
226 struct pt_regs *excp_regs;
227 bottom = regs->reg_sp;
228 if (!virt_addr_valid(bottom)) {
229 aee_nested_printf("invalid sp[%lx]\n", regs);
230 return;
231 }
232 high = ALIGN(bottom, THREAD_SIZE);
233 cur_frame.fp = regs->reg_fp;
234 cur_frame.pc = regs->reg_pc;
235 cur_frame.sp = regs->reg_sp;
236 for (i = 0; i < AEE_MAX_EXCP_FRAME; i++) {
237 fp = cur_frame.fp;
238 if ((fp < bottom) || (fp >= (high + THREAD_SIZE))) {
239 if (fp != 0)
240 aee_nested_printf("fp(%lx)", fp);
241 break;
242 }
243 unwind_frame(&cur_frame);
244 if (!
245 ((cur_frame.pc >= (PAGE_OFFSET + THREAD_SIZE))
246 && virt_addr_valid(cur_frame.pc)))
247 break;
248 if (in_exception_text(cur_frame.pc)) {
249 #ifdef __aarch64__
250 /* work around for unknown reason do_mem_abort stack abnormal */
251 excp_regs = (void *)(cur_frame.fp + 0x10 + 0xa0);
252 unwind_frame(&cur_frame); /* skip do_mem_abort & el1_da */
253 #else
254 excp_regs = (void *)(cur_frame.fp + 4);
255 #endif
256 cur_frame.pc = excp_regs->reg_pc;
257 }
258 aee_nested_printf("%p, ", (void *)cur_frame.pc);
259
260 }
261 aee_nested_printf("\n");
262 return;
263 }
264
265 inline int aee_nested_save_stack(struct pt_regs *regs)
266 {
267 int len = 0;
268 if (!virt_addr_valid(regs->reg_sp))
269 return -1;
270 aee_nested_printf("[%lx %lx]\n", regs->reg_sp, regs->reg_sp + 256);
271
272 len = aee_dump_stack_top_binary(nested_panic_buf, sizeof(nested_panic_buf),
273 regs->reg_sp, regs->reg_sp + 256);
274 if (len > 0)
275 aee_sram_fiq_save_bin(nested_panic_buf, len);
276 else
277 print_error_msg(len);
278 return len;
279 }
280
281 int aee_in_nested_panic(void)
282 {
283 return (atomic_read(&nested_panic_time) &&
284 ((aee_rr_curr_fiq_step() & ~(AEE_FIQ_STEP_KE_NESTED_PANIC - 1)) ==
285 AEE_FIQ_STEP_KE_NESTED_PANIC));
286 }
287
288 static inline void aee_rec_step_nested_panic(int step)
289 {
290 if (step < 64)
291 aee_rr_rec_fiq_step(AEE_FIQ_STEP_KE_NESTED_PANIC + step);
292 }
293
294 asmlinkage void aee_stop_nested_panic(struct pt_regs *regs)
295 {
296 struct thread_info *thread = current_thread_info();
297 int len = 0;
298 int timeout = 1000000;
299 int res = 0, cpu = 0;
300 struct wd_api *wd_api = NULL;
301 struct pt_regs *excp_regs = NULL;
302 int prev_fiq_step = aee_rr_curr_fiq_step();
303 /* everytime enter nested_panic flow, add 8 */
304 static int step_base = -8;
305 step_base = step_base < 48 ? step_base + 8 : 56;
306
307 aee_rec_step_nested_panic(step_base);
308 local_irq_disable();
309 aee_rec_step_nested_panic(step_base + 1);
310 cpu = get_HW_cpuid();
311 aee_rec_step_nested_panic(step_base + 2);
312 /*nested panic may happens more than once on many/single cpus */
313 if (atomic_read(&nested_panic_time) < 3)
314 aee_nested_printf("\nCPU%dpanic%d@%d\n", cpu, nested_panic_time, prev_fiq_step);
315 atomic_inc(&nested_panic_time);
316
317 switch (atomic_read(&nested_panic_time)) {
318 case 2:
319 aee_print_regs(regs);
320 aee_nested_printf("backtrace:");
321 aee_print_bt(regs);
322 break;
323
324 /* must guarantee Only one cpu can run here */
325 /* first check if thread valid */
326 case 1:
327 if (virt_addr_valid(thread) && virt_addr_valid(thread->regs_on_excp)) {
328 excp_regs = thread->regs_on_excp;
329 } else {
330 /* if thread invalid, which means wrong sp or thread_info corrupted,
331 check global aee_excp_regs instead */
332 aee_nested_printf("invalid thread [%lx], excp_regs [%lx]\n", thread,
333 aee_excp_regs);
334 excp_regs = aee_excp_regs;
335 }
336 aee_nested_printf("Nested panic\n");
337 if (excp_regs) {
338 aee_nested_printf("Previous\n");
339 aee_print_regs(excp_regs);
340 }
341 aee_nested_printf("Current\n");
342 aee_print_regs(regs);
343
344 /*should not print stack info. this may overwhelms ram console used by fiq */
345 if (0 != in_fiq_handler()) {
346 aee_nested_printf("in fiq hander\n");
347 } else {
348 /*Dump first panic stack */
349 aee_nested_printf("Previous\n");
350 if (excp_regs) {
351 len = aee_nested_save_stack(excp_regs);
352 aee_nested_printf("\nbacktrace:");
353 aee_print_bt(excp_regs);
354 }
355
356 /*Dump second panic stack */
357 aee_nested_printf("Current\n");
358 if (virt_addr_valid(regs)) {
359 len = aee_nested_save_stack(regs);
360 aee_nested_printf("\nbacktrace:");
361 aee_print_bt(regs);
362 }
363 }
364 aee_rec_step_nested_panic(step_base + 5);
365 ipanic_recursive_ke(regs, excp_regs, cpu);
366
367 aee_rec_step_nested_panic(step_base + 6);
368 /* we donot want a FIQ after this, so disable hwt */
369 res = get_wd_api(&wd_api);
370 if (res) {
371 aee_nested_printf("get_wd_api error\n");
372 } else {
373 wd_api->wd_aee_confirm_hwreboot();
374 }
375 aee_rec_step_nested_panic(step_base + 7);
376 break;
377 default:
378 break;
379 }
380
381 /* waiting for the WDT timeout */
382 while (1) {
383 /* output to UART directly to avoid printk nested panic */
384 /* mt_fiq_printf("%s hang here%d\t", __func__, i++); */
385 while (timeout--) {
386 udelay(1);
387 }
388 timeout = 1000000;
389 }
390 }