mako: debug: porting lge crash handler
Change-Id: I913d372131a25bb9c0d90680f5e96cebb8883055
diff --git a/arch/arm/configs/mako_defconfig b/arch/arm/configs/mako_defconfig
index d7e3ec2..702ef59 100644
--- a/arch/arm/configs/mako_defconfig
+++ b/arch/arm/configs/mako_defconfig
@@ -46,6 +46,7 @@
CONFIG_MACH_APQ8064_MTP=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_LGE_QC_LCDC_LUT=y
CONFIG_LGE_KCAL=y
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index a9582f9..fdb2add 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -412,6 +412,12 @@
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 @@
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 @@
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 @@
: "=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 63d402f..ff5d873 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 @@
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_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 @@
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 239dee1..833b419 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
@@ -126,10 +126,10 @@
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 2596364..c0e6791 100644
--- a/arch/arm/mach-msm/include/mach/memory.h
+++ b/arch/arm/mach-msm/include/mach/memory.h
@@ -93,6 +93,10 @@
#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 b913e3f..4d7b558 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 0c7e695..8c89b18 100644
--- a/arch/arm/mach-msm/lge/Kconfig
+++ b/arch/arm/mach-msm/lge/Kconfig
@@ -42,4 +42,11 @@
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 336374a..9142a7d 100644
--- a/arch/arm/mach-msm/lge/Makefile
+++ b/arch/arm/mach-msm/lge/Makefile
@@ -6,4 +6,5 @@
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 e709b70..9186e39 100644
--- a/arch/arm/mach-msm/lge/devices_lge.c
+++ b/arch/arm/mach-msm/lge/devices_lge.c
@@ -340,7 +340,7 @@
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);
@@ -348,9 +348,9 @@
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",
@@ -380,7 +380,7 @@
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 0000000..ff3e355
--- /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 <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <asm/setup.h>
+#include <mach/board_lge.h>
+
+#include <mach/subsystem_restart.h>
+#ifdef CONFIG_CPU_CP15_MMU
+#include <linux/ptrace.h>
+#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 <cleaneye.kim@lge.com>");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-msm/lge/mako/board-mako.c b/arch/arm/mach-msm/lge/mako/board-mako.c
index 468191b..7c14212 100644
--- a/arch/arm/mach-msm/lge/mako/board-mako.c
+++ b/arch/arm/mach-msm/lge/mako/board-mako.c
@@ -2357,11 +2357,10 @@
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
- /**/
#ifdef CONFIG_ANDROID_RAM_CONSOLE
lge_add_ramconsole_devices();
#endif
-#ifdef CONFIG_LGE_HANDLE_PANIC
+#ifdef CONFIG_LGE_CRASH_HANDLER
lge_add_panic_handler_devices();
#endif
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index c58b0e1..a546ff3 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -25,6 +25,11 @@
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+#include <mach/restart.h>
+#include <mach/board_lge.h>
+#endif
+
#include "smd_private.h"
#include "ramdump.h"
#include "sysmon.h"
@@ -120,6 +125,10 @@
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 @@
" 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 7288c1d..c12f39c 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 @@
__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 @@
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 @@
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 @@
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 @@
__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 @@
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 @@
#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 c98a672..241fde9 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -34,6 +34,10 @@
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+#include <mach/restart.h>
+#include <mach/board_lge.h>
+#endif
#include "smd_private.h"
struct subsys_soc_restart_order {
@@ -225,6 +229,9 @@
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);
@@ -266,10 +273,14 @@
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:
@@ -290,6 +301,9 @@
int i;
int restart_list_count = 0;
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+ int ssr_magic_number = get_ssr_magic_number();
+#endif
if (r_work->use_restart_order)
soc_restart_order = subsys->restart_order;
@@ -324,9 +338,13 @@
* 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(subsys);
@@ -351,9 +369,13 @@
pr_info("[%p]: Shutting down %s\n", current,
restart_list[i]->name);
- if (restart_list[i]->shutdown(subsys) < 0)
+ if (restart_list[i]->shutdown(subsys) < 0) {
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+ msm_set_restart_mode(ssr_magic_number | SUB_THD_F_SD);
+#endif
panic("subsys-restart: %s[%p]: Failed to shutdown %s!",
__func__, current, restart_list[i]->name);
+ }
}
_send_notification_to_order(restart_list, restart_list_count,
@@ -390,9 +412,13 @@
pr_info("[%p]: Powering up %s\n", current,
restart_list[i]->name);
- if (restart_list[i]->powerup(subsys) < 0)
+ if (restart_list[i]->powerup(subsys) < 0) {
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+ msm_set_restart_mode(ssr_magic_number | SUB_THD_F_PWR);
+#endif
panic("%s[%p]: Failed to powerup %s!", __func__,
current, restart_list[i]->name);
+ }
}
_send_notification_to_order(restart_list,
@@ -418,14 +444,21 @@
{
struct restart_wq_data *data = NULL;
int rc;
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+ int ssr_magic_number = get_ssr_magic_number();
+#endif
pr_debug("Restarting %s [level=%d]!\n", subsys->name,
restart_level);
data = kzalloc(sizeof(struct restart_wq_data), GFP_ATOMIC);
- if (!data)
+ if (!data) {
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+ msm_set_restart_mode(ssr_magic_number | SUB_UNAB_THD);
+#endif
panic("%s: Unable to allocate memory to restart %s.",
__func__, subsys->name);
+ }
data->subsys = subsys;
@@ -438,14 +471,21 @@
INIT_WORK(&data->work, subsystem_restart_wq_func);
rc = queue_work(ssr_wq, &data->work);
- if (rc < 0)
+ if (rc < 0) {
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+ msm_set_restart_mode(ssr_magic_number | SUB_UNAB_THD);
+#endif
panic("%s: Unable to schedule work to restart %s (%d).",
__func__, subsys->name, rc);
+ }
}
int subsystem_restart(const char *subsys_name)
{
struct subsys_data *subsys;
+#if defined(CONFIG_LGE_CRASH_HANDLER)
+ u32 ssr_magic_number;
+#endif
if (!subsys_name) {
pr_err("Invalid subsystem name.\n");
@@ -465,6 +505,11 @@
return -EINVAL;
}
+#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:
@@ -473,11 +518,17 @@
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.",
subsys->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 f581c8f..b66c970 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -349,6 +349,17 @@
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 b47ca87..57d1790 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -98,7 +98,14 @@
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 4cf4670..1320c94 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -939,6 +939,9 @@
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);