diff options
Diffstat (limited to 'arch/arm/mach-exynos/sec_debug.c')
-rw-r--r-- | arch/arm/mach-exynos/sec_debug.c | 212 |
1 files changed, 193 insertions, 19 deletions
diff --git a/arch/arm/mach-exynos/sec_debug.c b/arch/arm/mach-exynos/sec_debug.c index 2e19097..78e2b4a 100644 --- a/arch/arm/mach-exynos/sec_debug.c +++ b/arch/arm/mach-exynos/sec_debug.c @@ -32,6 +32,9 @@ #include <asm/mach/map.h> #include <plat/regs-watchdog.h> +#if defined(CONFIG_SEC_MODEM_P8LTE) +#include <linux/miscdevice.h> +#endif /* klaatu - schedule log */ #ifdef CONFIG_SEC_DEBUG_SCHED_LOG #define SCHED_LOG_MAX 2048 @@ -54,12 +57,17 @@ struct sched_log { struct work_struct *work; work_func_t f; } work[NR_CPUS][SCHED_LOG_MAX]; + struct hrtimer_log { + unsigned long long time; + struct hrtimer *timer; + enum hrtimer_restart (*fn)(struct hrtimer *); + int en; + } hrtimers[NR_CPUS][8]; }; #endif /* CONFIG_SEC_DEBUG_SCHED_LOG */ #ifdef CONFIG_SEC_DEBUG_AUXILIARY_LOG #define AUX_LOG_CPU_CLOCK_MAX 64 -#define AUX_LOG_LOGBUF_LOCK_MAX 64 #define AUX_LOG_LENGTH 128 struct auxiliary_info { @@ -71,7 +79,6 @@ struct auxiliary_info { /* This structure will be modified if some other items added for log */ struct auxiliary_log { struct auxiliary_info CpuClockLog[AUX_LOG_CPU_CLOCK_MAX]; - struct auxiliary_info LogBufLockLog[AUX_LOG_LOGBUF_LOCK_MAX]; }; #else @@ -229,6 +236,7 @@ static struct sched_log sec_debug_log[NR_CPUS][SCHED_LOG_MAX] static atomic_t task_log_idx[NR_CPUS] = { ATOMIC_INIT(-1), ATOMIC_INIT(-1) }; static atomic_t irq_log_idx[NR_CPUS] = { ATOMIC_INIT(-1), ATOMIC_INIT(-1) }; static atomic_t work_log_idx[NR_CPUS] = { ATOMIC_INIT(-1), ATOMIC_INIT(-1) }; +static atomic_t hrtimer_log_idx[NR_CPUS] = { ATOMIC_INIT(-1), ATOMIC_INIT(-1) }; static struct sched_log (*psec_debug_log) = (&sec_debug_log); /* static struct sched_log (*psec_debug_log)[NR_CPUS][SCHED_LOG_MAX] @@ -242,7 +250,6 @@ static unsigned long long gExcpIrqExitTime[NR_CPUS]; static struct auxiliary_log gExcpAuxLog __cacheline_aligned; static struct auxiliary_log *gExcpAuxLogPtr; static atomic_t gExcpAuxCpuClockLogIdx = ATOMIC_INIT(-1); -static atomic_t gExcpAuxLogBufLockLogIdx = ATOMIC_INIT(-1); #endif static int checksum_sched_log(void) @@ -548,6 +555,62 @@ static inline void sec_debug_disable_watchdog(void) } #endif +#if defined(CONFIG_SEC_MODEM_P8LTE) +static void __iomem *idpram_base; +void sec_set_cp_upload(void) +{ + unsigned int send_mail, wait_count; + volatile u16 *cp_dpram_mbx_BA;/*send mail box*/ + volatile u16 *cp_dpram_mbx_AB;/*receive mail box*/ + + cp_dpram_mbx_BA = (volatile u16 *)(idpram_base + 0x3FFC); + cp_dpram_mbx_AB = (volatile u16 *)(idpram_base + 0x3FFE); + + send_mail = 0xc9; /*KERNEL_SEC_DUMP_AP_DEAD_INDICATOR_DPRAM*/ + + *cp_dpram_mbx_BA = send_mail; + + pr_err("%s : set cp upload mode, MailboxBA 0x%x\n", + __func__, send_mail); + + wait_count = 0; + while (1) { + if (*cp_dpram_mbx_AB == 0xc6) { + pr_err("%s - Done.\n", __func__); + break; + } + mdelay(10); + if (++wait_count > 2500) { + pr_err("%s - Fail to set CP uploadmode.\n", __func__); + break; + } + } + pr_err("%s : modem_wait_count : %d\n", __func__, wait_count); +} + +static struct miscdevice sec_cp_upload_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "cp_upload", +}; +static __init int sec_cp_upload_init(void) +{ + /*DPRAM_START_ADDRESS_PHYS + DPRAM_SHARED_BANK_SIZE*/ + idpram_base = ioremap_nocache(0x13A00000, 0x4000); + + if (idpram_base == NULL) + printk(KERN_ERR "%s : failed ioremap\n", __func__); + + return misc_register(&sec_cp_upload_dev); +} + +static __exit void sec_cp_upload_exit(void) +{ + misc_deregister(&sec_cp_upload_dev); +} + +module_init(sec_cp_upload_init); +module_exit(sec_cp_upload_exit); +#endif static int sec_debug_panic_handler(struct notifier_block *nb, unsigned long l, void *buf) { @@ -577,21 +640,63 @@ static int sec_debug_panic_handler(struct notifier_block *nb, show_state(); sec_debug_dump_stack(); +#if defined(CONFIG_SEC_MODEM_P8LTE) + sec_set_cp_upload(); +#endif sec_debug_hw_reset(); return 0; } +#if defined(CONFIG_MACH_Q1_BD) +/* + * This function can be used while current pointer is invalid. + */ +int sec_debug_panic_handler_safe(void *buf) +{ + local_irq_disable(); + + sec_debug_set_upload_magic(0x66262564, buf); + + sec_debug_set_upload_cause(UPLOAD_CAUSE_KERNEL_PANIC); + + pr_err("(%s) checksum_sched_log: %x\n", __func__, checksum_sched_log()); + + sec_debug_dump_stack(); + sec_debug_hw_reset(); + + return 0; +} +#endif + #ifdef CONFIG_SEC_DEBUG_FUPLOAD_DUMP_MORE static void dump_state_and_upload(void); #endif +#if !defined(CONFIG_TARGET_LOCALE_NA) void sec_debug_check_crash_key(unsigned int code, int value) { static bool volup_p; static bool voldown_p; static int loopcount; + /* In Case of GC1, + * use Tele key as Volume up, + * use Wide key as volume down. + */ +#ifdef CONFIG_MACH_GC1 + static unsigned int VOLUME_UP = 0x221; + static unsigned int VOLUME_DOWN = 0x222; + + if (system_rev < 2) { + VOLUME_UP = KEY_CAMERA_ZOOMIN; + VOLUME_DOWN = KEY_CAMERA_ZOOMOUT; + } +#else + static const unsigned int VOLUME_UP = KEY_VOLUMEUP; + static const unsigned int VOLUME_DOWN = KEY_VOLUMEDOWN; +#endif + if (!sec_debug_level.en.kernel_fault) return; @@ -607,9 +712,9 @@ void sec_debug_check_crash_key(unsigned int code, int value) * and volume up key should not be pressed */ if (value) { - if (code == KEY_VOLUMEUP) + if (code == VOLUME_UP) volup_p = true; - if (code == KEY_VOLUMEDOWN) + if (code == VOLUME_DOWN) voldown_p = true; if (!volup_p && voldown_p) { if (code == KEY_POWER) { @@ -629,14 +734,73 @@ void sec_debug_check_crash_key(unsigned int code, int value) } } } else { - if (code == KEY_VOLUMEUP) + if (code == VOLUME_UP) volup_p = false; - if (code == KEY_VOLUMEDOWN) { + if (code == VOLUME_DOWN) { loopcount = 0; voldown_p = false; } } } +#else +static struct hrtimer upload_start_timer; + +static enum hrtimer_restart force_upload_timer_func(struct hrtimer *timer) +{ + panic("Crash Key"); + + return HRTIMER_NORESTART; +} + +/* Volume UP + Volume Down = Force Upload Mode + 1. check for VOL_UP and VOL_DOWN + 2. if both key pressed start a timer with timeout period 3s + 3. if any one of two keys is released before 3s disable timer. */ +void sec_debug_check_crash_key(unsigned int code, int value) +{ + static bool vol_up, vol_down, check; + + if (!sec_debug_level.en.kernel_fault) + return; + + if ((code == KEY_VOLUMEUP) || (code == KEY_VOLUMEDOWN)) { + if (value) { + if (code == KEY_VOLUMEUP) + vol_up = true; + + if (code == KEY_VOLUMEDOWN) + vol_down = true; + + if (vol_up == true && vol_down == true) { + hrtimer_start(&upload_start_timer, + ktime_set(3, 0), + HRTIMER_MODE_REL); + check = true; + } + } else { + if (vol_up == true) + vol_up = false; + if (vol_down == true) + vol_down = false; + if (check) { + hrtimer_cancel(&upload_start_timer); + check = 0; + } + } + } +} + +static int __init upload_timer_init(void) +{ + hrtimer_init(&upload_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + upload_start_timer.function = force_upload_timer_func; + return 0; +} + +/* this should be initialized prior to keypad driver */ +early_initcall(upload_timer_init); + +#endif static struct notifier_block nb_reboot_block = { .notifier_call = sec_debug_normal_reboot_handler @@ -719,7 +883,8 @@ void __sec_debug_task_log(int cpu, struct task_struct *task) { unsigned i; - i = atomic_inc_return(&task_log_idx[cpu]) & (SCHED_LOG_MAX - 1); + i = atomic_inc_return(&task_log_idx[cpu]) & + (ARRAY_SIZE(psec_debug_log->task[0]) - 1); psec_debug_log->task[cpu][i].time = cpu_clock(cpu); strcpy(psec_debug_log->task[cpu][i].comm, task->comm); psec_debug_log->task[cpu][i].pid = task->pid; @@ -730,7 +895,8 @@ void __sec_debug_irq_log(unsigned int irq, void *fn, int en) int cpu = raw_smp_processor_id(); unsigned i; - i = atomic_inc_return(&irq_log_idx[cpu]) & (SCHED_LOG_MAX - 1); + i = atomic_inc_return(&irq_log_idx[cpu]) & + (ARRAY_SIZE(psec_debug_log->irq[0]) - 1); psec_debug_log->irq[cpu][i].time = cpu_clock(cpu); psec_debug_log->irq[cpu][i].irq = irq; psec_debug_log->irq[cpu][i].fn = (void *)fn; @@ -743,13 +909,28 @@ void __sec_debug_work_log(struct worker *worker, int cpu = raw_smp_processor_id(); unsigned i; - i = atomic_inc_return(&work_log_idx[cpu]) & (SCHED_LOG_MAX - 1); + i = atomic_inc_return(&work_log_idx[cpu]) & + (ARRAY_SIZE(psec_debug_log->work[0]) - 1); psec_debug_log->work[cpu][i].time = cpu_clock(cpu); psec_debug_log->work[cpu][i].worker = worker; psec_debug_log->work[cpu][i].work = work; psec_debug_log->work[cpu][i].f = f; } +void __sec_debug_hrtimer_log(struct hrtimer *timer, + enum hrtimer_restart (*fn) (struct hrtimer *), int en) +{ + int cpu = raw_smp_processor_id(); + unsigned i; + + i = atomic_inc_return(&hrtimer_log_idx[cpu]) & + (ARRAY_SIZE(psec_debug_log->hrtimers[0]) - 1); + psec_debug_log->hrtimers[cpu][i].time = cpu_clock(cpu); + psec_debug_log->hrtimers[cpu][i].timer = timer; + psec_debug_log->hrtimers[cpu][i].fn = fn; + psec_debug_log->hrtimers[cpu][i].en = en; +} + #ifdef CONFIG_SEC_DEBUG_IRQ_EXIT_LOG void sec_debug_irq_last_exit_log(void) { @@ -783,14 +964,6 @@ void sec_debug_aux_log(int idx, char *fmt, ...) strncpy((*gExcpAuxLogPtr).CpuClockLog[i].log, buf, AUX_LOG_LENGTH); break; - case SEC_DEBUG_AUXLOG_LOGBUF_LOCK_CHANGE: - i = atomic_inc_return(&gExcpAuxLogBufLockLogIdx) - & (AUX_LOG_LOGBUF_LOCK_MAX - 1); - (*gExcpAuxLogPtr).LogBufLockLog[i].time = cpu_clock(cpu); - (*gExcpAuxLogPtr).LogBufLockLog[i].cpu = cpu; - strncpy((*gExcpAuxLogPtr).LogBufLockLog[i].log, - buf, AUX_LOG_LENGTH); - break; default: break; } @@ -981,7 +1154,7 @@ static int __init sec_debug_user_fault_init(void) { struct proc_dir_entry *entry; - entry = proc_create("user_fault", S_IWUGO, NULL, + entry = proc_create("user_fault", S_IWUSR | S_IWGRP, NULL, &sec_user_fault_proc_fops); if (!entry) return -ENOMEM; @@ -999,6 +1172,7 @@ int sec_debug_magic_init(void) } pr_info("%s: success reserving magic code area\n", __func__); + return 0; } |