Merge "Watchdog fixes"

This commit is contained in:
Gerrit
2012-04-25 16:56:04 -07:00
committed by Gerrit Code Review
6 changed files with 113 additions and 88 deletions

View File

@@ -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;

View File

@@ -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(),

View File

@@ -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,6 +489,23 @@ void mutex_unlock(struct mutex *mtx)
}
void task_print_list(void)
{
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);
if (in_interrupt_context())
uart_emergency_flush();
else
cflush();
}
}
#ifdef CONFIG_DEBUG
@@ -491,17 +513,10 @@ int command_task_info(int argc, char **argv)
{
#ifdef CONFIG_TASK_PROFILING
int total = 0;
#endif
int i;
#endif
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();
}
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)

View File

@@ -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);

View File

@@ -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.
*

View File

@@ -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 */