summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/lm4/watchdog.c44
-rw-r--r--common/main.c4
-rw-r--r--core/cortex-m/task.c47
-rw-r--r--core/cortex-m/timer.c54
-rw-r--r--include/task.h9
-rw-r--r--include/timer.h43
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 */