From 93c86c992b75ce01c1a3446e1e93c29a20f6bf94 Mon Sep 17 00:00:00 2001 From: Jaeseong GIM Date: Tue, 26 Jun 2012 10:36:57 -0700 Subject: [PATCH] mako: debug: porting lge crash handler Change-Id: I913d372131a25bb9c0d90680f5e96cebb8883055 Signed-off-by: Iliyan Malchev --- arch/arm/configs/mako_defconfig | 1 + arch/arm/kernel/process.c | 20 ++ arch/arm/kernel/traps.c | 27 ++ arch/arm/mach-msm/include/mach/board_lge.h | 8 +- arch/arm/mach-msm/include/mach/memory.h | 4 + arch/arm/mach-msm/include/mach/restart.h | 8 + arch/arm/mach-msm/lge/Kconfig | 7 + arch/arm/mach-msm/lge/Makefile | 3 +- arch/arm/mach-msm/lge/devices_lge.c | 8 +- arch/arm/mach-msm/lge/lge_panic_handler.c | 322 +++++++++++++++++++++ arch/arm/mach-msm/lpass-8960.c | 13 + arch/arm/mach-msm/restart.c | 85 +++++- arch/arm/mach-msm/subsystem_restart.c | 46 ++- include/linux/kernel.h | 11 + kernel/panic.c | 7 + kernel/printk.c | 3 + 16 files changed, 560 insertions(+), 13 deletions(-) create mode 100644 arch/arm/mach-msm/lge/lge_panic_handler.c diff --git a/arch/arm/configs/mako_defconfig b/arch/arm/configs/mako_defconfig index 607ff652680..3a9368ab99e 100644 --- a/arch/arm/configs/mako_defconfig +++ b/arch/arm/configs/mako_defconfig @@ -45,6 +45,7 @@ CONFIG_MSM_KRAIT_TBB_ABORT_HANDLER=y CONFIG_MACH_MSM_DUMMY=y CONFIG_BOARD_HEADER_FILE="mach/lge/board_mako.h" CONFIG_MACH_APQ8064_MAKO=y +CONFIG_LGE_CRASH_HANDLER=y CONFIG_LGE_QFPROM_INTERFACE=y CONFIG_UPDATE_LCDC_LUT=y CONFIG_LCD_KCAL=y diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index a9582f9b300..fdb2add2a6c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -412,6 +412,12 @@ void __show_regs(struct pt_regs *regs) unsigned long flags; char buf[64]; +#ifdef CONFIG_LGE_CRASH_HANDLER +#ifdef CONFIG_CPU_CP15_MMU + unsigned int c1, c2; +#endif + set_crash_store_enable(); +#endif printk("CPU: %d %s (%s %.*s)\n", raw_smp_processor_id(), print_tainted(), init_utsname()->release, @@ -419,7 +425,11 @@ void __show_regs(struct pt_regs *regs) init_utsname()->version); print_symbol("PC is at %s\n", instruction_pointer(regs)); print_symbol("LR is at %s\n", regs->ARM_lr); +#ifdef CONFIG_LGE_CRASH_HANDLER + printk("pc : <%08lx> lr : <%08lx> psr: %08lx\n" +#else printk("pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n" +#endif "sp : %08lx ip : %08lx fp : %08lx\n", regs->ARM_pc, regs->ARM_lr, regs->ARM_cpsr, regs->ARM_sp, regs->ARM_ip, regs->ARM_fp); @@ -432,6 +442,9 @@ void __show_regs(struct pt_regs *regs) printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", regs->ARM_r3, regs->ARM_r2, regs->ARM_r1, regs->ARM_r0); +#ifdef CONFIG_LGE_CRASH_HANDLER + set_crash_store_disable(); +#endif flags = regs->ARM_cpsr; buf[0] = flags & PSR_N_BIT ? 'N' : 'n'; @@ -459,11 +472,18 @@ void __show_regs(struct pt_regs *regs) : "=r" (transbase), "=r" (dac)); snprintf(buf, sizeof(buf), " Table: %08x DAC: %08x", transbase, dac); +#if defined(CONFIG_CPU_CP15_MMU) && defined(CONFIG_LGE_CRASH_HANDLER) + c1 = transbase; + c2 = dac; +#endif } #endif asm("mrc p15, 0, %0, c1, c0\n" : "=r" (ctrl)); printk("Control: %08x%s\n", ctrl, buf); +#if defined(CONFIG_CPU_CP15_MMU) && defined(CONFIG_LGE_CRASH_HANDLER) + lge_save_ctx(regs, ctrl, c1, c2); +#endif } #endif diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 63d402f75e2..ff5d87396b0 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -39,6 +39,10 @@ static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; +#ifdef CONFIG_LGE_CRASH_HANDLER +static int first_call_chain = 0; +static int first_die = 1; +#endif void *vectors_page; #ifdef CONFIG_DEBUG_USER @@ -57,7 +61,14 @@ static void dump_mem(const char *, const char *, unsigned long, unsigned long); void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) { #ifdef CONFIG_KALLSYMS +#ifdef CONFIG_LGE_CRASH_HANDLER + if (first_call_chain) + set_crash_store_enable(); +#endif printk("[<%08lx>] (%pS) from [<%08lx>] (%pS)\n", where, (void *)where, from, (void *)from); +#ifdef CONFIG_LGE_CRASH_HANDLER + set_crash_store_disable(); +#endif #else printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); #endif @@ -239,9 +250,22 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt static int die_counter; int ret; +#ifdef CONFIG_LGE_CRASH_HANDLER + if (first_die) { + first_call_chain = 1; + first_die = 0; + } + set_kernel_crash_magic_number(); + set_crash_store_enable(); +#endif + printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP S_ISA "\n", str, err, ++die_counter); +#ifdef CONFIG_LGE_CRASH_HANDLER + set_crash_store_disable(); +#endif + /* trap and error numbers are mostly meaningless on ARM */ ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); if (ret == NOTIFY_STOP) @@ -257,6 +281,9 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt THREAD_SIZE + (unsigned long)task_stack_page(tsk)); dump_backtrace(regs, tsk); dump_instr(KERN_EMERG, regs); +#ifdef CONFIG_LGE_CRASH_HANDLER + first_call_chain = 0; +#endif } return ret; diff --git a/arch/arm/mach-msm/include/mach/board_lge.h b/arch/arm/mach-msm/include/mach/board_lge.h index f77279f6884..92f3375dff8 100644 --- a/arch/arm/mach-msm/include/mach/board_lge.h +++ b/arch/arm/mach-msm/include/mach/board_lge.h @@ -23,7 +23,7 @@ #define LGE_RAM_CONSOLE_SIZE (124*SZ_1K * 2) #endif -#ifdef CONFIG_LGE_HANDLE_PANIC +#ifdef CONFIG_LGE_CRASH_HANDLER #define LGE_CRASH_LOG_SIZE (4*SZ_1K) #endif @@ -129,10 +129,10 @@ enum lge_boot_mode_type { void __init lge_add_ramconsole_devices(void); #endif -#ifdef CONFIG_LGE_HANDLE_PANIC +#ifdef CONFIG_LGE_CRASH_HANDLER void __init lge_add_panic_handler_devices(void); -int lge_get_magic_for_subsystem(void); -void lge_set_magic_for_subsystem(const char *subsys_name); +int get_ssr_magic_number(void); +void set_ssr_magic_number(const char *subsys_name); #endif #ifdef CONFIG_LGE_QFPROM_INTERFACE diff --git a/arch/arm/mach-msm/include/mach/memory.h b/arch/arm/mach-msm/include/mach/memory.h index 6b7ad9af6f3..1c7b2fb82e4 100644 --- a/arch/arm/mach-msm/include/mach/memory.h +++ b/arch/arm/mach-msm/include/mach/memory.h @@ -94,6 +94,10 @@ extern void l2x0_cache_sync(void); #if defined(CONFIG_ARCH_MSM8X60) || defined(CONFIG_ARCH_MSM8960) extern void store_ttbr0(void); +#ifdef CONFIG_LGE_CRASH_HANDLER +extern void store_ctrl(void); +extern void store_dac(void); +#endif #define finish_arch_switch(prev) do { store_ttbr0(); } while (0) #endif diff --git a/arch/arm/mach-msm/include/mach/restart.h b/arch/arm/mach-msm/include/mach/restart.h index b913e3f1dc6..4d7b558c5bc 100644 --- a/arch/arm/mach-msm/include/mach/restart.h +++ b/arch/arm/mach-msm/include/mach/restart.h @@ -17,6 +17,14 @@ #define RESTART_NORMAL 0x0 #define RESTART_DLOAD 0x1 +#if defined(CONFIG_LGE_CRASH_HANDLER) +#define SUB_THD_F_PWR 0x0190 +#define SUB_THD_F_SD 0x0110 +#define SUB_UNAB_THD 0x0120 +#define SUB_RESET_SOC 0x0130 +#define SUB_UNKNOWN 0x0140 +#endif + #if defined(CONFIG_MSM_NATIVE_RESTART) void msm_set_restart_mode(int mode); void msm_restart(char mode, const char *cmd); diff --git a/arch/arm/mach-msm/lge/Kconfig b/arch/arm/mach-msm/lge/Kconfig index af3b24b3b74..f70d7736835 100644 --- a/arch/arm/mach-msm/lge/Kconfig +++ b/arch/arm/mach-msm/lge/Kconfig @@ -35,4 +35,11 @@ config EARJACK_DEBUGGER default n help Saying Y here will support earjack type UART debugger cable + +config LGE_CRASH_HANDLER + tristate "Support LGE Crash Handler" + default n + help + LGE Crash Handler + endmenu diff --git a/arch/arm/mach-msm/lge/Makefile b/arch/arm/mach-msm/lge/Makefile index 336374a92b3..9142a7d8082 100644 --- a/arch/arm/mach-msm/lge/Makefile +++ b/arch/arm/mach-msm/lge/Makefile @@ -6,4 +6,5 @@ obj-$(CONFIG_MACH_LGE) += devices_lge.o obj-$(CONFIG_LGE_QFPROM_INTERFACE) += lge_qfprom_access.o obj-$(CONFIG_LGE_QC_LCDC_LUT) += lge_qc_lcdc_luts.o obj-$(CONFIG_LGE_KCAL) += lge_kcal_ctrl.o -obj-$(CONFIG_LGE_KCAL_QLUT) += kcal_qlut.o \ No newline at end of file +obj-$(CONFIG_LGE_KCAL_QLUT) += kcal_qlut.o +obj-$(CONFIG_LGE_CRASH_HANDLER) += lge_panic_handler.o diff --git a/arch/arm/mach-msm/lge/devices_lge.c b/arch/arm/mach-msm/lge/devices_lge.c index b21cb21d694..723df3e2dd7 100644 --- a/arch/arm/mach-msm/lge/devices_lge.c +++ b/arch/arm/mach-msm/lge/devices_lge.c @@ -343,7 +343,7 @@ void __init lge_add_ramconsole_devices(void) struct resource* res = ram_console_resource; struct membank* bank = &meminfo.bank[0]; - res->start = PHYS_OFFSET + bank->size; + res->start = bank->start + bank->size; res->end = res->start + LGE_RAM_CONSOLE_SIZE - 1; printk(KERN_INFO "RAM CONSOLE START ADDR : %X\n", res->start); @@ -351,9 +351,9 @@ void __init lge_add_ramconsole_devices(void) platform_device_register(&ram_console_device); } -#endif // CONFIG_ANDROID_RAM_CONSOLE +#endif /* CONFIG_ANDROID_RAM_CONSOLE */ -#ifdef CONFIG_LGE_HANDLE_PANIC +#ifdef CONFIG_LGE_CRASH_HANDLER static struct resource crash_log_resource[] = { { .name = "crash_log", @@ -383,7 +383,7 @@ void __init lge_add_panic_handler_devices(void) platform_device_register(&panic_handler_device); } -#endif // CONFIG_LGE_HANDLE_PANIC +#endif /* CONFIG_LGE_CRASH_HANDLER */ #ifdef CONFIG_LGE_QFPROM_INTERFACE static struct platform_device qfprom_device = { diff --git a/arch/arm/mach-msm/lge/lge_panic_handler.c b/arch/arm/mach-msm/lge/lge_panic_handler.c new file mode 100644 index 00000000000..ff3e355310c --- /dev/null +++ b/arch/arm/mach-msm/lge/lge_panic_handler.c @@ -0,0 +1,322 @@ +/* + * arch/arm/mach-msm/lge/lge_panic_handler.c + * + * Copyright (C) 2010 LGE, Inc + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef CONFIG_CPU_CP15_MMU +#include +#endif + +#define PANIC_HANDLER_NAME "panic-handler" +#define PANIC_DUMP_CONSOLE 0 +#define PANIC_MAGIC_KEY 0x12345678 +#define CRASH_ARM9 0x87654321 +#define CRASH_REBOOT 0x618E1000 + +struct crash_log_dump { + unsigned int magic_key; + unsigned int size; + unsigned char buffer[0]; +}; + +static struct crash_log_dump *crash_dump_log; +static unsigned int crash_buf_size = 0; +static int crash_store_flag = 0; + +#ifdef CONFIG_CPU_CP15_MMU +unsigned long *cpu_crash_ctx=NULL; +#endif + +unsigned int msm_mmuctrl; +unsigned int msm_mmudac; + +void store_ctrl(void) +{ + asm("mrc p15, 0, %0, c1, c0, 0\n" + : "=r" (msm_mmuctrl)); +} + +void store_dac(void) +{ + asm("mrc p15, 0, %0, c3, c0, 0\n" + : "=r" (msm_mmudac)); +} +static DEFINE_SPINLOCK(panic_lock); + +static int dummy_arg; +static int gen_bug(const char *val, struct kernel_param *kp) +{ + BUG(); + return 0; +} +module_param_call(gen_bug, gen_bug, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +static int gen_panic(const char *val, struct kernel_param *kp) +{ + panic("generate test-panic"); + return 0; +} +module_param_call(gen_panic, gen_panic, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +static int gen_mdm_ssr(const char *val, struct kernel_param *kp) +{ + subsystem_restart("external_modem"); + return 0; +} +module_param_call(gen_mdm_ssr, gen_mdm_ssr, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +static int gen_modem_ssr(const char *val, struct kernel_param *kp) +{ + subsystem_restart("modem"); + return 0; +} +module_param_call(gen_modem_ssr, gen_modem_ssr, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +static int gen_riva_ssr(const char *val, struct kernel_param *kp) +{ + subsystem_restart("riva"); + return 0; +} +module_param_call(gen_riva_ssr, gen_riva_ssr, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +static int gen_dsps_ssr(const char *val, struct kernel_param *kp) +{ + subsystem_restart("dsps"); + return 0; +} +module_param_call(gen_dsps_ssr, gen_dsps_ssr, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +static int gen_lpass_ssr(const char *val, struct kernel_param *kp) +{ + subsystem_restart("lpass"); + return 0; +} +module_param_call(gen_lpass_ssr, gen_lpass_ssr, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +#define WDT0_RST 0x38 +#define WDT0_EN 0x40 +#define WDT0_BARK_TIME 0x4C +#define WDT0_BITE_TIME 0x5C + +extern void __iomem *msm_timer_get_timer0_base(void); + +static int gen_wdt_bark(const char *val, struct kernel_param *kp) +{ + static void __iomem *msm_tmr0_base; + msm_tmr0_base = msm_timer_get_timer0_base(); + __raw_writel(0, msm_tmr0_base + WDT0_EN); + __raw_writel(1, msm_tmr0_base + WDT0_RST); + __raw_writel(0x31F3, msm_tmr0_base + WDT0_BARK_TIME); + __raw_writel(5 * 0x31F3, msm_tmr0_base + WDT0_BITE_TIME); + __raw_writel(1, msm_tmr0_base + WDT0_EN); + return 0; +} +module_param_call(gen_wdt_bark, gen_wdt_bark, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +static int gen_hw_reset(const char *val, struct kernel_param *kp) +{ + static void __iomem *msm_tmr0_base; + msm_tmr0_base = msm_timer_get_timer0_base(); + __raw_writel(0, msm_tmr0_base + WDT0_EN); + __raw_writel(1, msm_tmr0_base + WDT0_RST); + __raw_writel(5 * 0x31F3, msm_tmr0_base + WDT0_BARK_TIME); + __raw_writel(0x31F3, msm_tmr0_base + WDT0_BITE_TIME); + __raw_writel(1, msm_tmr0_base + WDT0_EN); + return 0; +} +module_param_call(gen_hw_reset, gen_hw_reset, param_get_bool, + &dummy_arg, S_IWUSR | S_IRUGO); + +void set_crash_store_enable(void) +{ + crash_store_flag = 1; + return; +} + +void set_crash_store_disable(void) +{ + crash_store_flag = 0; + return; +} + +void store_crash_log(char *p) +{ + if (!crash_store_flag) + return; + if (crash_dump_log->size == crash_buf_size) + return; + for ( ; *p; p++) { + if (*p == '[') { + for ( ; *p != ']'; p++) + ; + p++; + if (*p == ' ') + p++; + } + if (*p == '<') { + for ( ; *p != '>'; p++) + ; + p++; + } + crash_dump_log->buffer[crash_dump_log->size] = *p; + crash_dump_log->size++; + } + crash_dump_log->buffer[crash_dump_log->size] = 0; + + return; +} + +#ifdef CONFIG_CPU_CP15_MMU +void lge_save_ctx(struct pt_regs* regs, unsigned int ctrl, + unsigned int transbase, unsigned int dac) +{ + /* save cpu register for simulation */ + cpu_crash_ctx[0] = regs->ARM_r0; + cpu_crash_ctx[1] = regs->ARM_r1; + cpu_crash_ctx[2] = regs->ARM_r2; + cpu_crash_ctx[3] = regs->ARM_r3; + cpu_crash_ctx[4] = regs->ARM_r4; + cpu_crash_ctx[5] = regs->ARM_r5; + cpu_crash_ctx[6] = regs->ARM_r6; + cpu_crash_ctx[7] = regs->ARM_r7; + cpu_crash_ctx[8] = regs->ARM_r8; + cpu_crash_ctx[9] = regs->ARM_r9; + cpu_crash_ctx[10] = regs->ARM_r10; + cpu_crash_ctx[11] = regs->ARM_fp; + cpu_crash_ctx[12] = regs->ARM_ip; + cpu_crash_ctx[13] = regs->ARM_sp; + cpu_crash_ctx[14] = regs->ARM_lr; + cpu_crash_ctx[15] = regs->ARM_pc; + cpu_crash_ctx[16] = regs->ARM_cpsr; + /* save mmu register for simulation */ + cpu_crash_ctx[17] = ctrl; + cpu_crash_ctx[18] = transbase; + cpu_crash_ctx[19] = dac; +} +#endif + +static int restore_crash_log(struct notifier_block *this, + unsigned long event, void *ptr) +{ + unsigned long flags; + crash_store_flag = 0; + spin_lock_irqsave(&panic_lock, flags); + crash_dump_log->magic_key = PANIC_MAGIC_KEY; + spin_unlock_irqrestore(&panic_lock, flags); + + return NOTIFY_DONE; +} + +static struct notifier_block panic_handler_block = { + .notifier_call = restore_crash_log, +}; + +static int __init panic_handler_probe(struct platform_device *pdev) +{ + struct resource *res = pdev->resource; + size_t start; + size_t buffer_size; + void *buffer; + int ret = 0; +#ifdef CONFIG_CPU_CP15_MMU + void *ctx_buf; + size_t ctx_start; +#endif + if (res == NULL || pdev->num_resources != 1 || + !(res->flags & IORESOURCE_MEM)) { + printk(KERN_ERR "lge_panic_handler: invalid resource, %p %d " + "flags %lx\n", res, pdev->num_resources, + res ? res->flags : 0); + return -ENXIO; + } + + buffer_size = res->end - res->start + 1; + start = res->start; + printk(KERN_INFO "lge_panic_handler: got buffer at %zx, size %zx\n", + start, buffer_size); + buffer = ioremap(res->start, buffer_size); + if (buffer == NULL) { + printk(KERN_ERR "lge_panic_handler: failed to map memory\n"); + return -ENOMEM; + } + + crash_dump_log = (struct crash_log_dump *)buffer; + memset(crash_dump_log, 0, buffer_size); + crash_dump_log->magic_key = 0; + crash_dump_log->size = 0; + crash_buf_size = buffer_size - offsetof(struct crash_log_dump, buffer); +#ifdef CONFIG_CPU_CP15_MMU + ctx_start = res->end + 1; + ctx_buf = ioremap(ctx_start,1024); + if (ctx_buf == NULL) { + printk(KERN_ERR "cpu crash ctx buffer: " + "failed to map memory\n"); + return -ENOMEM; + } + cpu_crash_ctx = (unsigned long *)ctx_buf; +#endif + atomic_notifier_chain_register(&panic_notifier_list, + &panic_handler_block); + return ret; +} + +static int __devexit panic_handler_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver panic_handler_driver __refdata = { + .probe = panic_handler_probe, + .remove = __devexit_p(panic_handler_remove), + .driver = { + .name = PANIC_HANDLER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init lge_panic_handler_init(void) +{ + return platform_driver_register(&panic_handler_driver); +} + +static void __exit lge_panic_handler_exit(void) +{ + platform_driver_unregister(&panic_handler_driver); +} + +module_init(lge_panic_handler_init); +module_exit(lge_panic_handler_exit); + +MODULE_DESCRIPTION("LGE panic handler driver"); +MODULE_AUTHOR("SungEun Kim "); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c index b714a7f0cee..794eb529d5a 100644 --- a/arch/arm/mach-msm/lpass-8960.c +++ b/arch/arm/mach-msm/lpass-8960.c @@ -25,6 +25,11 @@ #include #include +#if defined(CONFIG_LGE_CRASH_HANDLER) +#include +#include +#endif + #include "smd_private.h" #include "ramdump.h" #include "sysmon.h" @@ -120,6 +125,10 @@ static void lpass_fatal_fn(struct work_struct *work) pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME, __func__); lpass_log_failure_reason(); +#if defined(CONFIG_LGE_CRASH_HANDLER) + set_ssr_magic_number("lpass"); + msm_set_restart_mode(0x6d634130); +#endif panic(MODULE_NAME ": Resetting the SoC"); } @@ -135,6 +144,10 @@ static void lpass_smsm_state_cb(void *data, uint32_t old_state, " new_state = 0x%x, old_state = 0x%x\n", __func__, new_state, old_state); lpass_log_failure_reason(); +#if defined(CONFIG_LGE_CRASH_HANDLER) + set_ssr_magic_number("lpass"); + msm_set_restart_mode(0x6d634130); +#endif panic(MODULE_NAME ": Resetting the SoC"); } } diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c index 7288c1d67d6..c12f39c8537 100644 --- a/arch/arm/mach-msm/restart.c +++ b/arch/arm/mach-msm/restart.c @@ -47,6 +47,12 @@ #define SCM_IO_DISABLE_PMIC_ARBITER 1 +#ifdef CONFIG_LGE_CRASH_HANDLER +#define LGE_ERROR_HANDLER_MAGIC_NUM 0xA97F2C46 +#define LGE_ERROR_HANDLER_MAGIC_ADDR 0x18 +void *lge_error_handler_cookie_addr; +#endif + static int restart_mode; void *restart_reason; @@ -80,6 +86,10 @@ static void set_dload_mode(int on) __raw_writel(on ? 0xE47B337D : 0, dload_mode_addr); __raw_writel(on ? 0xCE14091A : 0, dload_mode_addr + sizeof(unsigned int)); +#ifdef CONFIG_LGE_CRASH_HANDLER + __raw_writel(on ? LGE_ERROR_HANDLER_MAGIC_NUM : 0, + lge_error_handler_cookie_addr); +#endif mb(); } } @@ -177,6 +187,43 @@ static irqreturn_t resout_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +#ifdef CONFIG_LGE_CRASH_HANDLER +static int ssr_magic_number = 0; +#define SUBSYS_NAME_MAX_LENGTH 40 + +int get_ssr_magic_number(void) +{ + return ssr_magic_number; +} + +void set_ssr_magic_number(const char* subsys_name) +{ + int i; + const char *subsys_list[] = { + "modem", "riva", "dsps", "lpass", + "external_modem", "gss", + }; + + ssr_magic_number = (0x6d630000 | 0x0000f000); + + for (i=0; i < ARRAY_SIZE(subsys_list); i++) { + if (!strncmp(subsys_list[i], subsys_name, + SUBSYS_NAME_MAX_LENGTH)) { + ssr_magic_number = (0x6d630000 | ((i+1)<<12)); + break; + } + } +} + +void set_kernel_crash_magic_number(void) +{ + if (ssr_magic_number == 0) + __raw_writel(0x6d630100, restart_reason); + else + __raw_writel(restart_mode, restart_reason); +} +#endif /* CONFIG_LGE_CRASH_HANDLER */ + void msm_restart(char mode, const char *cmd) { @@ -189,8 +236,13 @@ void msm_restart(char mode, const char *cmd) set_dload_mode(in_panic); /* Write download mode flags if restart_mode says so */ - if (restart_mode == RESTART_DLOAD) + if (restart_mode == RESTART_DLOAD) { set_dload_mode(1); +#ifdef CONFIG_LGE_CRASH_HANDLER + writel(0x6d63c421, restart_reason); + goto reset; +#endif + } /* Kill download mode if master-kill switch is set */ if (!download_mode) @@ -201,6 +253,28 @@ void msm_restart(char mode, const char *cmd) pm8xxx_reset_pwr_off(1); +#ifdef CONFIG_LGE_CRASH_HANDLER + if (in_panic == 1) { + set_kernel_crash_magic_number(); + } else { + if (cmd != NULL) { + if (!strncmp(cmd, "bootloader", 10)) { + __raw_writel(0x77665500, restart_reason); + } else if (!strncmp(cmd, "recovery", 8)) { + __raw_writel(0x77665502, restart_reason); + } else if (!strncmp(cmd, "oem-", 4)) { + unsigned long code; + code = simple_strtoul(cmd+4, NULL, 16) & 0xff; + __raw_writel(0x6f656d00, restart_reason); + } else if (!strncmp(cmd, "recovery", 8)) { + __raw_writel(0x77665502, restart_reason); + } else { + __raw_writel(0x77665501, restart_reason); + } + } + } +reset: +#else if (cmd != NULL) { if (!strncmp(cmd, "bootloader", 10)) { __raw_writel(0x77665500, restart_reason); @@ -214,6 +288,7 @@ void msm_restart(char mode, const char *cmd) __raw_writel(0x77665501, restart_reason); } } +#endif /* CONFIG_LGE_CRASH_HANDLER */ __raw_writel(0, msm_tmr0_base + WDT0_EN); if (!(machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())) { @@ -246,6 +321,10 @@ static int __init msm_pmic_restart_init(void) pr_warn("no pmic restart interrupt specified\n"); } +#ifdef CONFIG_LGE_CRASH_HANDLER + __raw_writel(0x6d63ad00, restart_reason); +#endif + return 0; } @@ -256,6 +335,10 @@ static int __init msm_restart_init(void) #ifdef CONFIG_MSM_DLOAD_MODE atomic_notifier_chain_register(&panic_notifier_list, &panic_blk); dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR; +#ifdef CONFIG_LGE_CRASH_HANDLER + lge_error_handler_cookie_addr = MSM_IMEM_BASE + + LGE_ERROR_HANDLER_MAGIC_ADDR; +#endif set_dload_mode(download_mode); #endif msm_tmr0_base = msm_timer_get_timer0_base(); diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c index fdde328a9f5..201218e9a26 100644 --- a/arch/arm/mach-msm/subsystem_restart.c +++ b/arch/arm/mach-msm/subsystem_restart.c @@ -35,6 +35,10 @@ #include #include +#if defined(CONFIG_LGE_CRASH_HANDLER) +#include +#include +#endif #include "smd_private.h" struct subsys_soc_restart_order { @@ -209,6 +213,9 @@ static void do_epoch_check(struct subsys_device *dev) struct restart_log *r_log, *temp; static int max_restarts_check; static long max_history_time_check; +#if defined(CONFIG_LGE_CRASH_HANDLER) + int ssr_magic_number = get_ssr_magic_number(); +#endif mutex_lock(&restart_log_mutex); @@ -250,10 +257,14 @@ static void do_epoch_check(struct subsys_device *dev) if (time_first && n >= max_restarts_check) { if ((curr_time->tv_sec - time_first->tv_sec) < - max_history_time_check) + max_history_time_check) { +#if defined(CONFIG_LGE_CRASH_HANDLER) + msm_set_restart_mode(ssr_magic_number | SUB_UNAB_THD); +#endif panic("Subsystems have crashed %d times in less than " "%ld seconds!", max_restarts_check, max_history_time_check); + } } out: @@ -287,11 +298,18 @@ static void send_notification_to_order(struct subsys_device **l, unsigned n, static void subsystem_shutdown(struct subsys_device *dev, void *data) { const char *name = dev->desc->name; +#if defined(CONFIG_LGE_CRASH_HANDLER) + int ssr_magic_number = get_ssr_magic_number(); +#endif pr_info("[%p]: Shutting down %s\n", current, name); - if (dev->desc->shutdown(dev->desc) < 0) + if (dev->desc->shutdown(dev->desc) < 0) { +#if defined(CONFIG_LGE_CRASH_HANDLER) + msm_set_restart_mode(ssr_magic_number | SUB_THD_F_SD); +#endif panic("subsys-restart: [%p]: Failed to shutdown %s!", current, name); + } } static void subsystem_ramdump(struct subsys_device *dev, void *data) @@ -324,6 +342,10 @@ static void subsystem_restart_wq_func(struct work_struct *work) unsigned count; unsigned long flags; +#if defined(CONFIG_LGE_CRASH_HANDLER) + int ssr_magic_number = get_ssr_magic_number(); +#endif + if (restart_level != RESET_SUBSYS_INDEPENDENT) soc_restart_order = dev->restart_order; @@ -361,9 +383,13 @@ static void subsystem_restart_wq_func(struct work_struct *work) * sequence for these subsystems. In the latter case, panic and bail * out, since a subsystem died in its powerup sequence. */ - if (!mutex_trylock(powerup_lock)) + if (!mutex_trylock(powerup_lock)) { +#if defined(CONFIG_LGE_CRASH_HANDLER) + msm_set_restart_mode(ssr_magic_number | SUB_THD_F_PWR); +#endif panic("%s[%p]: Subsystem died during powerup!", __func__, current); + } do_epoch_check(dev); @@ -437,10 +463,18 @@ static void __subsystem_restart_dev(struct subsys_device *dev) int subsystem_restart_dev(struct subsys_device *dev) { const char *name = dev->desc->name; +#if defined(CONFIG_LGE_CRASH_HANDLER) + u32 ssr_magic_number; +#endif pr_info("Restart sequence requested for %s, restart_level = %d.\n", name, restart_level); +#if defined(CONFIG_LGE_CRASH_HANDLER) + set_ssr_magic_number(subsys_name); + ssr_magic_number = get_ssr_magic_number(); +#endif + switch (restart_level) { case RESET_SUBSYS_COUPLED: @@ -448,9 +482,15 @@ int subsystem_restart_dev(struct subsys_device *dev) __subsystem_restart_dev(dev); break; case RESET_SOC: +#if defined(CONFIG_LGE_CRASH_HANDLER) + msm_set_restart_mode(ssr_magic_number | SUB_RESET_SOC); +#endif panic("subsys-restart: Resetting the SoC - %s crashed.", name); break; default: +#if defined(CONFIG_LGE_CRASH_HANDLER) + msm_set_restart_mode(ssr_magic_number | SUB_UNKNOWN); +#endif panic("subsys-restart: Unknown restart level!\n"); break; } diff --git a/include/linux/kernel.h b/include/linux/kernel.h index fb0c7af76e5..2d2e1eee550 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -349,6 +349,17 @@ extern int func_ptr_is_kernel_text(void *ptr); struct pid; extern struct pid *session_of_pgrp(struct pid *pgrp); +#ifdef CONFIG_LGE_CRASH_HANDLER +extern void set_crash_store_enable(void); +extern void set_crash_store_disable(void); +extern void store_crash_log(char *p); +extern void set_kernel_crash_magic_number(void); +#ifdef CONFIG_CPU_CP15_MMU +extern void lge_save_ctx(struct pt_regs*, unsigned int, unsigned int, + unsigned int); +#endif +#endif + unsigned long int_sqrt(unsigned long); extern void bust_spinlocks(int yes); diff --git a/kernel/panic.c b/kernel/panic.c index 8c6babcf898..d061717cffb 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -106,7 +106,14 @@ void panic(const char *fmt, ...) va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); +#ifdef CONFIG_LGE_CRASH_HANDLER + set_kernel_crash_magic_number(); + set_crash_store_enable(); +#endif printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf); +#ifdef CONFIG_LGE_CRASH_HANDLER + set_crash_store_disable(); +#endif #ifdef CONFIG_DEBUG_BUGVERBOSE /* * Avoid nested stack-dumping if a panic occurs during oops processing diff --git a/kernel/printk.c b/kernel/printk.c index 7330ccc61c7..d72977beec5 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -940,6 +940,9 @@ asmlinkage int vprintk(const char *fmt, va_list args) p = printk_buf; +#ifdef CONFIG_LGE_CRASH_HANDLER + store_crash_log(p); +#endif /* Read log level and handle special printk prefix */ plen = log_prefix(p, ¤t_log_level, &special);