From 48ef31abe4ee8b75304602c0dfff25184efb9620 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') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 080f69e..d44690d 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.1 From 0d5d8ecf7556f054b249a358ee9ede2ec8070b15 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') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index d44690d..46bf7af 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.1 From b0092759638469a3a0ff12aa50985cc44ecbc980 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') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 46bf7af..71fa962 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.1 From 83b72704b03546192676933905b29005924f822e 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') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 71fa962..4c04cec 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.1 From efde655c8c27ad82f3487ef5e85d6600dafcb8a2 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 +++++++++++++++++++++++++++---------- arch/arm/include/asm/fiq_debugger.h | 9 +++++++ 2 files changed, 43 insertions(+), 13 deletions(-) (limited to 'arch') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 4c04cec..6804b25 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); diff --git a/arch/arm/include/asm/fiq_debugger.h b/arch/arm/include/asm/fiq_debugger.h index e711b57..39a7c16 100644 --- a/arch/arm/include/asm/fiq_debugger.h +++ b/arch/arm/include/asm/fiq_debugger.h @@ -27,6 +27,13 @@ #define FIQ_DEBUGGER_SIGNAL_IRQ_NAME "signal" #define FIQ_DEBUGGER_WAKEUP_IRQ_NAME "wakeup" +/** + * struct fiq_debugger_pdata - fiq debugger platform data + * @uart_enable: Do the work necessary to communicate with the uart + * hw (enable clocks, etc.). This must be ref-counted. + * @uart_disable: Do the work necessary to disable the uart hw + * (disable clocks, etc.). This must be ref-counted. + */ struct fiq_debugger_pdata { int (*uart_init)(struct platform_device *pdev); void (*uart_free)(struct platform_device *pdev); @@ -34,6 +41,8 @@ struct fiq_debugger_pdata { int (*uart_getc)(struct platform_device *pdev); void (*uart_putc)(struct platform_device *pdev, unsigned int c); void (*uart_flush)(struct platform_device *pdev); + void (*uart_enable)(struct platform_device *pdev); + void (*uart_disable)(struct platform_device *pdev); void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq, bool enable); -- cgit v1.1 From f4aea2122af88a6f940463efe124ccd00e026baa 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 +++++++++++++++++++++++++++++++++-- arch/arm/include/asm/fiq_debugger.h | 9 +++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 6804b25..7b037be 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) diff --git a/arch/arm/include/asm/fiq_debugger.h b/arch/arm/include/asm/fiq_debugger.h index 39a7c16..4d27488 100644 --- a/arch/arm/include/asm/fiq_debugger.h +++ b/arch/arm/include/asm/fiq_debugger.h @@ -29,10 +29,16 @@ /** * struct fiq_debugger_pdata - fiq debugger platform data + * @uart_resume: used to restore uart state right before enabling + * the fiq. * @uart_enable: Do the work necessary to communicate with the uart * hw (enable clocks, etc.). This must be ref-counted. * @uart_disable: Do the work necessary to disable the uart hw * (disable clocks, etc.). This must be ref-counted. + * @uart_dev_suspend: called during PM suspend, generally not needed + * for real fiq mode debugger. + * @uart_dev_resume: called during PM resume, generally not needed + * for real fiq mode debugger. */ struct fiq_debugger_pdata { int (*uart_init)(struct platform_device *pdev); @@ -44,6 +50,9 @@ struct fiq_debugger_pdata { void (*uart_enable)(struct platform_device *pdev); void (*uart_disable)(struct platform_device *pdev); + int (*uart_dev_suspend)(struct platform_device *pdev); + int (*uart_dev_resume)(struct platform_device *pdev); + void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq, bool enable); void (*fiq_ack)(struct platform_device *pdev, unsigned int fiq); -- cgit v1.1 From 932de6c144611d159311e758f3e9fad8f37f6497 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') diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c index 7b037be..a120b75 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.1