summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2012-06-03 07:33:17 -0700
committerGerrit <chrome-bot@google.com>2012-06-15 13:39:22 -0700
commit9f2e621d8032199b727918f04430d5cd0951c0c3 (patch)
tree2adfa391c2fedad7ab015a0d59cddeec0a0c4dcd
parent9c08e8994e8e09709b096a7e6f1cb17faa0ce52c (diff)
downloadchrome-ec-9f2e621d8032199b727918f04430d5cd0951c0c3.tar.gz
Move watchdog_trace() into the generic watchdog file
We want this function to be available for all chips, so move it into a generic place. The task_disable_irq() from the LM4 version can be left in watchdog_check(), to keep the watchdog_trace() function generic. BUG=chrome-os-partner:10145 TEST=build for all boards Change-Id: I98c60ce5958f1498b84a233ef04290a68a7838c5 Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/24397 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/lm4/watchdog.c55
-rw-r--r--chip/stm32/watchdog.c33
-rw-r--r--core/cortex-m/watchdog.c38
-rw-r--r--include/watchdog.h12
4 files changed, 94 insertions, 44 deletions
diff --git a/chip/lm4/watchdog.c b/chip/lm4/watchdog.c
index 2982c8b217..e86cb15852 100644
--- a/chip/lm4/watchdog.c
+++ b/chip/lm4/watchdog.c
@@ -13,8 +13,6 @@
#include "gpio.h"
#include "hooks.h"
#include "task.h"
-#include "timer.h"
-#include "uart.h"
#include "util.h"
#include "watchdog.h"
@@ -28,47 +26,6 @@
static uint32_t watchdog_period; /* Watchdog counter initial value */
-/* 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. */
-void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp)
-{
- uint32_t psp;
- uint32_t *stack;
-
- /* 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));
- if ((excep_lr & 0xf) == 1) {
- /* we were already in exception context */
- stack = (uint32_t *)excep_sp;
- } else {
- /* we were in task context */
- stack = (uint32_t *)psp;
- }
-
- uart_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ",
- stack[6], stack[5], psp);
- 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. */
- timer_print_info();
- uart_emergency_flush();
- task_print_list();
- uart_emergency_flush();
-}
-
-
void IRQ_HANDLER(LM4_IRQ_WATCHDOG)(void) __attribute__((naked));
void IRQ_HANDLER(LM4_IRQ_WATCHDOG)(void)
{
@@ -80,8 +37,18 @@ void IRQ_HANDLER(LM4_IRQ_WATCHDOG)(void)
* R0=LR so we can pass it to task_resched_if_needed. */
"push {r0, lr}\n"
"bl watchdog_trace\n"
+ /* 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.
+ */
+ "mov r0, %[irq]\n"
+ "bl task_disable_irq\n"
"pop {r0, lr}\n"
- "b task_resched_if_needed\n");
+ "b task_resched_if_needed\n"
+ : : [irq] "i" (LM4_IRQ_WATCHDOG));
}
const struct irq_priority IRQ_BUILD_NAME(prio_, LM4_IRQ_WATCHDOG, )
__attribute__((section(".rodata.irqprio")))
diff --git a/chip/stm32/watchdog.c b/chip/stm32/watchdog.c
index da6079ac29..1fd84b2f43 100644
--- a/chip/stm32/watchdog.c
+++ b/chip/stm32/watchdog.c
@@ -34,6 +34,39 @@ void watchdog_reload(void)
}
+/**
+ * Chcek if a watchdog interrupt needs to be reported.
+ *
+ * If so, this function should call watchdog_trace()
+ *
+ * @param excep_lr Value of lr to indicate caller return
+ * @param excep_sp Value of sp to indicate caller task id
+ */
+void watchdog_check(uint32_t excep_lr, uint32_t excep_sp)
+{
+ /* This is not actually called for now, since we reset instead */
+}
+
+
+void IRQ_HANDLER(STM32_IRQ_WWDG)(void) __attribute__((naked));
+void IRQ_HANDLER(STM32_IRQ_WWDG)(void)
+{
+ /* Naked call so we can extract raw LR and SP */
+ asm volatile("mov r0, lr\n"
+ "mov r1, sp\n"
+ /* Must push registers in pairs to keep 64-bit aligned
+ * stack for ARM EABI. This also conveninently saves
+ * R0=LR so we can pass it to task_resched_if_needed. */
+ "push {r0, lr}\n"
+ "bl watchdog_check\n"
+ "pop {r0, lr}\n"
+ "b task_resched_if_needed\n");
+}
+const struct irq_priority IRQ_BUILD_NAME(prio_, STM32_IRQ_WWDG, )
+ __attribute__((section(".rodata.irqprio")))
+ = {STM32_IRQ_WWDG, 0}; /* put the watchdog at the highest
+ priority */
+
int watchdog_init(void)
{
uint32_t watchdog_period;
diff --git a/core/cortex-m/watchdog.c b/core/cortex-m/watchdog.c
index e0a58953fb..3ad89e94ab 100644
--- a/core/cortex-m/watchdog.c
+++ b/core/cortex-m/watchdog.c
@@ -5,10 +5,48 @@
/* Watchdog common code */
+#include "board.h"
+#include "common.h"
+#include "config.h"
+#include "registers.h"
+#include "task.h"
#include "timer.h"
+#include "uart.h"
#include "watchdog.h"
+void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp)
+{
+ uint32_t psp;
+ uint32_t *stack;
+
+ asm("mrs %0, psp" : "=r"(psp));
+ if ((excep_lr & 0xf) == 1) {
+ /* we were already in exception context */
+ stack = (uint32_t *)excep_sp;
+ } else {
+ /* we were in task context */
+ stack = (uint32_t *)psp;
+ }
+
+ uart_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ",
+ stack[6], stack[5], psp);
+ 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. */
+ timer_print_info();
+ uart_emergency_flush();
+ task_print_list();
+ uart_emergency_flush();
+}
+
+
/* Low priority task to reload the watchdog */
void watchdog_task(void)
{
diff --git a/include/watchdog.h b/include/watchdog.h
index b4d0a1e2f6..46f3b996d7 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -20,6 +20,18 @@
* more than 2 watchdog periods since watchdog_reload() has been called. */
int watchdog_init(void);
+/**
+ * Display a trace with information about an expired watchdog timer
+ *
+ * This shows the location in the code where the expiration happened.
+ * Usually this helps locate a loop which is blocking execution of the
+ * watchdog task.
+ *
+ * @param excep_lr Value of lr to indicate caller return
+ * @param excep_sp Value of sp to indicate caller task id
+ */
+void watchdog_trace(uint32_t excep_lr, uint32_t excep_sp);
+
/* Reload the watchdog counter */
void watchdog_reload(void);