diff options
-rw-r--r-- | chip/lm4/watchdog.c | 44 | ||||
-rw-r--r-- | common/main.c | 4 | ||||
-rw-r--r-- | core/cortex-m/task.c | 47 | ||||
-rw-r--r-- | core/cortex-m/timer.c | 54 | ||||
-rw-r--r-- | include/task.h | 9 | ||||
-rw-r--r-- | include/timer.h | 43 |
6 files changed, 113 insertions, 88 deletions
diff --git a/chip/lm4/watchdog.c b/chip/lm4/watchdog.c index 45eb3a36e9..7ef2b36b97 100644 --- a/chip/lm4/watchdog.c +++ b/chip/lm4/watchdog.c @@ -32,11 +32,6 @@ static uint32_t watchdog_period; /* Watchdog counter initial value */ -/* console debug command prototypes */ -int command_task_info(int argc, char **argv); -int command_timer_info(int argc, char **argv); - - /* Watchdog debug trace. This is triggered if the watchdog has not been * reloaded after 1x the timeout period, after 2x the period an hardware reset * is triggering. */ @@ -45,11 +40,10 @@ void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp) uint32_t psp; uint32_t *stack; - /* we do NOT reset the watchdog interrupt here, it will be done in - * watchdog_reload() or fire the reset - * instead de-activate the interrupt in the NVIC : - * so, we will get the trace only once - */ + /* Do NOT reset the watchdog interrupt here; it will be done in + * watchdog_reload(), or reset will be triggered if we don't call that + * by the next watchdog period. Instead, de-activate the interrupt in + * the NVIC, so the watchdog trace will only be printed once. */ task_disable_irq(LM4_IRQ_WATCHDOG); asm("mrs %0, psp":"=r"(psp)); @@ -61,17 +55,20 @@ void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp) stack = (uint32_t *)psp; } - uart_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ###\n", + uart_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ", stack[6], stack[5], psp); - /* ensure this debug message is always flushed to the UART */ + if ((excep_lr & 0xf) == 1) + uart_puts("(exc) ###\n"); + else + uart_printf("(task %d) ###\n", task_from_addr(psp)); + /* Ensure this debug message is always flushed to the UART */ uart_emergency_flush(); - /* if we are blocked in a high priority IT handler, the following - * debug messages might not appear but they are useless in that - * situation. - */ - command_task_info(0, NULL); + + /* 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(); - command_timer_info(0, NULL); + task_print_list(); uart_emergency_flush(); } @@ -125,6 +122,10 @@ static int watchdog_freq_changed(void) { /* Set the timeout period */ watchdog_period = WATCHDOG_PERIOD_MS * (clock_get_freq() / 1000); + + /* Reload the watchdog timer now */ + watchdog_reload(); + return EC_SUCCESS; } DECLARE_HOOK(HOOK_FREQ_CHANGE, watchdog_freq_changed, HOOK_PRIO_DEFAULT); @@ -139,12 +140,11 @@ int watchdog_init(void) /* Wait 3 clock cycles before using the module */ scratch = LM4_SYSTEM_RCGCWD; - /* Unlock watchdog registers */ - LM4_WATCHDOG_LOCK(0) = LM4_WATCHDOG_MAGIC_WORD; - /* Set initial timeout period */ watchdog_freq_changed(); - LM4_WATCHDOG_LOAD(0) = watchdog_period; + + /* Unlock watchdog registers */ + LM4_WATCHDOG_LOCK(0) = LM4_WATCHDOG_MAGIC_WORD; /* De-activate the watchdog when the JTAG stops the CPU */ LM4_WATCHDOG_TEST(0) |= 1 << 8; diff --git a/common/main.c b/common/main.c index 8252a231d0..044ae45027 100644 --- a/common/main.c +++ b/common/main.c @@ -107,8 +107,8 @@ int main(void) /* Print the init time and reset cause. Init time isn't completely * accurate because it can't take into account the time for the first * few module inits, but it'll at least catch the majority of them. */ - uart_printf("\n\n--- Chrome EC initialized in %d us ---\n", - get_time().le.lo); + uart_printf("\n\n--- Chrome EC initialized in %ld us ---\n", + get_time().val); uart_printf("build: %s\n", system_get_build_info()); uart_printf("(image: %s, last reset: %s)\n", system_get_image_copy_string(), diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c index 3f63797146..b21d2cd59c 100644 --- a/core/cortex-m/task.c +++ b/core/cortex-m/task.c @@ -12,6 +12,7 @@ #include "link_defs.h" #include "task.h" #include "timer.h" +#include "uart.h" #include "util.h" /** @@ -191,9 +192,9 @@ inline int get_interrupt_context(void) } -task_id_t task_get_current(void) +task_id_t task_from_addr(uint32_t addr) { - task_id_t id = __get_current() - tasks; + task_id_t id = (addr - (uint32_t)tasks) >> TASK_SIZE_LOG2; if (id >= TASK_ID_COUNT) id = TASK_ID_INVALID; @@ -201,6 +202,12 @@ task_id_t task_get_current(void) } +task_id_t task_get_current(void) +{ + return task_from_addr((uint32_t)__get_current()); +} + + uint32_t *task_get_event_bitmap(task_id_t tskid) { task_ *tsk = __task_id_to_ptr(tskid); @@ -208,9 +215,7 @@ uint32_t *task_get_event_bitmap(task_id_t tskid) } -/** - * scheduling system call - */ +/* Scheduling system call */ void svc_handler(int desched, task_id_t resched) { task_ *current, *next; @@ -484,24 +489,34 @@ void mutex_unlock(struct mutex *mtx) } -#ifdef CONFIG_DEBUG - - -int command_task_info(int argc, char **argv) +void task_print_list(void) { -#ifdef CONFIG_TASK_PROFILING - int total = 0; -#endif int i; - ccputs("Task Ready Name Events Time (us)\n"); for (i = 0; i < TASK_ID_COUNT; i++) { char is_ready = (tasks_ready & (1<<i)) ? 'R' : ' '; ccprintf("%4d %c %-16s %08x %10ld\n", i, is_ready, task_names[i], tasks[i].events, tasks[i].runtime); - cflush(); + if (in_interrupt_context()) + uart_emergency_flush(); + else + cflush(); } +} + + +#ifdef CONFIG_DEBUG + + +int command_task_info(int argc, char **argv) +{ +#ifdef CONFIG_TASK_PROFILING + int total = 0; + int i; +#endif + + task_print_list(); #ifdef CONFIG_TASK_PROFILING ccputs("IRQ counts by type:\n"); @@ -539,7 +554,9 @@ static int command_task_ready(int argc, char **argv) return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(taskready, command_task_ready); -#endif + + +#endif /* CONFIG_DEBUG */ int task_pre_init(void) diff --git a/core/cortex-m/timer.c b/core/cortex-m/timer.c index 1501b0e269..d8123d1686 100644 --- a/core/cortex-m/timer.c +++ b/core/cortex-m/timer.c @@ -23,12 +23,12 @@ 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 */ @@ -37,11 +37,7 @@ static void expire_timer(task_id_t tskid) task_set_event(tskid, TASK_EVENT_TIMER, 0); } -/** - * Search the next deadline and program it in the timer hardware - * - * overflow: if true, the 32-bit counter as overflowed since the last call. - */ + void process_timers(int overflow) { uint32_t check_timer, running_t0; @@ -86,6 +82,7 @@ reprocess_timers: //TODO narrow race: deadline might have been reached before } + void udelay(unsigned us) { timestamp_t deadline = get_time(); @@ -94,6 +91,7 @@ void udelay(unsigned us) while (get_time().val < deadline.val) {} } + int timer_arm(timestamp_t tstamp, task_id_t tskid) { ASSERT(tskid < TASK_ID_COUNT); @@ -112,6 +110,7 @@ int timer_arm(timestamp_t tstamp, task_id_t tskid) return EC_SUCCESS; } + int timer_cancel(task_id_t tskid) { ASSERT(tskid < TASK_ID_COUNT); @@ -152,6 +151,31 @@ timestamp_t get_time(void) } +void timer_print_info(void) +{ + uint64_t t = get_time().val; + uint64_t deadline = (uint64_t)clksrc_high << 32 | + __hw_clock_event_get(); + int tskid; + + ccprintf("Time: 0x%016lx us\n" + "Deadline: 0x%016lx -> %10ld us from now\n" + "Active timers:\n", + t, deadline, deadline - t); + for (tskid = 0; tskid < TASK_ID_COUNT; tskid++) { + if (timer_running & (1<<tskid)) { + ccprintf(" Tsk %2d 0x%016lx -> %10ld %x\n", tskid, + timer_deadline[tskid].val, + timer_deadline[tskid].val - t, 0xabcd); + if (in_interrupt_context()) + uart_emergency_flush(); + else + cflush(); + } + } +} + + static int command_wait(int argc, char **argv) { if (argc < 2) @@ -176,23 +200,7 @@ DECLARE_CONSOLE_COMMAND(gettime, command_get_time); int command_timer_info(int argc, char **argv) { - uint64_t t = get_time().val; - uint64_t deadline = (uint64_t)clksrc_high << 32 | - __hw_clock_event_get(); - int tskid; - - ccprintf("Time: 0x%016lx us\n" - "Deadline: 0x%016lx -> %10ld us from now\n" - "Active timers:\n", - t, deadline, deadline - t); - for (tskid = 0; tskid < TASK_ID_COUNT; tskid++) { - if (timer_running & (1<<tskid)) { - ccprintf(" Tsk %2d 0x%016lx -> %10ld\n", tskid, - timer_deadline[tskid].val, - timer_deadline[tskid].val - t); - cflush(); - } - } + timer_print_info(); return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(timerinfo, command_timer_info); diff --git a/include/task.h b/include/task.h index 79289b1c08..660195460e 100644 --- a/include/task.h +++ b/include/task.h @@ -55,6 +55,11 @@ static inline void task_wake(task_id_t tskid) * When called in interrupt context, returns TASK_ID_INVALID. */ task_id_t task_get_current(void); +/* Convert an address to the corresponding task ID. The address may be a stack + * pointer or the task data for a task. Returns TASK_ID_INVALID if the address + * does not correspond to a task. */ +task_id_t task_from_addr(uint32_t addr); + /* Return a pointer to the bitmap of events of the task. */ uint32_t *task_get_event_bitmap(task_id_t tsk); @@ -70,6 +75,10 @@ uint32_t *task_get_event_bitmap(task_id_t tsk); * Returns the bitmap of received events (and clears it atomically). */ uint32_t task_wait_event(int timeout_us); +/* Prints the list of tasks using the command output channel. This may be + * called from interrupt level. */ +void task_print_list(void); + #ifdef CONFIG_TASK_PROFILING /* Start tracking an interrupt. * diff --git a/include/timer.h b/include/timer.h index b73ac292bb..4e132ebd6f 100644 --- a/include/timer.h +++ b/include/timer.h @@ -1,17 +1,17 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* 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 */ -#ifndef __EC_TIMER_H -#define __EC_TIMER_H +#ifndef __CROS_EC_TIMER_H +#define __CROS_EC_TIMER_H #include "common.h" #include "task_id.h" -/* Micro-second timestamp. */ +/* Microsecond timestamp. */ typedef union { uint64_t val; struct { @@ -23,38 +23,29 @@ typedef union { /* Initializes the Timer module. */ int timer_init(void); -/** - * Launches a one-shot timer. - * - * tstamp : timestamp in micro-seconds when the timer expires - * tskid : identifier of the task owning the timer - */ +/* Launch a one-shot timer for task <tskid> which expires at timestamp + * <tstamp>. */ int timer_arm(timestamp_t tstamp, task_id_t tskid); -/** - * Cancels a running timer. - * - * tskid : identifier of the task owning the timer - */ +/* Cancel a running timer for the specified task id. */ int timer_cancel(task_id_t tskid); -/** - * Busy wait the selected number of micro-seconds - */ +/* Busy-wait the selected number of microseconds. Note that calling this + * with us>1000 may impact system performance; use usleep for longer delays. */ void udelay(unsigned us); -/** - * Sleep during the selected number of micro-seconds - * - * The current task will be de-scheduled until the delay expired +/* Sleep during the selected number of microseconds. The current task will be + * de-scheduled until the delay expires. * * Note: if an event happens before the end of sleep, the function will return. */ void usleep(unsigned us); -/** - * Get the current timestamp from the system timer - */ +/* Get the current timestamp from the system timer. */ timestamp_t get_time(void); -#endif /* __EC_TIMER_H */ +/* Print the current timer information using the command output channel. This + * may be called from interrupt level. */ +void timer_print_info(void); + +#endif /* __CROS_EC_TIMER_H */ |