mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-04 22:11:41 +00:00
Merge "Watchdog fixes"
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user