From 1d1107d430eb0a314f69d0243cf0253387212ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Mon, 27 Sep 2010 17:50:00 -0700 Subject: ARM: Add fiq_glue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I27d2554e07d9de204e0a06696d38db51608d9f6b Signed-off-by: Arve Hjønnevåg Signed-off-by: Colin Cross --- arch/arm/common/Kconfig | 4 ++ arch/arm/common/Makefile | 1 + arch/arm/common/fiq_glue.S | 111 +++++++++++++++++++++++++++++++++++++++ arch/arm/common/fiq_glue_setup.c | 92 ++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 arch/arm/common/fiq_glue.S create mode 100644 arch/arm/common/fiq_glue_setup.c (limited to 'arch/arm/common') diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 4b71766fb21d..897b3fbe6e33 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -39,3 +39,7 @@ config SHARP_PARAM config SHARP_SCOOP bool + +config FIQ_GLUE + bool + select FIQ diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 6ea9b6f3607a..0ca99bbe9d84 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_ARCH_IXP2000) += uengine.o obj-$(CONFIG_ARCH_IXP23XX) += uengine.o obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o +obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o diff --git a/arch/arm/common/fiq_glue.S b/arch/arm/common/fiq_glue.S new file mode 100644 index 000000000000..9e3455a09f8f --- /dev/null +++ b/arch/arm/common/fiq_glue.S @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008 Google, 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 + + .text + + .global fiq_glue_end + + /* fiq stack: r0-r15,cpsr,spsr of interrupted mode */ + +ENTRY(fiq_glue) + /* store pc, cpsr from previous mode */ + mrs r12, spsr + sub r11, lr, #4 + subs r10, #1 + bne nested_fiq + + stmfd sp!, {r11-r12, lr} + + /* store r8-r14 from previous mode */ + sub sp, sp, #(7 * 4) + stmia sp, {r8-r14}^ + nop + + /* store r0-r7 from previous mode */ + stmfd sp!, {r0-r7} + + /* setup func(data,regs) arguments */ + mov r0, r9 + mov r1, sp + mov r3, r8 + + mov r7, sp + + /* Get sp and lr from non-user modes */ + and r4, r12, #MODE_MASK + cmp r4, #USR_MODE + beq fiq_from_usr_mode + + mov r7, sp + orr r4, r4, #(PSR_I_BIT | PSR_F_BIT) + msr cpsr_c, r4 + str sp, [r7, #(4 * 13)] + str lr, [r7, #(4 * 14)] + mrs r5, spsr + str r5, [r7, #(4 * 17)] + + cmp r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) + /* use fiq stack if we reenter this mode */ + subne sp, r7, #(4 * 3) + +fiq_from_usr_mode: + msr cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) + mov r2, sp + sub sp, r7, #12 + stmfd sp!, {r2, ip, lr} + /* call func(data,regs) */ + blx r3 + ldmfd sp, {r2, ip, lr} + mov sp, r2 + + /* restore/discard saved state */ + cmp r4, #USR_MODE + beq fiq_from_usr_mode_exit + + msr cpsr_c, r4 + ldr sp, [r7, #(4 * 13)] + ldr lr, [r7, #(4 * 14)] + msr spsr_cxsf, r5 + +fiq_from_usr_mode_exit: + msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) + + ldmfd sp!, {r0-r7} + add sp, sp, #(7 * 4) + ldmfd sp!, {r11-r12, lr} +exit_fiq: + msr spsr_cxsf, r12 + add r10, #1 + movs pc, r11 + +nested_fiq: + orr r12, r12, #(PSR_F_BIT) + b exit_fiq + +fiq_glue_end: + +ENTRY(fiq_glue_setup) /* func, data, sp */ + mrs r3, cpsr + msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) + movs r8, r0 + mov r9, r1 + mov sp, r2 + moveq r10, #0 + movne r10, #1 + msr cpsr_c, r3 + bx lr + diff --git a/arch/arm/common/fiq_glue_setup.c b/arch/arm/common/fiq_glue_setup.c new file mode 100644 index 000000000000..f878ea079b4d --- /dev/null +++ b/arch/arm/common/fiq_glue_setup.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010 Google, 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 + +extern unsigned char fiq_glue, fiq_glue_end; +extern void fiq_glue_setup(void *func, void *data, void *sp); + +static struct fiq_handler fiq_debbuger_fiq_handler = { + .name = "fiq_glue", +}; +static __percpu void *fiq_stack; +static struct fiq_glue_handler *current_handler; +static DEFINE_MUTEX(fiq_glue_lock); + +static void fiq_glue_setup_helper(void *info) +{ + struct fiq_glue_handler *handler = info; + fiq_glue_setup(handler->fiq, handler, + __this_cpu_ptr(fiq_stack) + THREAD_START_SP); +} + +int fiq_glue_register_handler(struct fiq_glue_handler *handler) +{ + int ret; + + if (!handler || !handler->fiq) + return -EINVAL; + + mutex_lock(&fiq_glue_lock); + if (fiq_stack) { + ret = -EBUSY; + goto err_busy; + } + + fiq_stack = __alloc_percpu(THREAD_SIZE, L1_CACHE_BYTES); + if (WARN_ON(!fiq_stack)) { + ret = -ENOMEM; + goto err_alloc_fiq_stack; + } + + ret = claim_fiq(&fiq_debbuger_fiq_handler); + if (WARN_ON(ret)) + goto err_claim_fiq; + + current_handler = handler; + on_each_cpu(fiq_glue_setup_helper, handler, true); + set_fiq_handler(&fiq_glue, &fiq_glue_end - &fiq_glue); + +err_claim_fiq: + if (ret) { + free_percpu(fiq_stack); + fiq_stack = NULL; + } +err_alloc_fiq_stack: +err_busy: + mutex_unlock(&fiq_glue_lock); + return ret; +} + +/** + * fiq_glue_resume - Restore fiqs after suspend or low power idle states + * + * This must be called before calling local_fiq_enable after returning from a + * power state where the fiq mode registers were lost. If a driver provided + * a resume hook when it registered the handler it will be called. + */ + +void fiq_glue_resume(void) +{ + if (!current_handler) + return; + fiq_glue_setup(current_handler->fiq, current_handler, + __this_cpu_ptr(fiq_stack) + THREAD_START_SP); + if (current_handler->resume) + current_handler->resume(current_handler); +} + -- cgit v1.2.3 From 94f389d3ac73b32b32de93a34a035736391305e5 Mon Sep 17 00:00:00 2001 From: Iliyan Malchev Date: Sat, 5 Jun 2010 17:36:24 -0700 Subject: ARM: Add generic fiq serial debugger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ibb536c88f0dbaf4766d0599296907e35e42cbfd6 Signed-off-by: Iliyan Malchev Signed-off-by: Arve Hjønnevåg --- arch/arm/common/Kconfig | 31 ++ arch/arm/common/Makefile | 1 + arch/arm/common/fiq_debugger.c | 680 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 712 insertions(+) create mode 100644 arch/arm/common/fiq_debugger.c (limited to 'arch/arm/common') diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 897b3fbe6e33..8ee3288a4b0a 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -43,3 +43,34 @@ config SHARP_SCOOP config FIQ_GLUE bool select FIQ + +config FIQ_DEBUGGER + bool "FIQ Mode Serial Debugger" + select FIQ + select FIQ_GLUE + select KERNEL_DEBUGGER_CORE + default n + help + The FIQ serial debugger can accept commands even when the + kernel is unresponsive due to being stuck with interrupts + disabled. Depends on the kernel debugger core in drivers/misc. + + +config FIQ_DEBUGGER_NO_SLEEP + bool "Keep serial debugger active" + depends on FIQ_DEBUGGER + default n + help + Enables the serial debugger at boot. Passing + fiq_debugger.no_sleep on the kernel commandline will + override this config option. + +config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON + bool "Don't disable wakeup IRQ when debugger is active" + depends on FIQ_DEBUGGER + default n + help + Don't disable the wakeup irq when enabling the uart clock. This will + cause extra interrupts, but it makes the serial debugger usable with + on some MSM radio builds that ignore the uart clock request in power + collapse. diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 0ca99bbe9d84..3ab5d765fedd 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_ARCH_IXP23XX) += uengine.o obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o +obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger.o diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c new file mode 100644 index 000000000000..c4679a16f340 --- /dev/null +++ b/arch/arm/common/fiq_debugger.c @@ -0,0 +1,680 @@ +/* + * arch/arm/common/fiq_debugger.c + * + * Serial Debugger Interface accessed through an FIQ interrupt. + * + * Copyright (C) 2008 Google, 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 +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#define DEBUG_MAX 64 + +struct fiq_debugger_state { + struct fiq_glue_handler handler; + + int fiq; + int signal_irq; + int wakeup_irq; + bool wakeup_irq_no_set_wake; + struct clk *clk; + struct fiq_debugger_pdata *pdata; + struct platform_device *pdev; + + char debug_cmd[DEBUG_MAX]; + int debug_busy; + int debug_abort; + + char debug_buf[DEBUG_MAX]; + int debug_count; + + bool no_sleep; + bool debug_enable; + bool ignore_next_wakeup_irq; + struct timer_list sleep_timer; + bool uart_clk_enabled; + struct wake_lock debugger_wake_lock; + + unsigned int last_irqs[NR_IRQS]; +}; + +#ifdef CONFIG_FIQ_DEBUGGER_NO_SLEEP +static bool initial_no_sleep = true; +#else +static bool initial_no_sleep; +#endif +static bool initial_debug_enable; + +module_param_named(no_sleep, initial_no_sleep, bool, 0644); +module_param_named(debug_enable, initial_debug_enable, bool, 0644); + +#ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON +static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {} +static inline void disable_wakeup_irq(struct fiq_debugger_state *state) {} +#else +static inline void enable_wakeup_irq(struct fiq_debugger_state *state) +{ + if (state->wakeup_irq < 0) + return; + enable_irq(state->wakeup_irq); + if (!state->wakeup_irq_no_set_wake) + enable_irq_wake(state->wakeup_irq); +} +static inline void disable_wakeup_irq(struct fiq_debugger_state *state) +{ + if (state->wakeup_irq < 0) + return; + disable_irq_nosync(state->wakeup_irq); + if (!state->wakeup_irq_no_set_wake) + disable_irq_wake(state->wakeup_irq); +} +#endif + +static void debug_force_irq(struct fiq_debugger_state *state) +{ + unsigned int irq = state->signal_irq; + if (state->pdata->force_irq) + state->pdata->force_irq(state->pdev, irq); + else { + struct irq_chip *chip = get_irq_chip(irq); + if (chip && chip->retrigger) + chip->retrigger(irq); + } +} + +static void debug_uart_flush(struct fiq_debugger_state *state) +{ + if (state->pdata->uart_flush) + state->pdata->uart_flush(state->pdev); +} + +static void debug_puts(struct fiq_debugger_state *state, char *s) +{ + unsigned c; + while ((c = *s++)) { + if (c == '\n') + state->pdata->uart_putc(state->pdev, '\r'); + state->pdata->uart_putc(state->pdev, c); + } +} + +static void debug_prompt(struct fiq_debugger_state *state) +{ + debug_puts(state, "debug> "); +} + +int log_buf_copy(char *dest, int idx, int len); +static void dump_kernel_log(struct fiq_debugger_state *state) +{ + char buf[1024]; + int idx = 0; + int ret; + int saved_oip; + + /* setting oops_in_progress prevents log_buf_copy() + * from trying to take a spinlock which will make it + * very unhappy in some cases... + */ + saved_oip = oops_in_progress; + oops_in_progress = 1; + for (;;) { + ret = log_buf_copy(buf, idx, 1023); + if (ret <= 0) + break; + buf[ret] = 0; + debug_puts(state, buf); + idx += ret; + } + oops_in_progress = saved_oip; +} + +static char *mode_name(unsigned cpsr) +{ + switch (cpsr & MODE_MASK) { + case USR_MODE: return "USR"; + case FIQ_MODE: return "FIQ"; + case IRQ_MODE: return "IRQ"; + case SVC_MODE: return "SVC"; + case ABT_MODE: return "ABT"; + case UND_MODE: return "UND"; + case SYSTEM_MODE: return "SYS"; + default: return "???"; + } +} + +static int debug_printf(void *cookie, const char *fmt, ...) +{ + struct fiq_debugger_state *state = cookie; + char buf[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + debug_puts(state, buf); + return state->debug_abort; +} + +/* Safe outside fiq context */ +static int debug_printf_nfiq(void *cookie, const char *fmt, ...) +{ + struct fiq_debugger_state *state = cookie; + char buf[256]; + va_list ap; + unsigned long irq_flags; + + va_start(ap, fmt); + vsnprintf(buf, 128, fmt, ap); + va_end(ap); + + local_irq_save(irq_flags); + debug_puts(state, buf); + debug_uart_flush(state); + local_irq_restore(irq_flags); + return state->debug_abort; +} + +static void dump_regs(struct fiq_debugger_state *state, unsigned *regs) +{ + debug_printf(state, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + regs[0], regs[1], regs[2], regs[3]); + debug_printf(state, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + regs[4], regs[5], regs[6], regs[7]); + debug_printf(state, " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", + regs[8], regs[9], regs[10], regs[11], + mode_name(regs[16])); + if ((regs[16] & MODE_MASK) == USR_MODE) + debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " + "cpsr %08x\n", regs[12], regs[13], regs[14], + regs[15], regs[16]); + else + debug_printf(state, " ip %08x sp %08x lr %08x pc %08x " + "cpsr %08x spsr %08x\n", regs[12], regs[13], + regs[14], regs[15], regs[16], regs[17]); +} + +struct mode_regs { + unsigned long sp_svc; + unsigned long lr_svc; + unsigned long spsr_svc; + + unsigned long sp_abt; + unsigned long lr_abt; + unsigned long spsr_abt; + + unsigned long sp_und; + unsigned long lr_und; + unsigned long spsr_und; + + unsigned long sp_irq; + unsigned long lr_irq; + unsigned long spsr_irq; + + unsigned long r8_fiq; + unsigned long r9_fiq; + unsigned long r10_fiq; + unsigned long r11_fiq; + unsigned long r12_fiq; + unsigned long sp_fiq; + unsigned long lr_fiq; + unsigned long spsr_fiq; +}; + +void __naked get_mode_regs(struct mode_regs *regs) +{ + asm volatile ( + "mrs r1, cpsr\n" + "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r13 - r14}\n" + "mrs r2, spsr\n" + "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" + "stmia r0!, {r2, r8 - r14}\n" + "mrs r2, spsr\n" + "stmia r0!, {r2}\n" + "msr cpsr_c, r1\n" + "bx lr\n"); +} + + +static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs) +{ + struct mode_regs mode_regs; + dump_regs(state, regs); + get_mode_regs(&mode_regs); + debug_printf(state, " svc: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); + debug_printf(state, " abt: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); + debug_printf(state, " und: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); + debug_printf(state, " irq: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); + debug_printf(state, " fiq: r8 %08x r9 %08x r10 %08x r11 %08x " + "r12 %08x\n", + mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, + mode_regs.r11_fiq, mode_regs.r12_fiq); + debug_printf(state, " fiq: sp %08x lr %08x spsr %08x\n", + mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); +} + +static void dump_irqs(struct fiq_debugger_state *state) +{ + int n; + debug_printf(state, "irqnr total since-last status name\n"); + for (n = 0; n < NR_IRQS; n++) { + struct irqaction *act = irq_desc[n].action; + if (!act && !kstat_irqs(n)) + continue; + debug_printf(state, "%5d: %10u %11u %8x %s\n", n, + kstat_irqs(n), + kstat_irqs(n) - state->last_irqs[n], + irq_desc[n].status, + (act && act->name) ? act->name : "???"); + state->last_irqs[n] = kstat_irqs(n); + } +} + +struct stacktrace_state { + struct fiq_debugger_state *state; + unsigned int depth; +}; + +static int report_trace(struct stackframe *frame, void *d) +{ + struct stacktrace_state *sts = d; + + if (sts->depth) { + debug_printf(sts->state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + frame->pc, frame->pc, frame->lr, frame->lr, + frame->sp, frame->fp); + sts->depth--; + return 0; + } + debug_printf(sts->state, " ...\n"); + + return sts->depth == 0; +} + +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + +static struct frame_tail *user_backtrace(struct fiq_debugger_state *state, + struct frame_tail *tail) +{ + struct frame_tail buftail[2]; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { + debug_printf(state, " invalid frame pointer %p\n", tail); + return NULL; + } + if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { + debug_printf(state, + " failed to copy frame pointer %p\n", tail); + return NULL; + } + + debug_printf(state, " %p\n", buftail[0].lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= buftail[0].fp) + return NULL; + + return buftail[0].fp-1; +} + +void dump_stacktrace(struct fiq_debugger_state *state, + struct pt_regs * const regs, unsigned int depth, void *ssp) +{ + struct frame_tail *tail; + struct thread_info *real_thread_info = (struct thread_info *) + ((unsigned long)ssp & ~(THREAD_SIZE - 1)); + struct stacktrace_state sts; + + sts.depth = depth; + sts.state = state; + *current_thread_info() = *real_thread_info; + + if (!current) + debug_printf(state, "current NULL\n"); + else + debug_printf(state, "pid: %d comm: %s\n", + current->pid, current->comm); + dump_regs(state, (unsigned *)regs); + + if (!user_mode(regs)) { + struct stackframe frame; + frame.fp = regs->ARM_fp; + frame.sp = regs->ARM_sp; + frame.lr = regs->ARM_lr; + frame.pc = regs->ARM_pc; + debug_printf(state, + " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", + regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, + regs->ARM_sp, regs->ARM_fp); + walk_stackframe(&frame, report_trace, &sts); + return; + } + + tail = ((struct frame_tail *) regs->ARM_fp) - 1; + while (depth-- && tail && !((unsigned long) tail & 3)) + tail = user_backtrace(state, tail); +} + +static void debug_exec(struct fiq_debugger_state *state, + const char *cmd, unsigned *regs, void *svc_sp) +{ + if (!strcmp(cmd, "pc")) { + debug_printf(state, " pc %08x cpsr %08x mode %s\n", + regs[15], regs[16], mode_name(regs[16])); + } else if (!strcmp(cmd, "regs")) { + dump_regs(state, regs); + } else if (!strcmp(cmd, "allregs")) { + dump_allregs(state, regs); + } else if (!strcmp(cmd, "bt")) { + dump_stacktrace(state, (struct pt_regs *)regs, 100, svc_sp); + } else if (!strcmp(cmd, "reboot")) { + arch_reset(0, 0); + } else if (!strcmp(cmd, "irqs")) { + dump_irqs(state); + } else if (!strcmp(cmd, "kmsg")) { + dump_kernel_log(state); + } else if (!strcmp(cmd, "version")) { + debug_printf(state, "%s\n", linux_banner); + } else if (!strcmp(cmd, "sleep")) { + state->no_sleep = false; + } else if (!strcmp(cmd, "nosleep")) { + state->no_sleep = true; + } else { + if (state->debug_busy) { + debug_printf(state, + "command processor busy. trying to abort.\n"); + state->debug_abort = -1; + } else { + strcpy(state->debug_cmd, cmd); + state->debug_busy = 1; + } + + debug_force_irq(state); + + return; + } + debug_prompt(state); +} + +static void sleep_timer_expired(unsigned long data) +{ + struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; + + if (state->uart_clk_enabled && !state->no_sleep) { + if (state->debug_enable) { + state->debug_enable = false; + debug_printf_nfiq(state, "suspending fiq debugger\n"); + } + state->ignore_next_wakeup_irq = true; + if (state->clk) + clk_disable(state->clk); + state->uart_clk_enabled = false; + enable_wakeup_irq(state); + } + wake_unlock(&state->debugger_wake_lock); +} + +static irqreturn_t wakeup_irq_handler(int irq, void *dev) +{ + struct fiq_debugger_state *state = dev; + + if (!state->no_sleep) + debug_puts(state, "WAKEUP\n"); + if (state->ignore_next_wakeup_irq) + state->ignore_next_wakeup_irq = false; + else if (!state->uart_clk_enabled) { + wake_lock(&state->debugger_wake_lock); + if (state->clk) + clk_enable(state->clk); + state->uart_clk_enabled = true; + disable_wakeup_irq(state); + mod_timer(&state->sleep_timer, jiffies + HZ / 2); + } + return IRQ_HANDLED; +} + +static irqreturn_t debug_irq(int irq, void *dev) +{ + struct fiq_debugger_state *state = dev; + if (state->pdata->force_irq_ack) + state->pdata->force_irq_ack(state->pdev, state->signal_irq); + + if (!state->no_sleep) { + wake_lock(&state->debugger_wake_lock); + mod_timer(&state->sleep_timer, jiffies + HZ * 5); + } + if (state->debug_busy) { + struct kdbg_ctxt ctxt; + + ctxt.printf = debug_printf_nfiq; + ctxt.cookie = state; + kernel_debugger(&ctxt, state->debug_cmd); + debug_prompt(state); + + state->debug_busy = 0; + } + return IRQ_HANDLED; +} + +static int debug_getc(struct fiq_debugger_state *state) +{ + return state->pdata->uart_getc(state->pdev); +} + +static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) +{ + struct fiq_debugger_state *state = + container_of(h, struct fiq_debugger_state, handler); + int c; + static int last_c; + int count = 0; + + while ((c = debug_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { + count++; + if (!state->debug_enable) { + if ((c == 13) || (c == 10)) { + state->debug_enable = true; + state->debug_count = 0; + debug_prompt(state); + } + } else if ((c >= ' ') && (c < 127)) { + if (state->debug_count < (DEBUG_MAX - 1)) { + state->debug_buf[state->debug_count++] = c; + state->pdata->uart_putc(state->pdev, c); + } + } else if ((c == 8) || (c == 127)) { + if (state->debug_count > 0) { + state->debug_count--; + state->pdata->uart_putc(state->pdev, 8); + state->pdata->uart_putc(state->pdev, ' '); + state->pdata->uart_putc(state->pdev, 8); + } + } else if ((c == 13) || (c == 10)) { + if (c == '\r' || (c == '\n' && last_c != '\r')) { + state->pdata->uart_putc(state->pdev, '\r'); + state->pdata->uart_putc(state->pdev, '\n'); + } + if (state->debug_count) { + state->debug_buf[state->debug_count] = 0; + state->debug_count = 0; + debug_exec(state, state->debug_buf, + regs, svc_sp); + } else { + debug_prompt(state); + } + } + last_c = c; + } + debug_uart_flush(state); + if (state->pdata->fiq_ack) + state->pdata->fiq_ack(state->pdev, state->fiq); + + /* poke sleep timer if necessary */ + if (state->debug_enable && !state->no_sleep) + debug_force_irq(state); +} + +static void debug_resume(struct fiq_glue_handler *h) +{ + struct fiq_debugger_state *state = + container_of(h, struct fiq_debugger_state, handler); + if (state->pdata->uart_resume) + state->pdata->uart_resume(state->pdev); +} + +static int fiq_debugger_probe(struct platform_device *pdev) +{ + int ret; + struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev); + struct fiq_debugger_state *state; + + if (!pdata->uart_getc || !pdata->uart_putc || !pdata->fiq_enable) + return -EINVAL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + state->handler.fiq = debug_fiq; + state->handler.resume = debug_resume; + setup_timer(&state->sleep_timer, sleep_timer_expired, + (unsigned long)state); + state->pdata = pdata; + state->pdev = pdev; + state->no_sleep = initial_no_sleep; + state->debug_enable = initial_debug_enable; + + state->fiq = platform_get_irq_byname(pdev, "fiq"); + state->signal_irq = platform_get_irq_byname(pdev, "signal"); + state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); + + if (state->wakeup_irq < 0) + state->no_sleep = true; + state->ignore_next_wakeup_irq = !state->no_sleep; + + wake_lock_init(&state->debugger_wake_lock, + WAKE_LOCK_SUSPEND, "serial-debug"); + + state->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(state->clk)) + state->clk = NULL; + + if (state->clk) + clk_enable(state->clk); + + if (pdata->uart_init) { + ret = pdata->uart_init(pdev); + if (ret) + goto err_uart_init; + } + + debug_printf_nfiq(state, "\n", + state->no_sleep ? "" : "twice "); + + ret = fiq_glue_register_handler(&state->handler); + if (ret) { + pr_err("serial_debugger: could not install fiq handler\n"); + goto err_register_fiq; + } + + pdata->fiq_enable(pdev, state->fiq, 1); + + if (state->clk) + clk_disable(state->clk); + + ret = request_irq(state->signal_irq, debug_irq, + IRQF_TRIGGER_RISING, "debug", state); + if (ret) + pr_err("serial_debugger: could not install signal_irq"); + + if (state->wakeup_irq >= 0) { + ret = request_irq(state->wakeup_irq, wakeup_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_DISABLED, + "debug-wakeup", state); + if (ret) { + pr_err("serial_debugger: " + "could not install wakeup irq\n"); + state->wakeup_irq = -1; + } else { + ret = enable_irq_wake(state->wakeup_irq); + if (ret) { + pr_err("serial_debugger: " + "could not enable wakeup\n"); + state->wakeup_irq_no_set_wake = true; + } + } + } + if (state->no_sleep) + wakeup_irq_handler(state->wakeup_irq, state); + + return 0; + +err_register_fiq: + if (pdata->uart_free) + pdata->uart_free(pdev); +err_uart_init: + kfree(state); + if (state->clk) + clk_put(state->clk); + return ret; +} + +static struct platform_driver fiq_debugger_driver = { + .probe = fiq_debugger_probe, + .driver.name = "fiq_debugger", +}; + +static int __init fiq_debugger_init(void) +{ + return platform_driver_register(&fiq_debugger_driver); +} + +postcore_initcall(fiq_debugger_init); -- cgit v1.2.3 From ce7f1774367b262e7142c88a6e3ca504810d67ef Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 16 Aug 2010 14:51:51 -0700 Subject: ARM: fiq debugger: Add tty to fiq debugger Change-Id: I80347cdb70cda104b96562c63f972c1f217e3822 Signed-off-by: Colin Cross --- arch/arm/common/Kconfig | 8 ++ arch/arm/common/fiq_debugger.c | 182 ++++++++++++++++++++++++++++++++- arch/arm/common/fiq_debugger_ringbuf.h | 94 +++++++++++++++++ 3 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 arch/arm/common/fiq_debugger_ringbuf.h (limited to 'arch/arm/common') diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index 8ee3288a4b0a..cbf3b84f90bd 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -74,3 +74,11 @@ config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON cause extra interrupts, but it makes the serial debugger usable with on some MSM radio builds that ignore the uart clock request in power collapse. + +config FIQ_DEBUGGER_CONSOLE + bool "Console on FIQ Serial Debugger port" + depends on FIQ_DEBUGGER + default n + help + Enables a console so that printk messages are displayed on + the debugger serial port as the occur. diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index c4679a16f340..1ba345d441d0 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -38,6 +41,8 @@ #include +#include "fiq_debugger_ringbuf.h" + #define DEBUG_MAX 64 struct fiq_debugger_state { @@ -64,6 +69,15 @@ struct fiq_debugger_state { struct timer_list sleep_timer; bool uart_clk_enabled; struct wake_lock debugger_wake_lock; + bool console_enable; + +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE + struct console console; + struct tty_driver *tty_driver; + struct tty_struct *tty; + int tty_open_count; + struct fiq_debugger_ringbuf *tty_rbuf; +#endif unsigned int last_irqs[NR_IRQS]; }; @@ -74,9 +88,11 @@ static bool initial_no_sleep = true; static bool initial_no_sleep; #endif static bool initial_debug_enable; +static bool initial_console_enable; module_param_named(no_sleep, initial_no_sleep, bool, 0644); module_param_named(debug_enable, initial_debug_enable, bool, 0644); +module_param_named(console_enable, initial_console_enable, bool, 0644); #ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {} @@ -430,6 +446,9 @@ static void debug_exec(struct fiq_debugger_state *state, state->no_sleep = false; } else if (!strcmp(cmd, "nosleep")) { state->no_sleep = true; + } else if (!strcmp(cmd, "console")) { + state->console_enable = true; + debug_printf(state, "console mode\n"); } else { if (state->debug_busy) { debug_printf(state, @@ -444,7 +463,8 @@ static void debug_exec(struct fiq_debugger_state *state, return; } - debug_prompt(state); + if (!state->console_enable) + debug_prompt(state); } static void sleep_timer_expired(unsigned long data) @@ -494,6 +514,19 @@ static irqreturn_t debug_irq(int irq, void *dev) wake_lock(&state->debugger_wake_lock); mod_timer(&state->sleep_timer, jiffies + HZ * 5); } +#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) + if (state->tty) { + int i; + int count = fiq_debugger_ringbuf_level(state->tty_rbuf); + for (i = 0; i < count; i++) { + int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, i); + tty_insert_flip_char(state->tty, c, TTY_NORMAL); + if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1)) + pr_warn("fiq tty failed to consume byte\n"); + } + tty_flip_buffer_push(state->tty); + } +#endif if (state->debug_busy) { struct kdbg_ctxt ctxt; @@ -528,6 +561,16 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) state->debug_count = 0; debug_prompt(state); } + } else if (c == FIQ_DEBUGGER_BREAK) { + state->console_enable = false; + debug_puts(state, "fiq debugger mode\n"); + state->debug_count = 0; + debug_prompt(state); +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE + } else if (state->console_enable && state->tty_rbuf) { + fiq_debugger_ringbuf_push(state->tty_rbuf, c); + debug_force_irq(state); +#endif } else if ((c >= ' ') && (c < 127)) { if (state->debug_count < (DEBUG_MAX - 1)) { state->debug_buf[state->debug_count++] = c; @@ -573,6 +616,137 @@ static void debug_resume(struct fiq_glue_handler *h) state->pdata->uart_resume(state->pdev); } +#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) +struct tty_driver *debug_console_device(struct console *co, int *index) +{ + struct fiq_debugger_state *state; + state = container_of(co, struct fiq_debugger_state, console); + *index = 0; + return state->tty_driver; +} + +static void debug_console_write(struct console *co, + const char *s, unsigned int count) +{ + struct fiq_debugger_state *state; + + state = container_of(co, struct fiq_debugger_state, console); + + if (!state->console_enable) + return; + + while (count--) { + if (*s == '\n') + state->pdata->uart_putc(state->pdev, '\r'); + state->pdata->uart_putc(state->pdev, *s++); + } + debug_uart_flush(state); +} + +static struct console fiq_debugger_console = { + .name = "ttyFIQ", + .device = debug_console_device, + .write = debug_console_write, + .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, +}; + +int fiq_tty_open(struct tty_struct *tty, struct file *filp) +{ + struct fiq_debugger_state *state = tty->driver->driver_state; + if (state->tty_open_count++) + return 0; + + tty->driver_data = state; + state->tty = tty; + return 0; +} + +void fiq_tty_close(struct tty_struct *tty, struct file *filp) +{ + struct fiq_debugger_state *state = tty->driver_data; + if (--state->tty_open_count) + return; + state->tty = NULL; +} + +int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + int i; + struct fiq_debugger_state *state = tty->driver_data; + + if (!state->console_enable) + return count; + + if (state->clk) + clk_enable(state->clk); + for (i = 0; i < count; i++) + state->pdata->uart_putc(state->pdev, *buf++); + if (state->clk) + clk_disable(state->clk); + + return count; +} + +int fiq_tty_write_room(struct tty_struct *tty) +{ + return 1024; +} + +static const struct tty_operations fiq_tty_driver_ops = { + .write = fiq_tty_write, + .write_room = fiq_tty_write_room, + .open = fiq_tty_open, + .close = fiq_tty_close, +}; + +static int fiq_debugger_tty_init(struct fiq_debugger_state *state) +{ + int ret = -EINVAL; + + state->tty_driver = alloc_tty_driver(1); + if (!state->tty_driver) { + pr_err("Failed to allocate fiq debugger tty\n"); + return -ENOMEM; + } + + state->tty_driver->owner = THIS_MODULE; + state->tty_driver->driver_name = "fiq-debugger"; + state->tty_driver->name = "ttyFIQ"; + state->tty_driver->type = TTY_DRIVER_TYPE_SERIAL; + state->tty_driver->subtype = SERIAL_TYPE_NORMAL; + state->tty_driver->init_termios = tty_std_termios; + state->tty_driver->init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; + state->tty_driver->init_termios.c_ispeed = + state->tty_driver->init_termios.c_ospeed = 115200; + state->tty_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(state->tty_driver, &fiq_tty_driver_ops); + state->tty_driver->driver_state = state; + + ret = tty_register_driver(state->tty_driver); + if (ret) { + pr_err("Failed to register fiq tty: %d\n", ret); + goto err; + } + + state->tty_rbuf = fiq_debugger_ringbuf_alloc(1024); + if (!state->tty_rbuf) { + pr_err("Failed to allocate fiq debugger ringbuf\n"); + ret = -ENOMEM; + goto err; + } + + pr_info("Registered FIQ tty driver %p\n", state->tty_driver); + return 0; + +err: + fiq_debugger_ringbuf_free(state->tty_rbuf); + state->tty_rbuf = NULL; + put_tty_driver(state->tty_driver); + return ret; +} +#endif + static int fiq_debugger_probe(struct platform_device *pdev) { int ret; @@ -591,6 +765,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) state->pdev = pdev; state->no_sleep = initial_no_sleep; state->debug_enable = initial_debug_enable; + state->console_enable = initial_console_enable; state->fiq = platform_get_irq_byname(pdev, "fiq"); state->signal_irq = platform_get_irq_byname(pdev, "signal"); @@ -655,6 +830,11 @@ static int fiq_debugger_probe(struct platform_device *pdev) if (state->no_sleep) wakeup_irq_handler(state->wakeup_irq, state); +#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) + state->console = fiq_debugger_console; + register_console(&state->console); + fiq_debugger_tty_init(state); +#endif return 0; err_register_fiq: diff --git a/arch/arm/common/fiq_debugger_ringbuf.h b/arch/arm/common/fiq_debugger_ringbuf.h new file mode 100644 index 000000000000..2649b5581088 --- /dev/null +++ b/arch/arm/common/fiq_debugger_ringbuf.h @@ -0,0 +1,94 @@ +/* + * arch/arm/common/fiq_debugger_ringbuf.c + * + * simple lockless ringbuffer + * + * Copyright (C) 2010 Google, 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 + +struct fiq_debugger_ringbuf { + int len; + int head; + int tail; + u8 buf[]; +}; + + +static inline struct fiq_debugger_ringbuf *fiq_debugger_ringbuf_alloc(int len) +{ + struct fiq_debugger_ringbuf *rbuf; + + rbuf = kzalloc(sizeof(*rbuf) + len, GFP_KERNEL); + if (rbuf == NULL) + return NULL; + + rbuf->len = len; + rbuf->head = 0; + rbuf->tail = 0; + smp_mb(); + + return rbuf; +} + +static inline void fiq_debugger_ringbuf_free(struct fiq_debugger_ringbuf *rbuf) +{ + kfree(rbuf); +} + +static inline int fiq_debugger_ringbuf_level(struct fiq_debugger_ringbuf *rbuf) +{ + int level = rbuf->head - rbuf->tail; + + if (level < 0) + level = rbuf->len + level; + + return level; +} + +static inline int fiq_debugger_ringbuf_room(struct fiq_debugger_ringbuf *rbuf) +{ + return rbuf->len - fiq_debugger_ringbuf_level(rbuf) - 1; +} + +static inline u8 +fiq_debugger_ringbuf_peek(struct fiq_debugger_ringbuf *rbuf, int i) +{ + return rbuf->buf[(rbuf->tail + i) % rbuf->len]; +} + +static inline int +fiq_debugger_ringbuf_consume(struct fiq_debugger_ringbuf *rbuf, int count) +{ + count = min(count, fiq_debugger_ringbuf_level(rbuf)); + + rbuf->tail = (rbuf->tail + count) % rbuf->len; + smp_mb(); + + return count; +} + +static inline int +fiq_debugger_ringbuf_push(struct fiq_debugger_ringbuf *rbuf, u8 datum) +{ + if (fiq_debugger_ringbuf_room(rbuf) == 0) + return 0; + + rbuf->buf[rbuf->head] = datum; + smp_mb(); + rbuf->head = (rbuf->head + 1) % rbuf->len; + smp_mb(); + + return 1; +} -- cgit v1.2.3 From 40dc985279093ce4b1f6ffeff13c88e6f2ae8ce7 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 1 Oct 2010 23:41:38 -0700 Subject: [ARM] fiq debugger: Allow selection of target cpu Change-Id: I676bac08ba12dfa506aea16800fc80432b4bc83d Signed-off-by: Colin Cross --- arch/arm/common/fiq_debugger.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 1ba345d441d0..330053856c76 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -44,6 +44,10 @@ #include "fiq_debugger_ringbuf.h" #define DEBUG_MAX 64 +#define MAX_UNHANDLED_FIQ_COUNT 1000000 + +#define THREAD_INFO(sp) ((struct thread_info *) \ + ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) struct fiq_debugger_state { struct fiq_glue_handler handler; @@ -70,6 +74,9 @@ struct fiq_debugger_state { bool uart_clk_enabled; struct wake_lock debugger_wake_lock; bool console_enable; + int current_cpu; + atomic_t unhandled_fiq_count; + bool in_fiq; #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE struct console console; @@ -388,8 +395,7 @@ void dump_stacktrace(struct fiq_debugger_state *state, struct pt_regs * const regs, unsigned int depth, void *ssp) { struct frame_tail *tail; - struct thread_info *real_thread_info = (struct thread_info *) - ((unsigned long)ssp & ~(THREAD_SIZE - 1)); + struct thread_info *real_thread_info = THREAD_INFO(ssp); struct stacktrace_state sts; sts.depth = depth; @@ -449,6 +455,15 @@ static void debug_exec(struct fiq_debugger_state *state, } else if (!strcmp(cmd, "console")) { state->console_enable = true; debug_printf(state, "console mode\n"); + } else if (!strcmp(cmd, "cpu")) { + debug_printf(state, "cpu %d\n", state->current_cpu); + } else if (!strncmp(cmd, "cpu ", 4)) { + unsigned long cpu = 0; + if (strict_strtoul(cmd + 4, 10, &cpu) == 0) + state->current_cpu = cpu; + else + debug_printf(state, "invalid cpu\n"); + debug_printf(state, "cpu %d\n", state->current_cpu); } else { if (state->debug_busy) { debug_printf(state, @@ -552,6 +567,26 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) int c; static int last_c; int count = 0; + unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; + + if (this_cpu != state->current_cpu) { + if (state->in_fiq) + return; + + if (atomic_inc_return(&state->unhandled_fiq_count) != + MAX_UNHANDLED_FIQ_COUNT) + return; + + debug_printf(state, "fiq_debugger: cpu %d not responding, " + "reverting to cpu %d\n", state->current_cpu, + this_cpu); + + atomic_set(&state->unhandled_fiq_count, 0); + state->current_cpu = this_cpu; + return; + } + + state->in_fiq = true; while ((c = debug_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { count++; @@ -606,6 +641,9 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) /* poke sleep timer if necessary */ if (state->debug_enable && !state->no_sleep) debug_force_irq(state); + + atomic_set(&state->unhandled_fiq_count, 0); + state->in_fiq = false; } static void debug_resume(struct fiq_glue_handler *h) -- cgit v1.2.3 From 91311759bf9410ef68b61ca2b58405acb9dc680e Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 5 Oct 2010 22:08:01 -0700 Subject: [ARM] fiq glue: Align fiq stacks Change-Id: I956f05d0b0ce48572e611765e56a439dc036c052 Signed-off-by: Colin Cross --- arch/arm/common/fiq_glue_setup.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_glue_setup.c b/arch/arm/common/fiq_glue_setup.c index f878ea079b4d..4044c7db95c8 100644 --- a/arch/arm/common/fiq_glue_setup.c +++ b/arch/arm/common/fiq_glue_setup.c @@ -23,7 +23,7 @@ extern void fiq_glue_setup(void *func, void *data, void *sp); static struct fiq_handler fiq_debbuger_fiq_handler = { .name = "fiq_glue", }; -static __percpu void *fiq_stack; +DEFINE_PER_CPU(void *, fiq_stack); static struct fiq_glue_handler *current_handler; static DEFINE_MUTEX(fiq_glue_lock); @@ -31,12 +31,13 @@ static void fiq_glue_setup_helper(void *info) { struct fiq_glue_handler *handler = info; fiq_glue_setup(handler->fiq, handler, - __this_cpu_ptr(fiq_stack) + THREAD_START_SP); + __get_cpu_var(fiq_stack) + THREAD_START_SP); } int fiq_glue_register_handler(struct fiq_glue_handler *handler) { int ret; + int cpu; if (!handler || !handler->fiq) return -EINVAL; @@ -47,10 +48,14 @@ int fiq_glue_register_handler(struct fiq_glue_handler *handler) goto err_busy; } - fiq_stack = __alloc_percpu(THREAD_SIZE, L1_CACHE_BYTES); - if (WARN_ON(!fiq_stack)) { - ret = -ENOMEM; - goto err_alloc_fiq_stack; + for_each_possible_cpu(cpu) { + void *stack; + stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); + if (WARN_ON(!stack)) { + ret = -ENOMEM; + goto err_alloc_fiq_stack; + } + per_cpu(fiq_stack, cpu) = stack; } ret = claim_fiq(&fiq_debbuger_fiq_handler); @@ -61,12 +66,15 @@ int fiq_glue_register_handler(struct fiq_glue_handler *handler) on_each_cpu(fiq_glue_setup_helper, handler, true); set_fiq_handler(&fiq_glue, &fiq_glue_end - &fiq_glue); + mutex_unlock(&fiq_glue_lock); + return 0; + err_claim_fiq: - if (ret) { - free_percpu(fiq_stack); - fiq_stack = NULL; - } err_alloc_fiq_stack: + for_each_possible_cpu(cpu) { + __free_pages(per_cpu(fiq_stack, cpu), THREAD_SIZE_ORDER); + per_cpu(fiq_stack, cpu) = NULL; + } err_busy: mutex_unlock(&fiq_glue_lock); return ret; @@ -85,7 +93,7 @@ void fiq_glue_resume(void) if (!current_handler) return; fiq_glue_setup(current_handler->fiq, current_handler, - __this_cpu_ptr(fiq_stack) + THREAD_START_SP); + __get_cpu_var(fiq_stack) + THREAD_START_SP); if (current_handler->resume) current_handler->resume(current_handler); } -- cgit v1.2.3 From 4a4b46bf86f8d24231b8a16e27ce87726ff678e0 Mon Sep 17 00:00:00 2001 From: Rebecca Schultz Zavin Date: Fri, 22 Oct 2010 15:55:17 -0700 Subject: [ARM] fiq_debugger: Print local timer irqs count Prints the number of local timer irqs on each cpu when the irqs command is executed. Change-Id: Ic70fa9f528d98996fabb2d0cc80e937c5b239c1a Signed-off-by: Rebecca Schultz Zavin --- arch/arm/common/fiq_debugger.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 330053856c76..6b7ce432a31d 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -87,6 +87,7 @@ struct fiq_debugger_state { #endif unsigned int last_irqs[NR_IRQS]; + unsigned int last_local_timer_irqs[NR_CPUS]; }; #ifdef CONFIG_FIQ_DEBUGGER_NO_SLEEP @@ -323,6 +324,8 @@ static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs) static void dump_irqs(struct fiq_debugger_state *state) { int n; + unsigned int cpu; + debug_printf(state, "irqnr total since-last status name\n"); for (n = 0; n < NR_IRQS; n++) { struct irqaction *act = irq_desc[n].action; @@ -335,6 +338,16 @@ static void dump_irqs(struct fiq_debugger_state *state) (act && act->name) ? act->name : "???"); state->last_irqs[n] = kstat_irqs(n); } + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + + debug_printf(state, "LOC %d: %10u %11u\n", cpu, + __IRQ_STAT(cpu, local_timer_irqs), + __IRQ_STAT(cpu, local_timer_irqs) - + state->last_local_timer_irqs[cpu]); + state->last_local_timer_irqs[cpu] = + __IRQ_STAT(cpu, local_timer_irqs); + } } struct stacktrace_state { -- cgit v1.2.3 From 43f62554ccf68a2da72891e0da8f1cbfc7a9bbab Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Wed, 10 Nov 2010 15:39:07 -0800 Subject: ARM: fiq_debugger: make fiq_debugger be in debug mode by default Adds a config option that controls whether or not the console is on at boot, defaulting to no. Change-Id: Id4a3cad1c9dd4fb3c2b8c2298ca5d385a8bd0f8d Signed-off-by: Dima Zavin --- arch/arm/common/Kconfig | 8 ++++++++ arch/arm/common/fiq_debugger.c | 6 ++++++ 2 files changed, 14 insertions(+) (limited to 'arch/arm/common') diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index cbf3b84f90bd..cf82a884a5c5 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -82,3 +82,11 @@ config FIQ_DEBUGGER_CONSOLE help Enables a console so that printk messages are displayed on the debugger serial port as the occur. + +config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE + bool "Put the FIQ debugger into console mode by default" + depends on FIQ_DEBUGGER_CONSOLE + default n + help + If enabled, this puts the fiq debugger into console mode by default. + Otherwise, the fiq debugger will start out in debug mode. diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 6b7ce432a31d..a97c9b2c197a 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -95,8 +95,14 @@ static bool initial_no_sleep = true; #else static bool initial_no_sleep; #endif + +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE +static bool initial_debug_enable = true; +static bool initial_console_enable = true; +#else static bool initial_debug_enable; static bool initial_console_enable; +#endif module_param_named(no_sleep, initial_no_sleep, bool, 0644); module_param_named(debug_enable, initial_debug_enable, bool, 0644); -- cgit v1.2.3 From eb283c5eee37992538eddc2ef25ab6fdf7114a19 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 16 Nov 2010 15:40:13 -0800 Subject: ARM: fiq_debugger: Add help command Signed-off-by: Dmitry Shmidt --- arch/arm/common/fiq_debugger.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index a97c9b2c197a..f172c15f1d3e 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -447,10 +447,35 @@ void dump_stacktrace(struct fiq_debugger_state *state, tail = user_backtrace(state, tail); } +static void debug_help(struct fiq_debugger_state *state) +{ + debug_printf(state, "FIQ Debugger commands:\n" + " pc PC status\n" + " regs Register dump\n" + " allregs Extended Register dump\n" + " bt Stack trace\n" + " reboot Reboot\n" + " irqs Interupt status\n" + " kmsg Kernel log\n" + " version Kernel version\n"); + debug_printf(state, " sleep Allow sleep while in FIQ\n" + " nosleep Disable sleep while in FIQ\n" + " console Switch terminal to console\n" + " cpu Current CPU\n" + " cpu Switch to CPU\n"); + if (!state->debug_busy) { + strcpy(state->debug_cmd, "help"); + state->debug_busy = 1; + debug_force_irq(state); + } +} + static void debug_exec(struct fiq_debugger_state *state, const char *cmd, unsigned *regs, void *svc_sp) { - if (!strcmp(cmd, "pc")) { + if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { + debug_help(state); + } else if (!strcmp(cmd, "pc")) { debug_printf(state, " pc %08x cpsr %08x mode %s\n", regs[15], regs[16], mode_name(regs[16])); } else if (!strcmp(cmd, "regs")) { -- cgit v1.2.3 From 21a050602be10b661c762251e91883df19252a69 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 8 Apr 2011 17:26:06 -0700 Subject: ARM: common: fiq_debugger: Fix build for 2.6.39 irq changes Signed-off-by: Colin Cross Change-Id: I68147c0a17f9cd1b7693826754edc55b1bb09592 --- arch/arm/common/fiq_debugger.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index f172c15f1d3e..080f69edd75a 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -136,9 +136,9 @@ static void debug_force_irq(struct fiq_debugger_state *state) if (state->pdata->force_irq) state->pdata->force_irq(state->pdev, irq); else { - struct irq_chip *chip = get_irq_chip(irq); - if (chip && chip->retrigger) - chip->retrigger(irq); + struct irq_chip *chip = irq_get_chip(irq); + if (chip && chip->irq_retrigger) + chip->irq_retrigger(irq_get_irq_data(irq)); } } @@ -340,7 +340,7 @@ static void dump_irqs(struct fiq_debugger_state *state) debug_printf(state, "%5d: %10u %11u %8x %s\n", n, kstat_irqs(n), kstat_irqs(n) - state->last_irqs[n], - irq_desc[n].status, + irq_desc[n].status_use_accessors, (act && act->name) ? act->name : "???"); state->last_irqs[n] = kstat_irqs(n); } -- cgit v1.2.3 From ee4afb6a61624628c9080c18bcdfe79be72d1667 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Sun, 9 Oct 2011 11:47:35 -0700 Subject: ARM: common: fiq_debugger: do not disable debug when console is enabled Change-Id: I5f8074a860f9b143ee0c87296683bbf2cffb5a36 Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 080f69edd75a..d44690dae546 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -531,7 +531,7 @@ static void sleep_timer_expired(unsigned long data) struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; if (state->uart_clk_enabled && !state->no_sleep) { - if (state->debug_enable) { + if (state->debug_enable && !state->console_enable) { state->debug_enable = false; debug_printf_nfiq(state, "suspending fiq debugger\n"); } -- cgit v1.2.3 From c45e9b96a7734f065ed3237855e88a509cc34358 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Thu, 20 Oct 2011 14:48:37 -0700 Subject: ARM: common: fiq_debugger: fix the cleanup on errors in probe Change-Id: I58bd0604c0520b13e11bf02836eb4ddbadba1372 Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index d44690dae546..46bf7af88ff9 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -923,9 +923,12 @@ err_register_fiq: if (pdata->uart_free) pdata->uart_free(pdev); err_uart_init: - kfree(state); + if (state->clk) + clk_disable(state->clk); if (state->clk) clk_put(state->clk); + wake_lock_destroy(&state->debugger_wake_lock); + kfree(state); return ret; } -- cgit v1.2.3 From 985ecccfab39e289fb1f1e1b0641cc2c298bb4ce Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Tue, 25 Oct 2011 21:24:10 -0700 Subject: ARM: common: fiq_debugger: peek the 0th char in ringbuf ringbuf_consume advances the tail ptr, so peek should always just peek at offset 0 Change-Id: I8d3d22d2ec1e563d73b53ccbad302e6d74e64e53 Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 46bf7af88ff9..71fa962bc535 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -578,7 +578,7 @@ static irqreturn_t debug_irq(int irq, void *dev) int i; int count = fiq_debugger_ringbuf_level(state->tty_rbuf); for (i = 0; i < count; i++) { - int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, i); + int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0); tty_insert_flip_char(state->tty, c, TTY_NORMAL); if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1)) pr_warn("fiq tty failed to consume byte\n"); -- cgit v1.2.3 From 37f2fdb72a756e54dda38372edc3fa84d9aef1a4 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Sun, 2 Oct 2011 20:35:47 -0700 Subject: ARM: common: fiq_debugger: add non-fiq debugger support Add irq-only support to the debugger. This allows the debugger to always run at irq context. This introduces limitations to being able to debug certain kinds of issues, but it is still very useful as a debugging tool. Change-Id: I1e4223e886cb2d90ef5ed31419bdd5cdd7f904ca Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 219 +++++++++++++++++++++++++++++++---------- 1 file changed, 169 insertions(+), 50 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 71fa962bc535..4c04cec67f9e 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ struct fiq_debugger_state { struct fiq_glue_handler handler; int fiq; + int uart_irq; int signal_irq; int wakeup_irq; bool wakeup_irq_no_set_wake; @@ -130,12 +132,20 @@ static inline void disable_wakeup_irq(struct fiq_debugger_state *state) } #endif +static bool inline debug_have_fiq(struct fiq_debugger_state *state) +{ + return (state->fiq >= 0); +} + static void debug_force_irq(struct fiq_debugger_state *state) { unsigned int irq = state->signal_irq; - if (state->pdata->force_irq) + + if (WARN_ON(!debug_have_fiq(state))) + return; + if (state->pdata->force_irq) { state->pdata->force_irq(state->pdev, irq); - else { + } else { struct irq_chip *chip = irq_get_chip(irq); if (chip && chip->irq_retrigger) chip->irq_retrigger(irq_get_irq_data(irq)); @@ -447,7 +457,7 @@ void dump_stacktrace(struct fiq_debugger_state *state, tail = user_backtrace(state, tail); } -static void debug_help(struct fiq_debugger_state *state) +static bool debug_help(struct fiq_debugger_state *state) { debug_printf(state, "FIQ Debugger commands:\n" " pc PC status\n" @@ -466,15 +476,37 @@ static void debug_help(struct fiq_debugger_state *state) if (!state->debug_busy) { strcpy(state->debug_cmd, "help"); state->debug_busy = 1; - debug_force_irq(state); + return true; } + + return false; +} + +static void take_affinity(void *info) +{ + struct fiq_debugger_state *state = info; + struct cpumask cpumask; + + cpumask_clear(&cpumask); + cpumask_set_cpu(get_cpu(), &cpumask); + + irq_set_affinity(state->uart_irq, &cpumask); +} + +static void switch_cpu(struct fiq_debugger_state *state, int cpu) +{ + if (!debug_have_fiq(state)) + smp_call_function_single(cpu, take_affinity, state, false); + state->current_cpu = cpu; } -static void debug_exec(struct fiq_debugger_state *state, +static bool debug_exec(struct fiq_debugger_state *state, const char *cmd, unsigned *regs, void *svc_sp) { + bool signal_helper = false; + if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { - debug_help(state); + signal_helper |= debug_help(state); } else if (!strcmp(cmd, "pc")) { debug_printf(state, " pc %08x cpsr %08x mode %s\n", regs[15], regs[16], mode_name(regs[16])); @@ -494,8 +526,10 @@ static void debug_exec(struct fiq_debugger_state *state, debug_printf(state, "%s\n", linux_banner); } else if (!strcmp(cmd, "sleep")) { state->no_sleep = false; + debug_printf(state, "enabling sleep\n"); } else if (!strcmp(cmd, "nosleep")) { state->no_sleep = true; + debug_printf(state, "disabling sleep\n"); } else if (!strcmp(cmd, "console")) { state->console_enable = true; debug_printf(state, "console mode\n"); @@ -504,7 +538,7 @@ static void debug_exec(struct fiq_debugger_state *state, } else if (!strncmp(cmd, "cpu ", 4)) { unsigned long cpu = 0; if (strict_strtoul(cmd + 4, 10, &cpu) == 0) - state->current_cpu = cpu; + switch_cpu(state, cpu); else debug_printf(state, "invalid cpu\n"); debug_printf(state, "cpu %d\n", state->current_cpu); @@ -518,12 +552,12 @@ static void debug_exec(struct fiq_debugger_state *state, state->debug_busy = 1; } - debug_force_irq(state); - - return; + return true; } if (!state->console_enable) debug_prompt(state); + + return signal_helper; } static void sleep_timer_expired(unsigned long data) @@ -544,15 +578,11 @@ static void sleep_timer_expired(unsigned long data) wake_unlock(&state->debugger_wake_lock); } -static irqreturn_t wakeup_irq_handler(int irq, void *dev) +static void handle_wakeup(struct fiq_debugger_state *state) { - struct fiq_debugger_state *state = dev; - - if (!state->no_sleep) - debug_puts(state, "WAKEUP\n"); - if (state->ignore_next_wakeup_irq) + if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) { state->ignore_next_wakeup_irq = false; - else if (!state->uart_clk_enabled) { + } else if (!state->uart_clk_enabled) { wake_lock(&state->debugger_wake_lock); if (state->clk) clk_enable(state->clk); @@ -560,15 +590,22 @@ static irqreturn_t wakeup_irq_handler(int irq, void *dev) disable_wakeup_irq(state); mod_timer(&state->sleep_timer, jiffies + HZ / 2); } - return IRQ_HANDLED; } -static irqreturn_t debug_irq(int irq, void *dev) +static irqreturn_t wakeup_irq_handler(int irq, void *dev) { struct fiq_debugger_state *state = dev; - if (state->pdata->force_irq_ack) - state->pdata->force_irq_ack(state->pdev, state->signal_irq); + if (!state->no_sleep) + debug_puts(state, "WAKEUP\n"); + handle_wakeup(state); + + return IRQ_HANDLED; +} + + +static void debug_handle_irq_context(struct fiq_debugger_state *state) +{ if (!state->no_sleep) { wake_lock(&state->debugger_wake_lock); mod_timer(&state->sleep_timer, jiffies + HZ * 5); @@ -596,7 +633,6 @@ static irqreturn_t debug_irq(int irq, void *dev) state->debug_busy = 0; } - return IRQ_HANDLED; } static int debug_getc(struct fiq_debugger_state *state) @@ -604,30 +640,29 @@ static int debug_getc(struct fiq_debugger_state *state) return state->pdata->uart_getc(state->pdev); } -static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) +static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, + int this_cpu, void *regs, void *svc_sp) { - struct fiq_debugger_state *state = - container_of(h, struct fiq_debugger_state, handler); int c; static int last_c; int count = 0; - unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; + bool signal_helper = false; if (this_cpu != state->current_cpu) { if (state->in_fiq) - return; + return false; if (atomic_inc_return(&state->unhandled_fiq_count) != MAX_UNHANDLED_FIQ_COUNT) - return; + return false; debug_printf(state, "fiq_debugger: cpu %d not responding, " "reverting to cpu %d\n", state->current_cpu, this_cpu); atomic_set(&state->unhandled_fiq_count, 0); - state->current_cpu = this_cpu; - return; + switch_cpu(state, this_cpu); + return false; } state->in_fiq = true; @@ -648,7 +683,7 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE } else if (state->console_enable && state->tty_rbuf) { fiq_debugger_ringbuf_push(state->tty_rbuf, c); - debug_force_irq(state); + signal_helper = true; #endif } else if ((c >= ' ') && (c < 127)) { if (state->debug_count < (DEBUG_MAX - 1)) { @@ -670,8 +705,9 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) if (state->debug_count) { state->debug_buf[state->debug_count] = 0; state->debug_count = 0; - debug_exec(state, state->debug_buf, - regs, svc_sp); + signal_helper |= + debug_exec(state, state->debug_buf, + regs, svc_sp); } else { debug_prompt(state); } @@ -684,10 +720,63 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) /* poke sleep timer if necessary */ if (state->debug_enable && !state->no_sleep) - debug_force_irq(state); + signal_helper = true; atomic_set(&state->unhandled_fiq_count, 0); state->in_fiq = false; + + return signal_helper; +} + +static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp) +{ + struct fiq_debugger_state *state = + container_of(h, struct fiq_debugger_state, handler); + unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; + bool need_irq; + + need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp); + if (need_irq) + debug_force_irq(state); +} + +/* + * When not using FIQs, we only use this single interrupt as an entry point. + * This just effectively takes over the UART interrupt and does all the work + * in this context. + */ +static irqreturn_t debug_uart_irq(int irq, void *dev) +{ + struct fiq_debugger_state *state = dev; + bool not_done; + + handle_wakeup(state); + + /* handle the debugger irq in regular context */ + not_done = debug_handle_uart_interrupt(state, smp_processor_id(), + get_irq_regs(), + current_thread_info()); + if (not_done) + debug_handle_irq_context(state); + + return IRQ_HANDLED; +} + +/* + * If FIQs are used, not everything can happen in fiq context. + * FIQ handler does what it can and then signals this interrupt to finish the + * job in irq context. + */ +static irqreturn_t debug_signal_irq(int irq, void *dev) +{ + struct fiq_debugger_state *state = dev; + + if (state->pdata->force_irq_ack) + state->pdata->force_irq_ack(state->pdev, state->signal_irq); + + debug_handle_irq_context(state); + + return IRQ_HANDLED; } static void debug_resume(struct fiq_glue_handler *h) @@ -834,13 +923,23 @@ static int fiq_debugger_probe(struct platform_device *pdev) int ret; struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev); struct fiq_debugger_state *state; + int fiq; + int uart_irq; + + if (!pdata->uart_getc || !pdata->uart_putc) + return -EINVAL; - if (!pdata->uart_getc || !pdata->uart_putc || !pdata->fiq_enable) + fiq = platform_get_irq_byname(pdev, "fiq"); + uart_irq = platform_get_irq_byname(pdev, "uart_irq"); + + /* uart_irq mode and fiq mode are mutually exclusive, but one of them + * is required */ + if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0)) + return -EINVAL; + if (fiq >= 0 && !pdata->fiq_enable) return -EINVAL; state = kzalloc(sizeof(*state), GFP_KERNEL); - state->handler.fiq = debug_fiq; - state->handler.resume = debug_resume; setup_timer(&state->sleep_timer, sleep_timer_expired, (unsigned long)state); state->pdata = pdata; @@ -849,11 +948,12 @@ static int fiq_debugger_probe(struct platform_device *pdev) state->debug_enable = initial_debug_enable; state->console_enable = initial_console_enable; - state->fiq = platform_get_irq_byname(pdev, "fiq"); + state->fiq = fiq; + state->uart_irq = uart_irq; state->signal_irq = platform_get_irq_byname(pdev, "signal"); state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); - if (state->wakeup_irq < 0) + if (state->wakeup_irq < 0 && debug_have_fiq(state)) state->no_sleep = true; state->ignore_next_wakeup_irq = !state->no_sleep; @@ -876,21 +976,39 @@ static int fiq_debugger_probe(struct platform_device *pdev) debug_printf_nfiq(state, "\n", state->no_sleep ? "" : "twice "); - ret = fiq_glue_register_handler(&state->handler); - if (ret) { - pr_err("serial_debugger: could not install fiq handler\n"); - goto err_register_fiq; - } + if (debug_have_fiq(state)) { + state->handler.fiq = debug_fiq; + state->handler.resume = debug_resume; + ret = fiq_glue_register_handler(&state->handler); + if (ret) { + pr_err("%s: could not install fiq handler\n", __func__); + goto err_register_fiq; + } - pdata->fiq_enable(pdev, state->fiq, 1); + pdata->fiq_enable(pdev, state->fiq, 1); + } else { + ret = request_irq(state->uart_irq, debug_uart_irq, + 0, "debug", state); + if (ret) { + pr_err("%s: could not install irq handler\n", __func__); + goto err_register_irq; + } + + /* for irq-only mode, we want this irq to wake us up, if it + * can. + */ + enable_irq_wake(state->uart_irq); + } if (state->clk) clk_disable(state->clk); - ret = request_irq(state->signal_irq, debug_irq, - IRQF_TRIGGER_RISING, "debug", state); - if (ret) - pr_err("serial_debugger: could not install signal_irq"); + if (state->signal_irq >= 0) { + ret = request_irq(state->signal_irq, debug_signal_irq, + IRQF_TRIGGER_RISING, "debug-signal", state); + if (ret) + pr_err("serial_debugger: could not install signal_irq"); + } if (state->wakeup_irq >= 0) { ret = request_irq(state->wakeup_irq, wakeup_irq_handler, @@ -910,7 +1028,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) } } if (state->no_sleep) - wakeup_irq_handler(state->wakeup_irq, state); + handle_wakeup(state); #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) state->console = fiq_debugger_console; @@ -919,6 +1037,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) #endif return 0; +err_register_irq: err_register_fiq: if (pdata->uart_free) pdata->uart_free(pdev); -- cgit v1.2.3 From 18127e16cfa980182fccdf6f3ea407b3ddf34e83 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Wed, 5 Oct 2011 14:08:20 -0700 Subject: ARM: common: fiq_debugger: add uart_enable/disable platform callbacks This allows the platform specific drivers to properly enable and disable the uart at the appropriate times. On some platforms, just managing the clock is not enough. Change-Id: I5feaab04cfe313a4a9470ca274838676b9684201 Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 47 ++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 4c04cec67f9e..6804b25f0810 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -73,7 +73,7 @@ struct fiq_debugger_state { bool debug_enable; bool ignore_next_wakeup_irq; struct timer_list sleep_timer; - bool uart_clk_enabled; + bool uart_enabled; struct wake_lock debugger_wake_lock; bool console_enable; int current_cpu; @@ -152,6 +152,22 @@ static void debug_force_irq(struct fiq_debugger_state *state) } } +static void debug_uart_enable(struct fiq_debugger_state *state) +{ + if (state->clk) + clk_enable(state->clk); + if (state->pdata->uart_enable) + state->pdata->uart_enable(state->pdev); +} + +static void debug_uart_disable(struct fiq_debugger_state *state) +{ + if (state->pdata->uart_disable) + state->pdata->uart_disable(state->pdev); + if (state->clk) + clk_disable(state->clk); +} + static void debug_uart_flush(struct fiq_debugger_state *state) { if (state->pdata->uart_flush) @@ -564,15 +580,14 @@ static void sleep_timer_expired(unsigned long data) { struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; - if (state->uart_clk_enabled && !state->no_sleep) { + if (state->uart_enabled && !state->no_sleep) { if (state->debug_enable && !state->console_enable) { state->debug_enable = false; debug_printf_nfiq(state, "suspending fiq debugger\n"); } state->ignore_next_wakeup_irq = true; - if (state->clk) - clk_disable(state->clk); - state->uart_clk_enabled = false; + debug_uart_disable(state); + state->uart_enabled = false; enable_wakeup_irq(state); } wake_unlock(&state->debugger_wake_lock); @@ -582,11 +597,10 @@ static void handle_wakeup(struct fiq_debugger_state *state) { if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) { state->ignore_next_wakeup_irq = false; - } else if (!state->uart_clk_enabled) { + } else if (!state->uart_enabled) { wake_lock(&state->debugger_wake_lock); - if (state->clk) - clk_enable(state->clk); - state->uart_clk_enabled = true; + debug_uart_enable(state); + state->uart_enabled = true; disable_wakeup_irq(state); mod_timer(&state->sleep_timer, jiffies + HZ / 2); } @@ -806,12 +820,14 @@ static void debug_console_write(struct console *co, if (!state->console_enable) return; + debug_uart_enable(state); while (count--) { if (*s == '\n') state->pdata->uart_putc(state->pdev, '\r'); state->pdata->uart_putc(state->pdev, *s++); } debug_uart_flush(state); + debug_uart_disable(state); } static struct console fiq_debugger_console = { @@ -848,12 +864,10 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) if (!state->console_enable) return count; - if (state->clk) - clk_enable(state->clk); + debug_uart_enable(state); for (i = 0; i < count; i++) state->pdata->uart_putc(state->pdev, *buf++); - if (state->clk) - clk_disable(state->clk); + debug_uart_disable(state); return count; } @@ -928,6 +942,9 @@ static int fiq_debugger_probe(struct platform_device *pdev) if (!pdata->uart_getc || !pdata->uart_putc) return -EINVAL; + if ((pdata->uart_enable && !pdata->uart_disable) || + (!pdata->uart_enable && pdata->uart_disable)) + return -EINVAL; fiq = platform_get_irq_byname(pdev, "fiq"); uart_irq = platform_get_irq_byname(pdev, "uart_irq"); @@ -964,6 +981,10 @@ static int fiq_debugger_probe(struct platform_device *pdev) if (IS_ERR(state->clk)) state->clk = NULL; + /* do not call pdata->uart_enable here since uart_init may still + * need to do some initialization before uart_enable can work. + * So, only try to manage the clock during init. + */ if (state->clk) clk_enable(state->clk); -- cgit v1.2.3 From b326fb875d174b8ec9dd0fdd47049f36b0da1583 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Mon, 10 Oct 2011 15:24:34 -0700 Subject: ARM: common: fiq_debugger: add suspend/resume handlers Change-Id: If6eb75059fdf4867eb9a974d60b9d50e5e3350d4 Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 6804b25f0810..7b037beb66d2 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -932,6 +932,26 @@ err: } #endif +static int fiq_debugger_dev_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fiq_debugger_state *state = platform_get_drvdata(pdev); + + if (state->pdata->uart_dev_suspend) + return state->pdata->uart_dev_suspend(pdev); + return 0; +} + +static int fiq_debugger_dev_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fiq_debugger_state *state = platform_get_drvdata(pdev); + + if (state->pdata->uart_dev_resume) + return state->pdata->uart_dev_resume(pdev); + return 0; +} + static int fiq_debugger_probe(struct platform_device *pdev) { int ret; @@ -970,6 +990,8 @@ static int fiq_debugger_probe(struct platform_device *pdev) state->signal_irq = platform_get_irq_byname(pdev, "signal"); state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); + platform_set_drvdata(pdev, state); + if (state->wakeup_irq < 0 && debug_have_fiq(state)) state->no_sleep = true; state->ignore_next_wakeup_irq = !state->no_sleep; @@ -1068,13 +1090,22 @@ err_uart_init: if (state->clk) clk_put(state->clk); wake_lock_destroy(&state->debugger_wake_lock); + platform_set_drvdata(pdev, NULL); kfree(state); return ret; } +static const struct dev_pm_ops fiq_debugger_dev_pm_ops = { + .suspend = fiq_debugger_dev_suspend, + .resume = fiq_debugger_dev_resume, +}; + static struct platform_driver fiq_debugger_driver = { - .probe = fiq_debugger_probe, - .driver.name = "fiq_debugger", + .probe = fiq_debugger_probe, + .driver = { + .name = "fiq_debugger", + .pm = &fiq_debugger_dev_pm_ops, + }, }; static int __init fiq_debugger_init(void) -- cgit v1.2.3 From 9ff09004d6a89b67b9c051186816e350f565021e Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Thu, 13 Oct 2011 22:38:45 -0700 Subject: ARM: common: fiq_debugger: protect the uart state from the sleep timer Change-Id: I6b834d5cab96c3466042f758feb69eae6893ec49 Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 7b037beb66d2..a120b75afe3d 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -73,6 +73,7 @@ struct fiq_debugger_state { bool debug_enable; bool ignore_next_wakeup_irq; struct timer_list sleep_timer; + spinlock_t sleep_timer_lock; bool uart_enabled; struct wake_lock debugger_wake_lock; bool console_enable; @@ -579,7 +580,9 @@ static bool debug_exec(struct fiq_debugger_state *state, static void sleep_timer_expired(unsigned long data) { struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; + unsigned long flags; + spin_lock_irqsave(&state->sleep_timer_lock, flags); if (state->uart_enabled && !state->no_sleep) { if (state->debug_enable && !state->console_enable) { state->debug_enable = false; @@ -591,10 +594,14 @@ static void sleep_timer_expired(unsigned long data) enable_wakeup_irq(state); } wake_unlock(&state->debugger_wake_lock); + spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } static void handle_wakeup(struct fiq_debugger_state *state) { + unsigned long flags; + + spin_lock_irqsave(&state->sleep_timer_lock, flags); if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) { state->ignore_next_wakeup_irq = false; } else if (!state->uart_enabled) { @@ -604,6 +611,7 @@ static void handle_wakeup(struct fiq_debugger_state *state) disable_wakeup_irq(state); mod_timer(&state->sleep_timer, jiffies + HZ / 2); } + spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } static irqreturn_t wakeup_irq_handler(int irq, void *dev) @@ -621,8 +629,12 @@ static irqreturn_t wakeup_irq_handler(int irq, void *dev) static void debug_handle_irq_context(struct fiq_debugger_state *state) { if (!state->no_sleep) { + unsigned long flags; + + spin_lock_irqsave(&state->sleep_timer_lock, flags); wake_lock(&state->debugger_wake_lock); mod_timer(&state->sleep_timer, jiffies + HZ * 5); + spin_unlock_irqrestore(&state->sleep_timer_lock, flags); } #if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) if (state->tty) { @@ -992,6 +1004,8 @@ static int fiq_debugger_probe(struct platform_device *pdev) platform_set_drvdata(pdev, state); + spin_lock_init(&state->sleep_timer_lock); + if (state->wakeup_irq < 0 && debug_have_fiq(state)) state->no_sleep = true; state->ignore_next_wakeup_irq = !state->no_sleep; -- cgit v1.2.3 From 6fc3734fe44c91ef3d27a70b9936a94c77ac8d6b Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Thu, 27 Oct 2011 16:31:24 -0700 Subject: ARM: common: fiq_debugger: make uart irq be no_suspend Change-Id: I8e3d2a95c0ddc2706b021cd33534fe2fd302268e Signed-off-by: Dima Zavin --- arch/arm/common/fiq_debugger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index a120b75afe3d..b9b53c9994ab 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -1045,7 +1045,7 @@ static int fiq_debugger_probe(struct platform_device *pdev) pdata->fiq_enable(pdev, state->fiq, 1); } else { ret = request_irq(state->uart_irq, debug_uart_irq, - 0, "debug", state); + IRQF_NO_SUSPEND, "debug", state); if (ret) { pr_err("%s: could not install irq handler\n", __func__); goto err_register_irq; -- cgit v1.2.3 From 4c38a69720f669d7d7ced5f4e86298caac885a22 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Wed, 9 Nov 2011 16:10:57 -0800 Subject: ARM: common: fiq_debugger: add irq context debug functions This code is moved here from the drivers/misc/kernel_debugger. Change-Id: Iccf21c4313a8516a917125ca93f64baa5f354228 Signed-off-by: Dima Zavin --- arch/arm/common/Kconfig | 3 +- arch/arm/common/fiq_debugger.c | 80 ++++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 21 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index cf82a884a5c5..638256600ffe 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -48,12 +48,11 @@ config FIQ_DEBUGGER bool "FIQ Mode Serial Debugger" select FIQ select FIQ_GLUE - select KERNEL_DEBUGGER_CORE default n help The FIQ serial debugger can accept commands even when the kernel is unresponsive due to being stuck with interrupts - disabled. Depends on the kernel debugger core in drivers/misc. + disabled. config FIQ_DEBUGGER_NO_SLEEP diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index b9b53c9994ab..68e7265cc68d 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -474,7 +473,59 @@ void dump_stacktrace(struct fiq_debugger_state *state, tail = user_backtrace(state, tail); } -static bool debug_help(struct fiq_debugger_state *state) +static void do_ps(struct fiq_debugger_state *state) +{ + struct task_struct *g; + struct task_struct *p; + unsigned task_state; + static const char stat_nam[] = "RSDTtZX"; + + debug_printf(state, "pid ppid prio task pc\n"); + read_lock(&tasklist_lock); + do_each_thread(g, p) { + task_state = p->state ? __ffs(p->state) + 1 : 0; + debug_printf(state, + "%5d %5d %4d ", p->pid, p->parent->pid, p->prio); + debug_printf(state, "%-13.13s %c", p->comm, + task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]); + if (task_state == TASK_RUNNING) + debug_printf(state, " running\n"); + else + debug_printf(state, " %08lx\n", thread_saved_pc(p)); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); +} + +extern int do_syslog(int type, char __user *bug, int count); +static void do_sysrq(struct fiq_debugger_state *state, char rq) +{ + char buf[128]; + int ret; + int idx = 0; + do_syslog(5 /* clear */, NULL, 0); + handle_sysrq(rq); + while (1) { + ret = log_buf_copy(buf, idx, sizeof(buf) - 1); + if (ret <= 0) + break; + buf[ret] = 0; + debug_printf(state, "%s", buf); + idx += ret; + } +} + +/* This function CANNOT be called in FIQ context */ +static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd) +{ + if (!strcmp(cmd, "ps")) + do_ps(state); + if (!strcmp(cmd, "sysrq")) + do_sysrq(state, 'h'); + if (!strncmp(cmd, "sysrq ", 6)) + do_sysrq(state, cmd[6]); +} + +static void debug_help(struct fiq_debugger_state *state) { debug_printf(state, "FIQ Debugger commands:\n" " pc PC status\n" @@ -490,13 +541,9 @@ static bool debug_help(struct fiq_debugger_state *state) " console Switch terminal to console\n" " cpu Current CPU\n" " cpu Switch to CPU\n"); - if (!state->debug_busy) { - strcpy(state->debug_cmd, "help"); - state->debug_busy = 1; - return true; - } - - return false; + debug_printf(state, " ps Process list\n" + " sysrq sysrq options\n" + " sysrq Execute sysrq with \n"); } static void take_affinity(void *info) @@ -517,13 +564,13 @@ static void switch_cpu(struct fiq_debugger_state *state, int cpu) state->current_cpu = cpu; } -static bool debug_exec(struct fiq_debugger_state *state, +static bool debug_fiq_exec(struct fiq_debugger_state *state, const char *cmd, unsigned *regs, void *svc_sp) { bool signal_helper = false; if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { - signal_helper |= debug_help(state); + debug_help(state); } else if (!strcmp(cmd, "pc")) { debug_printf(state, " pc %08x cpsr %08x mode %s\n", regs[15], regs[16], mode_name(regs[16])); @@ -650,13 +697,8 @@ static void debug_handle_irq_context(struct fiq_debugger_state *state) } #endif if (state->debug_busy) { - struct kdbg_ctxt ctxt; - - ctxt.printf = debug_printf_nfiq; - ctxt.cookie = state; - kernel_debugger(&ctxt, state->debug_cmd); + debug_irq_exec(state, state->debug_cmd); debug_prompt(state); - state->debug_busy = 0; } } @@ -732,8 +774,8 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state, state->debug_buf[state->debug_count] = 0; state->debug_count = 0; signal_helper |= - debug_exec(state, state->debug_buf, - regs, svc_sp); + debug_fiq_exec(state, state->debug_buf, + regs, svc_sp); } else { debug_prompt(state); } -- cgit v1.2.3 From b4afed20dd3cc670a313c13d88620ce07be38924 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Wed, 9 Nov 2011 16:48:00 -0800 Subject: ARM: common: fiq_debugger: dump sysrq directly to console if enabled If the fiq console is enabled, then don't filter the console output while sysrq command is in progress. Change-Id: I9389d757373a5fdca5cbf61f0723667510d3ae88 --- arch/arm/common/fiq_debugger.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'arch/arm/common') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 68e7265cc68d..3ed18ae2ed80 100644 --- a/arch/arm/common/fiq_debugger.c +++ b/arch/arm/common/fiq_debugger.c @@ -86,6 +86,7 @@ struct fiq_debugger_state { struct tty_struct *tty; int tty_open_count; struct fiq_debugger_ringbuf *tty_rbuf; + bool syslog_dumping; #endif unsigned int last_irqs[NR_IRQS]; @@ -496,14 +497,29 @@ static void do_ps(struct fiq_debugger_state *state) read_unlock(&tasklist_lock); } +#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE +static void begin_syslog_dump(struct fiq_debugger_state *state) +{ + state->syslog_dumping = true; +} + +static void end_syslog_dump(struct fiq_debugger_state *state) +{ + state->syslog_dumping = false; +} +#else extern int do_syslog(int type, char __user *bug, int count); -static void do_sysrq(struct fiq_debugger_state *state, char rq) +static void begin_syslog_dump(struct fiq_debugger_state *state) +{ + do_syslog(5 /* clear */, NULL, 0); +} + +static void end_syslog_dump(struct fiq_debugger_state *state) { char buf[128]; int ret; int idx = 0; - do_syslog(5 /* clear */, NULL, 0); - handle_sysrq(rq); + while (1) { ret = log_buf_copy(buf, idx, sizeof(buf) - 1); if (ret <= 0) @@ -513,6 +529,14 @@ static void do_sysrq(struct fiq_debugger_state *state, char rq) idx += ret; } } +#endif + +static void do_sysrq(struct fiq_debugger_state *state, char rq) +{ + begin_syslog_dump(state); + handle_sysrq(rq); + end_syslog_dump(state); +} /* This function CANNOT be called in FIQ context */ static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd) @@ -871,7 +895,7 @@ static void debug_console_write(struct console *co, state = container_of(co, struct fiq_debugger_state, console); - if (!state->console_enable) + if (!state->console_enable && !state->syslog_dumping) return; debug_uart_enable(state); -- cgit v1.2.3