From 1762de9d19d2671cc56e5a479055379a346030d3 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 4 Dec 2013 17:15:12 -0800 Subject: extract common core code Move the non-core dependent code out of core/$(CORE) directory to common/ directory. Put all panic printing code in common/panic_output.c Put timer management code in common/timer.c Signed-off-by: Vincent Palatin BRANCH=none BUG=chrome-os-partner:23574 TEST=./util/make_all.sh use "crash divzero" and "panicinfo" on Link. Change-Id: Ia4e1ebc74cd53da55fe24f69e96f39f512b9336d Reviewed-on: https://chromium-review.googlesource.com/178871 Reviewed-by: Randall Spangler Tested-by: Vincent Palatin Reviewed-by: Jeremy Thorpe Commit-Queue: Vincent Palatin --- chip/host/config_chip.h | 5 + common/build.mk | 2 + common/panic_output.c | 169 +++++++++++++++++++++++++++++ common/timer.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++++ core/cortex-m/build.mk | 2 +- core/cortex-m/panic.c | 220 ++++++-------------------------------- core/cortex-m/timer.c | 278 ------------------------------------------------ include/config.h | 8 ++ include/panic.h | 37 +++++-- util/ectool.c | 9 +- 10 files changed, 533 insertions(+), 475 deletions(-) create mode 100644 common/panic_output.c create mode 100644 common/timer.c delete mode 100644 core/cortex-m/timer.c diff --git a/chip/host/config_chip.h b/chip/host/config_chip.h index 9aa51f6108..906aa232b2 100644 --- a/chip/host/config_chip.h +++ b/chip/host/config_chip.h @@ -44,5 +44,10 @@ extern char __host_flash[CONFIG_FLASH_PHYSICAL_SIZE]; /* Interval between HOOK_TICK notifications */ #define HOOK_TICK_INTERVAL (250 * MSEC) +/* Do NOT use common panic code (designed to output information on the UART) */ +#undef CONFIG_COMMON_PANIC_OUTPUT +/* Do NOT use common timer code which is designed for hardware counters. */ +#undef CONFIG_COMMON_TIMER + #endif /* __CROS_EC_CONFIG_CHIP_H */ diff --git a/common/build.mk b/common/build.mk index dc64e4bcd9..18da04ae78 100644 --- a/common/build.mk +++ b/common/build.mk @@ -22,6 +22,8 @@ common-$(CONFIG_CHARGER)+=charge_state.o charger.o # TODO(crosbug.com/p/23815): This is really the charge state machine # for ARM, not the charger driver for the tps65090. Rename. common-$(CONFIG_CHARGER_TPS65090)+=pmu_tps65090_charger.o +common-$(CONFIG_COMMON_PANIC_OUTPUT)+=panic_output.o +common-$(CONFIG_COMMON_TIMER)+=timer.o common-$(CONFIG_PMU_POWERINFO)+=pmu_tps65090_powerinfo.o common-$(CONFIG_PMU_TPS65090)+=pmu_tps65090.o common-$(CONFIG_EOPTION)+=eoption.o diff --git a/common/panic_output.c b/common/panic_output.c new file mode 100644 index 0000000000..f77277ab33 --- /dev/null +++ b/common/panic_output.c @@ -0,0 +1,169 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#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" +#include "uart.h" +#include "util.h" + +/* Panic data goes at the end of RAM. */ +static struct panic_data * const pdata_ptr = PANIC_DATA_PTR; + +/** + * 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) +{ + 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_printf(const char *format, ...) +{ + va_list args; + + /* Flush the output buffer */ + uart_flush_output(); + + va_start(args, format); + vfnprintf(panic_txchar, NULL, format, args); + va_end(args); + + /* Flush the transmit FIFO */ + uart_tx_flush(); +} + +/** + * Display a message and reboot + */ +void panic_reboot(void) +{ + panic_puts("\n\nRebooting...\n"); + system_reset(0); +} + +#ifdef CONFIG_DEBUG_ASSERT_REBOOTS +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_reboot(); +} +#endif + +void panic(const char *msg) +{ + panic_printf("\n** PANIC: %s\n", msg); + panic_reboot(); +} + +struct panic_data *panic_get_data(void) +{ + return pdata_ptr->magic == PANIC_DATA_MAGIC ? pdata_ptr : NULL; +} + +/*****************************************************************************/ +/* Console commands */ + +static int command_crash(int argc, char **argv) +{ + if (argc < 2) + return EC_ERROR_PARAM1; + + if (!strcasecmp(argv[1], "divzero")) { + int a = 1, b = 0; + + cflush(); + ccprintf("%08x", a / b); + } else if (!strcasecmp(argv[1], "unaligned")) { + cflush(); + ccprintf("%08x", *(int *)0xcdef); + } else { + return EC_ERROR_PARAM1; + } + + /* Everything crashes, so shouldn't get back here */ + return EC_ERROR_UNKNOWN; +} +DECLARE_CONSOLE_COMMAND(crash, command_crash, + "[divzero | unaligned]", + "Crash the system (for testing)", + NULL); + +static int command_panicinfo(int argc, char **argv) +{ + if (pdata_ptr->magic == PANIC_DATA_MAGIC) { + ccprintf("Saved panic data:%s\n", + (pdata_ptr->flags & PANIC_DATA_FLAG_OLD_CONSOLE ? + "" : " (NEW)")); + + panic_data_print(pdata_ptr); + + /* Data has now been printed */ + pdata_ptr->flags |= PANIC_DATA_FLAG_OLD_CONSOLE; + } else { + ccprintf("No saved panic data available.\n"); + } + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(panicinfo, command_panicinfo, + NULL, + "Print info from a previous panic", + NULL); + +/*****************************************************************************/ +/* Host commands */ + +int host_command_panic_info(struct host_cmd_handler_args *args) +{ + if (pdata_ptr->magic == PANIC_DATA_MAGIC) { + ASSERT(pdata_ptr->struct_size <= args->response_max); + memcpy(args->response, pdata_ptr, pdata_ptr->struct_size); + args->response_size = pdata_ptr->struct_size; + + /* Data has now been returned */ + pdata_ptr->flags |= PANIC_DATA_FLAG_OLD_HOSTCMD; + } + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_GET_PANIC_INFO, + host_command_panic_info, + EC_VER_MASK(0)); diff --git a/common/timer.c b/common/timer.c new file mode 100644 index 0000000000..0256d673bc --- /dev/null +++ b/common/timer.c @@ -0,0 +1,278 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Timer module for Chrome EC operating system */ + +#include "atomic.h" +#include "console.h" +#include "hooks.h" +#include "hwtimer.h" +#include "system.h" +#include "uart.h" +#include "util.h" +#include "task.h" +#include "timer.h" + +#define TIMER_SYSJUMP_TAG 0x4d54 /* "TM" */ + +/* High word of the 64-bit timestamp counter */ +static volatile uint32_t clksrc_high; + +/* Bitmap of currently running timers */ +static uint32_t timer_running = 0; + +/* Deadlines of all timers */ +static timestamp_t timer_deadline[TASK_ID_COUNT]; +static uint32_t next_deadline = 0xffffffff; + +/* Hardware timer routine IRQ number */ +static int timer_irq; + +static void expire_timer(task_id_t tskid) +{ + /* we are done with this timer */ + atomic_clear(&timer_running, 1 << tskid); + /* wake up the taks waiting for this timer */ + task_set_event(tskid, TASK_EVENT_TIMER, 0); +} + +int timestamp_expired(timestamp_t deadline, const timestamp_t *now) +{ + timestamp_t now_val; + + if (!now) { + now_val = get_time(); + now = &now_val; + } + + return ((int64_t)(now->val - deadline.val) >= 0); +} + +void process_timers(int overflow) +{ + uint32_t check_timer, running_t0; + timestamp_t next; + timestamp_t now; + + if (overflow) + clksrc_high++; + + do { + next.val = -1ull; + now = get_time(); + do { + /* read atomically the current state of timer running */ + check_timer = running_t0 = timer_running; + while (check_timer) { + int tskid = 31 - __builtin_clz(check_timer); + + /* timer has expired ? */ + if (timer_deadline[tskid].val < now.val) + expire_timer(tskid); + else if ((timer_deadline[tskid].le.hi == + now.le.hi) && + (timer_deadline[tskid].le.lo < + next.le.lo)) + next.val = timer_deadline[tskid].val; + + check_timer &= ~(1 << tskid); + } + /* if there is a new timer, let's retry */ + } while (timer_running & ~running_t0); + + if (next.le.hi == 0xffffffff) { + /* no deadline to set */ + __hw_clock_event_clear(); + next_deadline = 0xffffffff; + return; + } + + __hw_clock_event_set(next.le.lo); + next_deadline = next.le.lo; + } while (next.val <= get_time().val); +} + +void udelay(unsigned us) +{ + unsigned t0 = __hw_clock_source_read(); + + /* + * udelay() may be called with interrupts disabled, so we can't rely on + * process_timers() updating the top 32 bits. So handle wraparound + * ourselves rather than calling get_time() and comparing with a + * deadline. + * + * This may fail for delays close to 2^32 us (~4000 sec), because the + * subtraction below can overflow. That's acceptable, because the + * watchdog timer would have tripped long before that anyway. + */ + while (__hw_clock_source_read() - t0 < us) + ; +} + +int timer_arm(timestamp_t tstamp, task_id_t tskid) +{ + ASSERT(tskid < TASK_ID_COUNT); + + if (timer_running & (1< %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< %11.6ld\n", tskid, + timer_deadline[tskid].val, + timer_deadline[tskid].val - t); + cflush(); + } + } +} + +void timer_init(void) +{ + const timestamp_t *ts; + int size, version; + + BUILD_ASSERT(TASK_ID_COUNT < sizeof(timer_running) * 8); + + /* Restore time from before sysjump */ + ts = (const timestamp_t *)system_get_jump_tag(TIMER_SYSJUMP_TAG, + &version, &size); + if (ts && version == 1 && size == sizeof(timestamp_t)) { + clksrc_high = ts->le.hi; + timer_irq = __hw_clock_source_init(ts->le.lo); + } else { + clksrc_high = 0; + timer_irq = __hw_clock_source_init(0); + } +} + +/* Preserve time across a sysjump */ +static void timer_sysjump(void) +{ + timestamp_t ts = get_time(); + + system_add_jump_tag(TIMER_SYSJUMP_TAG, 1, sizeof(ts), &ts); +} +DECLARE_HOOK(HOOK_SYSJUMP, timer_sysjump, HOOK_PRIO_DEFAULT); + +static int command_wait(int argc, char **argv) +{ + char *e; + int i; + + if (argc < 2) + return EC_ERROR_PARAM_COUNT; + + i = strtoi(argv[1], &e, 0); + if (*e) + return EC_ERROR_PARAM1; + + udelay(i * 1000); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(waitms, command_wait, + "msec", + "Busy-wait for msec", + NULL); + +static int command_get_time(int argc, char **argv) +{ + timestamp_t ts = get_time(); + ccprintf("Time: 0x%016lx = %.6ld s\n", ts.val, ts.val); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(gettime, command_get_time, + NULL, + "Print current time", + NULL); + +int command_timer_info(int argc, char **argv) +{ + timer_print_info(); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(timerinfo, command_timer_info, + NULL, + "Print timer info", + NULL); diff --git a/core/cortex-m/build.mk b/core/cortex-m/build.mk index d90b36f9ab..741ec005cc 100644 --- a/core/cortex-m/build.mk +++ b/core/cortex-m/build.mk @@ -17,6 +17,6 @@ CFLAGS_CPU+=-mthumb -Os -mno-sched-prolog CFLAGS_CPU+=-mno-unaligned-access CFLAGS_CPU+=$(CFLAGS_FPU-y) -core-y=cpu.o init.o panic.o switch.o task.o timer.o +core-y=cpu.o init.o panic.o switch.o task.o core-$(CONFIG_WATCHDOG)+=watchdog.o core-$(CONFIG_MPU)+=mpu.o diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 95344bbb07..d63a5e3d9a 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -19,69 +19,14 @@ /* Whether bus fault is ignored */ static int bus_fault_ignored; -/* - * Panic data goes at the end of RAM. This is safe because we don't context - * switch away from the panic handler before rebooting, and stacks and data - * start at the beginning of RAM. - */ -static struct panic_data * const pdata_ptr = - (struct panic_data *)(CONFIG_RAM_BASE + CONFIG_RAM_SIZE - - sizeof(struct panic_data)); + +/* Panic data goes at the end of RAM. */ +static struct panic_data * const pdata_ptr = PANIC_DATA_PTR; /* Preceded by stack, rounded down to nearest 64-bit-aligned boundary */ static const uint32_t pstack_addr = (CONFIG_RAM_BASE + CONFIG_RAM_SIZE - sizeof(struct panic_data)) & ~7; -/** - * 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) -{ - 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_printf(const char *format, ...) -{ - va_list args; - - /* Flush the output buffer */ - uart_flush_output(); - - va_start(args, format); - vfnprintf(panic_txchar, NULL, format, args); - va_end(args); - - /* Flush the transmit FIFO */ - uart_tx_flush(); -} - /** * Print the name and value of a register * @@ -253,13 +198,13 @@ static uint32_t get_exception_frame_size(const struct panic_data *pdata) /* CPU uses xPSR[9] to indicate whether it padded the stack for * alignment or not. */ - if (pdata->frame[7] & (1 << 9)) + if (pdata->cm.frame[7] & (1 << 9)) frame_size += sizeof(uint32_t); #ifdef CONFIG_FPU /* CPU uses EXC_RETURN[4] to indicate whether it stored extended * frame for FPU or not. */ - if (!(pdata->regs[11] & (1 << 4))) + if (!(pdata->cm.regs[11] & (1 << 4))) frame_size += 18 * sizeof(uint32_t); #endif @@ -273,9 +218,9 @@ static uint32_t get_exception_frame_size(const struct panic_data *pdata) */ static uint32_t get_process_stack_position(const struct panic_data *pdata) { - uint32_t psp = pdata->regs[0]; + uint32_t psp = pdata->cm.regs[0]; - if (!is_frame_in_handler_stack(pdata->regs[11])) + if (!is_frame_in_handler_stack(pdata->cm.regs[11])) psp += get_exception_frame_size(pdata); return psp; @@ -289,15 +234,15 @@ static uint32_t get_process_stack_position(const struct panic_data *pdata) */ static void panic_show_extra(const struct panic_data *pdata) { - show_fault(pdata->mmfs, pdata->hfsr, pdata->dfsr); - if (pdata->mmfs & CPU_NVIC_MMFS_BFARVALID) - panic_printf(", bfar = %x", pdata->bfar); - if (pdata->mmfs & CPU_NVIC_MMFS_MFARVALID) - panic_printf(", mfar = %x", pdata->mfar); - 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); + show_fault(pdata->cm.mmfs, pdata->cm.hfsr, pdata->cm.dfsr); + if (pdata->cm.mmfs & CPU_NVIC_MMFS_BFARVALID) + panic_printf(", bfar = %x", pdata->cm.bfar); + if (pdata->cm.mmfs & CPU_NVIC_MMFS_MFARVALID) + panic_printf(", mfar = %x", pdata->cm.mfar); + panic_printf("\nmmfs = %x, ", pdata->cm.mmfs); + panic_printf("shcsr = %x, ", pdata->cm.shcsr); + panic_printf("hfsr = %x, ", pdata->cm.hfsr); + panic_printf("dfsr = %x\n", pdata->cm.dfsr); } /* @@ -324,27 +269,19 @@ static void panic_show_process_stack(const struct panic_data *pdata) } #endif /* CONFIG_DEBUG_EXCEPTIONS */ -/** - * Display a message and reboot - */ -void panic_reboot(void) -{ - panic_puts("\n\nRebooting...\n"); - system_reset(0); -} - /* * Print panic data */ -static void panic_print(const struct panic_data *pdata) +void panic_data_print(const struct panic_data *pdata) { - const uint32_t *lregs = pdata->regs; + const uint32_t *lregs = pdata->cm.regs; const uint32_t *sregs = NULL; - const int32_t in_handler = is_frame_in_handler_stack(pdata->regs[11]); + const int32_t in_handler = + is_frame_in_handler_stack(pdata->cm.regs[11]); int i; if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) - sregs = pdata->frame; + sregs = pdata->cm.frame; panic_printf("\n=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n", in_handler ? "HANDLER" : "PROCESS", @@ -378,8 +315,8 @@ void report_panic(void) pdata->reserved = 0; /* Choose the right sp (psp or msp) based on EXC_RETURN value */ - sp = is_frame_in_handler_stack(pdata->regs[11]) - ? pdata->regs[2] : pdata->regs[0]; + sp = is_frame_in_handler_stack(pdata->cm.regs[11]) + ? pdata->cm.regs[2] : pdata->cm.regs[0]; /* If stack is valid, copy exception frame to pdata */ if ((sp & 3) == 0 && sp >= CONFIG_RAM_BASE && @@ -387,19 +324,19 @@ void report_panic(void) const uint32_t *sregs = (const uint32_t *)sp; int i; for (i = 0; i < 8; i++) - pdata->frame[i] = sregs[i]; + pdata->cm.frame[i] = sregs[i]; pdata->flags |= PANIC_DATA_FLAG_FRAME_VALID; } /* Save extra information */ - pdata->mmfs = CPU_NVIC_MMFS; - pdata->bfar = CPU_NVIC_BFAR; - pdata->mfar = CPU_NVIC_MFAR; - pdata->shcsr = CPU_NVIC_SHCSR; - pdata->hfsr = CPU_NVIC_HFSR; - pdata->dfsr = CPU_NVIC_DFSR; - - panic_print(pdata); + pdata->cm.mmfs = CPU_NVIC_MMFS; + pdata->cm.bfar = CPU_NVIC_BFAR; + pdata->cm.mfar = CPU_NVIC_MFAR; + pdata->cm.shcsr = CPU_NVIC_SHCSR; + pdata->cm.hfsr = CPU_NVIC_HFSR; + pdata->cm.dfsr = CPU_NVIC_DFSR; + + panic_data_print(pdata); #ifdef CONFIG_DEBUG_EXCEPTIONS panic_show_process_stack(pdata); /* @@ -427,7 +364,7 @@ void exception_panic(void) "stmia r0, {r1-r11, lr}\n" "mov sp, %[pstack]\n" "b report_panic\n" : : - [pregs] "r" (pdata_ptr->regs), + [pregs] "r" (pdata_ptr->cm.regs), [pstack] "r" (pstack_addr) : /* Constraints protecting these from being clobbered. * Gcc should be using r0 & r12 for pregs and pstack. */ @@ -446,94 +383,3 @@ void ignore_bus_fault(int ignored) { bus_fault_ignored = ignored; } - -#ifdef CONFIG_DEBUG_ASSERT_REBOOTS -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_reboot(); -} -#endif - -void panic(const char *msg) -{ - panic_printf("\n** PANIC: %s\n", msg); - panic_reboot(); -} - -struct panic_data *panic_get_data(void) -{ - return pdata_ptr->magic == PANIC_DATA_MAGIC ? pdata_ptr : NULL; -} - -/*****************************************************************************/ -/* Console commands */ - -static int command_crash(int argc, char **argv) -{ - if (argc < 2) - return EC_ERROR_PARAM1; - - if (!strcasecmp(argv[1], "divzero")) { - int a = 1, b = 0; - - cflush(); - ccprintf("%08x", a / b); - } else if (!strcasecmp(argv[1], "unaligned")) { - cflush(); - ccprintf("%08x", *(int *)0xcdef); - } else { - return EC_ERROR_PARAM1; - } - - /* Everything crashes, so shouldn't get back here */ - return EC_ERROR_UNKNOWN; -} -DECLARE_CONSOLE_COMMAND(crash, command_crash, - "[divzero | unaligned]", - "Crash the system (for testing)", - NULL); - -static int command_panicinfo(int argc, char **argv) -{ - if (pdata_ptr->magic == PANIC_DATA_MAGIC) { - ccprintf("Saved panic data:%s\n", - (pdata_ptr->flags & PANIC_DATA_FLAG_OLD_CONSOLE ? - "" : " (NEW)")); - - panic_print(pdata_ptr); - - /* Data has now been printed */ - pdata_ptr->flags |= PANIC_DATA_FLAG_OLD_CONSOLE; - } else { - ccprintf("No saved panic data available.\n"); - } - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(panicinfo, command_panicinfo, - NULL, - "Print info from a previous panic", - NULL); - -/*****************************************************************************/ -/* Host commands */ - -int host_command_panic_info(struct host_cmd_handler_args *args) -{ - if (pdata_ptr->magic == PANIC_DATA_MAGIC) { - ASSERT(pdata_ptr->struct_size <= args->response_max); - memcpy(args->response, pdata_ptr, pdata_ptr->struct_size); - args->response_size = pdata_ptr->struct_size; - - /* Data has now been returned */ - pdata_ptr->flags |= PANIC_DATA_FLAG_OLD_HOSTCMD; - } - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_GET_PANIC_INFO, - host_command_panic_info, - EC_VER_MASK(0)); diff --git a/core/cortex-m/timer.c b/core/cortex-m/timer.c deleted file mode 100644 index 0256d673bc..0000000000 --- a/core/cortex-m/timer.c +++ /dev/null @@ -1,278 +0,0 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Timer module for Chrome EC operating system */ - -#include "atomic.h" -#include "console.h" -#include "hooks.h" -#include "hwtimer.h" -#include "system.h" -#include "uart.h" -#include "util.h" -#include "task.h" -#include "timer.h" - -#define TIMER_SYSJUMP_TAG 0x4d54 /* "TM" */ - -/* High word of the 64-bit timestamp counter */ -static volatile uint32_t clksrc_high; - -/* Bitmap of currently running timers */ -static uint32_t timer_running = 0; - -/* Deadlines of all timers */ -static timestamp_t timer_deadline[TASK_ID_COUNT]; -static uint32_t next_deadline = 0xffffffff; - -/* Hardware timer routine IRQ number */ -static int timer_irq; - -static void expire_timer(task_id_t tskid) -{ - /* we are done with this timer */ - atomic_clear(&timer_running, 1 << tskid); - /* wake up the taks waiting for this timer */ - task_set_event(tskid, TASK_EVENT_TIMER, 0); -} - -int timestamp_expired(timestamp_t deadline, const timestamp_t *now) -{ - timestamp_t now_val; - - if (!now) { - now_val = get_time(); - now = &now_val; - } - - return ((int64_t)(now->val - deadline.val) >= 0); -} - -void process_timers(int overflow) -{ - uint32_t check_timer, running_t0; - timestamp_t next; - timestamp_t now; - - if (overflow) - clksrc_high++; - - do { - next.val = -1ull; - now = get_time(); - do { - /* read atomically the current state of timer running */ - check_timer = running_t0 = timer_running; - while (check_timer) { - int tskid = 31 - __builtin_clz(check_timer); - - /* timer has expired ? */ - if (timer_deadline[tskid].val < now.val) - expire_timer(tskid); - else if ((timer_deadline[tskid].le.hi == - now.le.hi) && - (timer_deadline[tskid].le.lo < - next.le.lo)) - next.val = timer_deadline[tskid].val; - - check_timer &= ~(1 << tskid); - } - /* if there is a new timer, let's retry */ - } while (timer_running & ~running_t0); - - if (next.le.hi == 0xffffffff) { - /* no deadline to set */ - __hw_clock_event_clear(); - next_deadline = 0xffffffff; - return; - } - - __hw_clock_event_set(next.le.lo); - next_deadline = next.le.lo; - } while (next.val <= get_time().val); -} - -void udelay(unsigned us) -{ - unsigned t0 = __hw_clock_source_read(); - - /* - * udelay() may be called with interrupts disabled, so we can't rely on - * process_timers() updating the top 32 bits. So handle wraparound - * ourselves rather than calling get_time() and comparing with a - * deadline. - * - * This may fail for delays close to 2^32 us (~4000 sec), because the - * subtraction below can overflow. That's acceptable, because the - * watchdog timer would have tripped long before that anyway. - */ - while (__hw_clock_source_read() - t0 < us) - ; -} - -int timer_arm(timestamp_t tstamp, task_id_t tskid) -{ - ASSERT(tskid < TASK_ID_COUNT); - - if (timer_running & (1< %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< %11.6ld\n", tskid, - timer_deadline[tskid].val, - timer_deadline[tskid].val - t); - cflush(); - } - } -} - -void timer_init(void) -{ - const timestamp_t *ts; - int size, version; - - BUILD_ASSERT(TASK_ID_COUNT < sizeof(timer_running) * 8); - - /* Restore time from before sysjump */ - ts = (const timestamp_t *)system_get_jump_tag(TIMER_SYSJUMP_TAG, - &version, &size); - if (ts && version == 1 && size == sizeof(timestamp_t)) { - clksrc_high = ts->le.hi; - timer_irq = __hw_clock_source_init(ts->le.lo); - } else { - clksrc_high = 0; - timer_irq = __hw_clock_source_init(0); - } -} - -/* Preserve time across a sysjump */ -static void timer_sysjump(void) -{ - timestamp_t ts = get_time(); - - system_add_jump_tag(TIMER_SYSJUMP_TAG, 1, sizeof(ts), &ts); -} -DECLARE_HOOK(HOOK_SYSJUMP, timer_sysjump, HOOK_PRIO_DEFAULT); - -static int command_wait(int argc, char **argv) -{ - char *e; - int i; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - i = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - udelay(i * 1000); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(waitms, command_wait, - "msec", - "Busy-wait for msec", - NULL); - -static int command_get_time(int argc, char **argv) -{ - timestamp_t ts = get_time(); - ccprintf("Time: 0x%016lx = %.6ld s\n", ts.val, ts.val); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(gettime, command_get_time, - NULL, - "Print current time", - NULL); - -int command_timer_info(int argc, char **argv) -{ - timer_print_info(); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(timerinfo, command_timer_info, - NULL, - "Print timer info", - NULL); diff --git a/include/config.h b/include/config.h index 24cf8b5815..bc5e176e52 100644 --- a/include/config.h +++ b/include/config.h @@ -226,6 +226,14 @@ /*****************************************************************************/ +/* Provide common core code to output panic information without interrupts. */ +#define CONFIG_COMMON_PANIC_OUTPUT + +/* Provide common core code to handle the operating system timers. */ +#define CONFIG_COMMON_TIMER + +/*****************************************************************************/ + /* * Provide additional help on console commands, such as the supported * options/usage. diff --git a/include/panic.h b/include/panic.h index 2647592448..40bab2487e 100644 --- a/include/panic.h +++ b/include/panic.h @@ -11,13 +11,8 @@ #include -/* Data saved across reboots */ -struct panic_data { - uint8_t arch; /* Architecture (PANIC_ARCH_*) */ - uint8_t struct_version; /* Structure version (currently 2) */ - uint8_t flags; /* Flags (PANIC_DATA_FLAG_*) */ - uint8_t reserved; /* Reserved; set 0 */ - +/* ARM Cortex-Mx registers saved on panic */ +struct cortex_panic_data { uint32_t regs[12]; /* psp, ipsr, msp, r4-r11, lr(=exc_return). * In version 1, that was uint32_t regs[11] = * psp, ipsr, lr, r4-r11 @@ -30,6 +25,19 @@ struct panic_data { uint32_t shcsr; uint32_t hfsr; uint32_t dfsr; +}; + +/* Data saved across reboots */ +struct panic_data { + uint8_t arch; /* Architecture (PANIC_ARCH_*) */ + uint8_t struct_version; /* Structure version (currently 2) */ + uint8_t flags; /* Flags (PANIC_DATA_FLAG_*) */ + uint8_t reserved; /* Reserved; set 0 */ + + /* core specific panic data */ + union { + struct cortex_panic_data cm; /* Cortex-Mx registers */ + }; /* * These fields go at the END of the struct so we can find it at the @@ -42,6 +50,14 @@ struct panic_data { #define PANIC_DATA_MAGIC 0x21636e50 /* "Pnc!" */ #define PANIC_ARCH_CORTEX_M 1 /* Cortex-M architecture */ +/* + * Panic data goes at the end of RAM. This is safe because we don't context + * switch away from the panic handler before rebooting, and stacks and data + * start at the beginning of RAM. + */ +#define PANIC_DATA_PTR ((struct panic_data *)\ + (CONFIG_RAM_BASE + CONFIG_RAM_SIZE - sizeof(struct panic_data))) + /* Flags for panic_data.flags */ /* panic_data.frame is valid */ #define PANIC_DATA_FLAG_FRAME_VALID (1 << 0) @@ -70,6 +86,13 @@ void panic_puts(const char *s); */ void panic_printf(const char *format, ...); +/* + * Print saved panic information + * + * @param pdata pointer to saved panic data + */ +void panic_data_print(const struct panic_data *pdata); + /** * Report an assertion failure and reset * diff --git a/util/ectool.c b/util/ectool.c index 8bb079c818..db3f0262af 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -1875,7 +1875,7 @@ int cmd_panic_info(int argc, char *argv[]) { int rv; struct panic_data *pdata = (struct panic_data *)ec_inbuf; - const uint32_t *lregs = pdata->regs; + const uint32_t *lregs = pdata->cm.regs; const uint32_t *sregs = NULL; enum { ORIG_UNKNOWN = 0, @@ -1905,6 +1905,11 @@ int cmd_panic_info(int argc, char *argv[]) "Following data may be incorrect!\n", pdata->struct_version); + if (pdata->arch != PANIC_ARCH_CORTEX_M) + fprintf(stderr, "Unknown architecture (%d). " + "CPU specific data will be incorrect!\n", + pdata->arch); + printf("Saved panic data:%s\n", (pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)")); @@ -1919,7 +1924,7 @@ int cmd_panic_info(int argc, char *argv[]) * version 1. */ if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) - sregs = pdata->frame - (pdata->struct_version == 1 ? 1 : 0); + sregs = pdata->cm.frame - (pdata->struct_version == 1 ? 1 : 0); printf("=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n", panic_origins[origin], -- cgit v1.2.1