mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
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
This commit is contained in:
@@ -478,6 +478,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.
|
||||
*/
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
uart_emergency_flush();
|
||||
if (ch == '\n')
|
||||
panic_putc('\r');
|
||||
uart_write_char(ch);
|
||||
if (c == '\n')
|
||||
panic_txchar(context, '\r');
|
||||
|
||||
/* Wait for space in transmit FIFO */
|
||||
while (!uart_tx_ready())
|
||||
;
|
||||
|
||||
/* Write the character directly to the transmit FIFO */
|
||||
uart_write_char(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void panic_puts(const char *outstr)
|
||||
{
|
||||
/* Flush the output buffer */
|
||||
uart_flush_output();
|
||||
|
||||
/* Put all characters in the output buffer */
|
||||
while (*outstr)
|
||||
panic_txchar(NULL, *outstr++);
|
||||
|
||||
/* Flush the transmit FIFO */
|
||||
uart_tx_flush();
|
||||
}
|
||||
|
||||
void panic_puts(const char *s)
|
||||
{
|
||||
while (*s)
|
||||
panic_putc(*s++);
|
||||
}
|
||||
|
||||
void panic_vprintf(const char *format, va_list args)
|
||||
{
|
||||
int pad_width;
|
||||
|
||||
while (*format) {
|
||||
int c = *format++;
|
||||
|
||||
/* Copy normal characters */
|
||||
if (c != '%') {
|
||||
panic_putc(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get first format character */
|
||||
c = *format++;
|
||||
|
||||
/* Handle %c */
|
||||
if (c == 'c') {
|
||||
c = va_arg(args, int);
|
||||
panic_putc(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Count padding length (only supported for hex) */
|
||||
pad_width = 0;
|
||||
while (c >= '0' && c <= '9') {
|
||||
pad_width = (10 * pad_width) + c - '0';
|
||||
c = *format++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -47,16 +47,6 @@ struct panic_data {
|
||||
/* Already returned via host command */
|
||||
#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
|
||||
*
|
||||
@@ -67,23 +57,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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user