diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-10-26 09:29:40 -0700 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-10-29 10:36:05 -0700 |
commit | fc6b412589742976db12de4aa64137c03bfbf311 (patch) | |
tree | b32b72aeef1284e9c2d8354d68cc8ef0694712e6 | |
parent | bff5a49e6d06c13e67b1a72470dc1d9a2326eb16 (diff) | |
download | chrome-ec-fc6b412589742976db12de4aa64137c03bfbf311.tar.gz |
Consolidate emergency debug output
This removes the duplicate uart_emergency_printf() vs. panic_printf()
/ uart_emergency_puts() vs. panic_puts() implementation and saves
~0.5kb of code size.
The other significant change is that uart_flush_output() is now smart
enough to determine if it's in an interrupt; if so, it will spin-flush
the output buffer instead of waiting on the uart interrupt. This
removes the need for a separate panic_flush().
BUG=chrome-os-partner:15579
BRANCH=none
TEST=crash unaligned; should print well-formatted crash dump
Change-Id: Ifae756203dd1881806be563308077c1d68302e1f
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/36695
-rw-r--r-- | common/uart_buffering.c | 79 | ||||
-rw-r--r-- | core/cortex-m/panic.c | 114 | ||||
-rw-r--r-- | core/cortex-m/task.c | 5 | ||||
-rw-r--r-- | core/cortex-m/timer.c | 8 | ||||
-rw-r--r-- | core/cortex-m/watchdog.c | 16 | ||||
-rw-r--r-- | include/panic.h | 27 | ||||
-rw-r--r-- | include/uart.h | 12 |
7 files changed, 79 insertions, 182 deletions
diff --git a/common/uart_buffering.c b/common/uart_buffering.c index 6f22576762..5251507b38 100644 --- a/common/uart_buffering.c +++ b/common/uart_buffering.c @@ -479,6 +479,19 @@ static void handle_console_char(int c) } /** + * Copy output from buffer until TX fifo full or output buffer empty. + * + * May be called from interrupt context. + */ +static void fill_tx_fifo(void) +{ + while (uart_tx_ready() && (tx_buf_head != tx_buf_tail)) { + uart_write_char(tx_buf[tx_buf_tail]); + tx_buf_tail = TX_BUF_NEXT(tx_buf_tail); + } +} + +/** * Helper for UART processing. */ void uart_process(void) @@ -488,10 +501,7 @@ void uart_process(void) handle_console_char(uart_read_char()); /* Copy output from buffer until TX fifo full or output buffer empty */ - while (uart_tx_ready() && (tx_buf_head != tx_buf_tail)) { - uart_write_char(tx_buf[tx_buf_tail]); - tx_buf_tail = TX_BUF_NEXT(tx_buf_tail); - } + fill_tx_fifo(); /* If output buffer is empty, disable transmit interrupt */ if (tx_buf_tail == tx_buf_head) @@ -534,37 +544,23 @@ int uart_printf(const char *format, ...) return rv; } -/** - * Add a character directly to the UART buffer. - */ -static int emergency_txchar(void *format, int c) -{ - /* Wait for space */ - while (!uart_tx_ready()) - ; - - /* Write the character */ - uart_write_char(c); - return 0; -} - -int uart_emergency_printf(const char *format, ...) -{ - int rv; - va_list args; - - va_start(args, format); - rv = vfnprintf(emergency_txchar, NULL, format, args); - va_end(args); - - /* Wait for transmit FIFO empty */ - uart_tx_flush(); - - return rv; -} - void uart_flush_output(void) { + /* + * If we're in interrupt context, copy output explicitly, since the + * UART interrupt may not be able to preempt this one. + */ + if (in_interrupt_context()) { + do { + /* Copy until TX fifo full or output buffer empty */ + fill_tx_fifo(); + + /* Wait for transmit FIFO empty */ + uart_tx_flush(); + } while (tx_buf_head != tx_buf_tail); + return; + } + /* Wait for buffer to empty */ while (tx_buf_head != tx_buf_tail) { /* @@ -584,23 +580,6 @@ void uart_flush_output(void) uart_tx_flush(); } -void uart_emergency_flush(void) -{ - do { - /* - * Copy output from buffer until TX fifo full or output buffer - * empty. - */ - while (uart_tx_ready() && - (tx_buf_head != tx_buf_tail)) { - uart_write_char(tx_buf[tx_buf_tail]); - tx_buf_tail = TX_BUF_NEXT(tx_buf_tail); - } - /* Wait for transmit FIFO empty */ - uart_tx_flush(); - } while (tx_buf_head != tx_buf_tail); -} - void uart_flush_input(void) { /* Disable interrupts */ diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 5b0bff89e7..91ea733f04 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -3,13 +3,12 @@ * found in the LICENSE file. */ -#include <stdarg.h> - -#include "config.h" +#include "common.h" #include "console.h" #include "cpu.h" #include "host_command.h" #include "panic.h" +#include "printf.h" #include "system.h" #include "task.h" #include "timer.h" @@ -33,83 +32,54 @@ static struct panic_data * const pdata_ptr = static const uint32_t pstack_addr = (CONFIG_RAM_BASE + CONFIG_RAM_SIZE - sizeof(struct panic_data)) & ~7; -void panic_putc(int ch) -{ - uart_emergency_flush(); - if (ch == '\n') - panic_putc('\r'); - uart_write_char(ch); - uart_tx_flush(); -} - -void panic_puts(const char *s) -{ - while (*s) - panic_putc(*s++); -} - -void panic_vprintf(const char *format, va_list args) +/** + * Add a character directly to the UART buffer. + * + * @param context Context; ignored. + * @param c Character to write. + * @return 0 if the character was transmitted, 1 if it was dropped. + */ +static int panic_txchar(void *context, int c) { - int pad_width; + if (c == '\n') + panic_txchar(context, '\r'); - while (*format) { - int c = *format++; + /* Wait for space in transmit FIFO */ + while (!uart_tx_ready()) + ; - /* Copy normal characters */ - if (c != '%') { - panic_putc(c); - continue; - } + /* Write the character directly to the transmit FIFO */ + uart_write_char(c); - /* Get first format character */ - c = *format++; + return 0; +} - /* Handle %c */ - if (c == 'c') { - c = va_arg(args, int); - panic_putc(c); - continue; - } +void panic_puts(const char *outstr) +{ + /* Flush the output buffer */ + uart_flush_output(); - /* Count padding length (only supported for hex) */ - pad_width = 0; - while (c >= '0' && c <= '9') { - pad_width = (10 * pad_width) + c - '0'; - c = *format++; - } + /* Put all characters in the output buffer */ + while (*outstr) + panic_txchar(NULL, *outstr++); - if (c == 's') { - char *vstr; - - vstr = va_arg(args, char *); - panic_puts(vstr ? vstr : "(null)"); - } else { /* assume 'x' */ - uint32_t v, shift; - int i; - - v = va_arg(args, uint32_t); - if (!pad_width) - pad_width = 8; - shift = pad_width * 4 - 4; - for (i = 0; i < pad_width; i++) { - int ch = '0' + ((v >> shift) & 0xf); - - if (ch > '9') - ch += 'a' - '9' - 1; - panic_putc(ch); - shift -= 4; - } - } - } + /* Flush the transmit FIFO */ + uart_tx_flush(); } void panic_printf(const char *format, ...) { va_list args; + /* Flush the output buffer */ + uart_flush_output(); + va_start(args, format); - panic_vprintf(format, args); + vfnprintf(panic_txchar, NULL, format, args); va_end(args); + + /* Flush the transmit FIFO */ + uart_tx_flush(); } /** @@ -143,10 +113,10 @@ static void print_reg(int regnum, const uint32_t *regs, int index) name = regnum < 10 ? rname : ®name[(regnum - 10) * 3]; panic_printf("%c%c%c:", name[0], name[1], name[2]); if (regs) - panic_printf("%8x", regs[index]); + panic_printf("%08x", regs[index]); else panic_puts(" "); - panic_putc((regnum & 3) == 3 ? '\n' : ' '); + panic_puts((regnum & 3) == 3 ? "\n" : " "); } #ifdef CONFIG_PANIC_HELP @@ -269,15 +239,13 @@ static void panic_show_extra(const struct panic_data *pdata) panic_printf(", bfar = %x", pdata->bfar); if (pdata->mmfs & CPU_NVIC_MMFS_MFARVALID) panic_printf(", mfar = %x", pdata->mfar); - panic_putc('\n'); - panic_printf("mmfs = %x, ", pdata->mmfs); + panic_printf("\nmmfs = %x, ", pdata->mmfs); panic_printf("shcsr = %x, ", pdata->shcsr); panic_printf("hfsr = %x, ", pdata->hfsr); panic_printf("dfsr = %x\n", pdata->dfsr); } #endif /* CONFIG_PANIC_HELP */ - /** * Display a message and reboot */ @@ -299,7 +267,7 @@ static void panic_print(const struct panic_data *pdata) if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) sregs = pdata->frame; - panic_printf("\n=== EXCEPTION: %2x ====== xPSR: %8x ===========\n", + panic_printf("\n=== EXCEPTION: %02x ====== xPSR: %08x ===========\n", lregs[1] & 7, sregs ? sregs[7] : -1); for (i = 0; i < 4; i++) print_reg(i, sregs, i); @@ -415,8 +383,8 @@ void ignore_bus_fault(int ignored) void panic_assert_fail(const char *msg, const char *func, const char *fname, int linenum) { - panic_printf("\nASSERTION FAILURE '%s' in %s() at %s:%d\n", msg, func, - fname, linenum); + panic_printf("\nASSERTION FAILURE '%s' in %s() at %s:%d\n", + msg, func, fname, linenum); panic_reboot(); } diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c index 7b4eb9ddfe..c48a5e3068 100644 --- a/core/cortex-m/task.c +++ b/core/cortex-m/task.c @@ -497,10 +497,7 @@ void task_print_list(void) ccprintf("%4d %c %-16s %08x %11.6ld %3d/%3d\n", i, is_ready, task_names[i], tasks[i].events, tasks[i].runtime, stackused, tasks_init[i].stack_size); - if (in_interrupt_context()) - uart_emergency_flush(); - else - cflush(); + cflush(); } } diff --git a/core/cortex-m/timer.c b/core/cortex-m/timer.c index d3eaae7efb..5038706a24 100644 --- a/core/cortex-m/timer.c +++ b/core/cortex-m/timer.c @@ -188,20 +188,18 @@ void timer_print_info(void) "Deadline: 0x%016lx -> %11.6ld s from now\n" "Active timers:\n", t, deadline, deadline - t); + cflush(); + for (tskid = 0; tskid < TASK_ID_COUNT; tskid++) { if (timer_running & (1<<tskid)) { ccprintf(" Tsk %2d 0x%016lx -> %11.6ld\n", tskid, timer_deadline[tskid].val, timer_deadline[tskid].val - t); - if (in_interrupt_context()) - uart_emergency_flush(); - else - cflush(); + cflush(); } } } - static int command_wait(int argc, char **argv) { char *e; diff --git a/core/cortex-m/watchdog.c b/core/cortex-m/watchdog.c index d21bb4f1ec..ae26734692 100644 --- a/core/cortex-m/watchdog.c +++ b/core/cortex-m/watchdog.c @@ -5,16 +5,14 @@ /* Watchdog common code */ -#include "board.h" #include "common.h" -#include "config.h" +#include "panic.h" #include "registers.h" #include "task.h" #include "timer.h" #include "uart.h" #include "watchdog.h" - void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp) { uint32_t psp; @@ -29,21 +27,17 @@ void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp) stack = (uint32_t *)psp; } - uart_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ", - stack[6], stack[5], psp); + panic_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ", + stack[6], stack[5], psp); if ((excep_lr & 0xf) == 1) - uart_puts("(exc) ###\n"); + panic_puts("(exc) ###\n"); else - uart_printf("(task %d) ###\n", task_get_current()); - /* Ensure this debug message is always flushed to the UART */ - uart_emergency_flush(); + panic_printf("(task %d) ###\n", task_get_current()); /* If we are blocked in a high priority IT handler, the following debug * messages might not appear but they are useless in that situation. */ timer_print_info(); - uart_emergency_flush(); task_print_list(); - uart_emergency_flush(); } diff --git a/include/panic.h b/include/panic.h index bb3e853bd2..b003f188c8 100644 --- a/include/panic.h +++ b/include/panic.h @@ -48,16 +48,6 @@ struct panic_data { #define PANIC_DATA_FLAG_OLD_HOSTCMD (1 << 2) /** - * Write a character to the panic reporting device - * - * This function will not return until the character has left the UART - * data register. Any previously queued UART traffic is displayed first. - * - * @param ch Character to write - */ -void panic_putc(int ch); - -/** * Write a string to the panic reporting device * * This function will not return until the string has left the UART @@ -68,23 +58,6 @@ void panic_putc(int ch); void panic_puts(const char *s); /** - * Very basic vprintf() for use in panic situations - * - * We only support %s and %nx where n is the number of hex digits to display. - * Currently we don't even support %d, and it is aimed at small code size. - * - * TODO(sjg@chromium.org): Really what we need is a vsnprintf() that is - * shared between the console UART and panic (and is also available as an - * snprintf()). The only downside is that we would then require a large - * printf() implementation to be always present, whereas presumably now we - * can turn it off. - * - * @param format printf-style format string - * @param args List of arguments to process - */ -void panic_vprintf(const char *format, va_list args); - -/** * Very basic printf() for use in panic situations * * See panic_vprintf() for full details diff --git a/include/uart.h b/include/uart.h index ce940457bd..115896f54a 100644 --- a/include/uart.h +++ b/include/uart.h @@ -42,18 +42,6 @@ int uart_vprintf(const char *format, va_list args); /* Flushes output. Blocks until UART has transmitted all output. */ void uart_flush_output(void); -/* Flushes output. - * - * Blocks until UART has transmitted all output, even in a high priority - * interrupt context. */ -void uart_emergency_flush(void); - -/* Like uart_printf(), but bypasses the transmit buffer. - * - * Blocks until UART has transmitted the formatted output, even in a high - * priority interrupt context. */ -int uart_emergency_printf(const char *format, ...); - /*****************************************************************************/ /* Input functions * |