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>
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>
17 #include <mach/wd_api.h>
19 #include <linux/aee.h>
20 #include <linux/mrdump.h>
21 #include "aee-common.h"
23 #define RR_PROC_NAME "reboot-reason"
24 extern int aee_rr_last_fiq_step(void);
26 static struct proc_dir_entry
*aee_rr_file
;
28 #define WDT_NORMAL_BOOT 0
29 #define WDT_HW_REBOOT 1
30 #define WDT_SW_REBOOT 2
44 char boot_reason
[][16] =
45 { "keypad", "usb_chg", "rtc", "wdt", "reboot", "tool reboot", "smpl", "others", "kpanic" };
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
)
50 seq_printf(m
, "mtk_ram_console not enabled.");
54 static int aee_rr_reboot_reason_proc_open(struct inode
*inode
, struct file
*file
)
56 return single_open(file
, aee_rr_reboot_reason_show
, NULL
);
59 static const struct file_operations aee_rr_reboot_reason_proc_fops
= {
60 .open
= aee_rr_reboot_reason_proc_open
,
63 .release
= single_release
,
67 void aee_rr_proc_init(struct proc_dir_entry
*aed_proc_dir
)
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__
);
75 EXPORT_SYMBOL(aee_rr_proc_init
);
77 void aee_rr_proc_done(struct proc_dir_entry
*aed_proc_dir
)
79 remove_proc_entry(RR_PROC_NAME
, aed_proc_dir
);
81 EXPORT_SYMBOL(aee_rr_proc_done
);
83 /* define /sys/bootinfo/powerup_reason */
84 static ssize_t
powerup_reason_show(struct kobject
*kobj
, struct kobj_attribute
*attr
, char *buf
)
86 int g_boot_reason
= 0;
88 if ((br_ptr
= strstr(saved_command_line
, "boot_reason=")) != 0) {
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
;
96 return sprintf(buf
, "%s\n", boot_reason
[g_boot_reason
]);
102 static struct kobj_attribute powerup_reason_attr
= __ATTR_RO(powerup_reason
);
104 struct kobject
*bootinfo_kobj
;
105 EXPORT_SYMBOL(bootinfo_kobj
);
107 static struct attribute
*bootinfo_attrs
[] = {
108 &powerup_reason_attr
.attr
,
112 static struct attribute_group bootinfo_attr_group
= {
113 .attrs
= bootinfo_attrs
,
116 int ksysfs_bootinfo_init(void)
120 bootinfo_kobj
= kobject_create_and_add("bootinfo", NULL
);
121 if (!bootinfo_kobj
) {
125 error
= sysfs_create_group(bootinfo_kobj
, &bootinfo_attr_group
);
127 kobject_put(bootinfo_kobj
);
132 void ksysfs_bootinfo_exit(void)
134 kobject_put(bootinfo_kobj
);
137 /* end sysfs bootinfo */
139 static inline unsigned int get_linear_memory_size(void)
141 return (unsigned long)high_memory
- PAGE_OFFSET
;
144 static char nested_panic_buf
[1024];
145 int aee_nested_printf(const char *fmt
, ...)
148 static int total_len
;
150 total_len
+= vsnprintf(nested_panic_buf
, sizeof(nested_panic_buf
), fmt
, args
);
153 aee_sram_fiq_log(nested_panic_buf
);
158 static void print_error_msg(int len
)
160 static char error_msg
[][50] = { "Bottom unaligned", "Bottom out of kernel addr",
161 "Top out of kernel addr", "Buf len not enough"
163 int tmp
= (-len
) - 1;
164 aee_sram_fiq_log(error_msg
[tmp
]);
167 /*save stack as binary into buf,
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
176 int aee_dump_stack_top_binary(char *buf
, int buf_len
, unsigned long bottom
, unsigned long top
)
178 /*should check stack address in kernel range */
182 if (!((bottom
>= (PAGE_OFFSET
+ THREAD_SIZE
)) &&
183 (bottom
<= (PAGE_OFFSET
+ get_linear_memory_size())))) {
187 if (!((top
>= (PAGE_OFFSET
+ THREAD_SIZE
)) &&
188 (top
<= (PAGE_OFFSET
+ get_linear_memory_size())))) {
192 if (buf_len
< top
- bottom
) {
196 memcpy((void *)buf
, (void *)bottom
, top
- bottom
);
201 /* extern void mt_fiq_printf(const char *fmt, ...); */
203 static atomic_t nested_panic_time
= ATOMIC_INIT(0);
206 #define FORMAT_LONG "%016lx "
208 #define FORMAT_LONG "%08lx "
210 inline void aee_print_regs(struct pt_regs
*regs
)
213 aee_nested_printf("[pt_regs]");
214 for (i
= 0; i
< ELF_NGREG
; i
++) {
215 aee_nested_printf(FORMAT_LONG
, ((unsigned long *)regs
)[i
]);
217 aee_nested_printf("\n");
220 #define AEE_MAX_EXCP_FRAME 32
221 inline void aee_print_bt(struct pt_regs
*regs
)
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
);
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
++) {
238 if ((fp
< bottom
) || (fp
>= (high
+ THREAD_SIZE
))) {
240 aee_nested_printf("fp(%lx)", fp
);
243 unwind_frame(&cur_frame
);
245 ((cur_frame
.pc
>= (PAGE_OFFSET
+ THREAD_SIZE
))
246 && virt_addr_valid(cur_frame
.pc
)))
248 if (in_exception_text(cur_frame
.pc
)) {
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 */
254 excp_regs
= (void *)(cur_frame
.fp
+ 4);
256 cur_frame
.pc
= excp_regs
->reg_pc
;
258 aee_nested_printf("%p, ", (void *)cur_frame
.pc
);
261 aee_nested_printf("\n");
265 inline int aee_nested_save_stack(struct pt_regs
*regs
)
268 if (!virt_addr_valid(regs
->reg_sp
))
270 aee_nested_printf("[%lx %lx]\n", regs
->reg_sp
, regs
->reg_sp
+ 256);
272 len
= aee_dump_stack_top_binary(nested_panic_buf
, sizeof(nested_panic_buf
),
273 regs
->reg_sp
, regs
->reg_sp
+ 256);
275 aee_sram_fiq_save_bin(nested_panic_buf
, len
);
277 print_error_msg(len
);
281 int aee_in_nested_panic(void)
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
));
288 static inline void aee_rec_step_nested_panic(int step
)
291 aee_rr_rec_fiq_step(AEE_FIQ_STEP_KE_NESTED_PANIC
+ step
);
294 asmlinkage
void aee_stop_nested_panic(struct pt_regs
*regs
)
296 struct thread_info
*thread
= current_thread_info();
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;
307 aee_rec_step_nested_panic(step_base
);
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
);
317 switch (atomic_read(&nested_panic_time
)) {
319 aee_print_regs(regs
);
320 aee_nested_printf("backtrace:");
324 /* must guarantee Only one cpu can run here */
325 /* first check if thread valid */
327 if (virt_addr_valid(thread
) && virt_addr_valid(thread
->regs_on_excp
)) {
328 excp_regs
= thread
->regs_on_excp
;
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
,
334 excp_regs
= aee_excp_regs
;
336 aee_nested_printf("Nested panic\n");
338 aee_nested_printf("Previous\n");
339 aee_print_regs(excp_regs
);
341 aee_nested_printf("Current\n");
342 aee_print_regs(regs
);
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");
348 /*Dump first panic stack */
349 aee_nested_printf("Previous\n");
351 len
= aee_nested_save_stack(excp_regs
);
352 aee_nested_printf("\nbacktrace:");
353 aee_print_bt(excp_regs
);
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:");
364 aee_rec_step_nested_panic(step_base
+ 5);
365 ipanic_recursive_ke(regs
, excp_regs
, cpu
);
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
);
371 aee_nested_printf("get_wd_api error\n");
373 wd_api
->wd_aee_confirm_hwreboot();
375 aee_rec_step_nested_panic(step_base
+ 7);
381 /* waiting for the WDT timeout */
383 /* output to UART directly to avoid printk nested panic */
384 /* mt_fiq_printf("%s hang here%d\t", __func__, i++); */