diff --git a/chip/lm4/watchdog.c b/chip/lm4/watchdog.c index 248d895369..65c5ad2d2a 100644 --- a/chip/lm4/watchdog.c +++ b/chip/lm4/watchdog.c @@ -25,6 +25,9 @@ #define LM4_WATCHDOG_MAGIC_WORD 0x1ACCE551 #define WATCHDOG_PERIOD_MS 1100 /* Watchdog period in ms */ +#define WATCHDOG_RELOAD_MS 500 /* Interval in ms between reloads of the + * watchdog timer. Should be less than half + * of the watchdog period. */ static uint32_t watchdog_period; /* Watchdog counter initial value */ @@ -93,20 +96,24 @@ void watchdog_reload(void) { uint32_t status = LM4_WATCHDOG_RIS(0); - /* unlock watchdog registers */ + /* Unlock watchdog registers */ LM4_WATCHDOG_LOCK(0) = LM4_WATCHDOG_MAGIC_WORD; - /* As we reboot only on the second time-out, - * if we have already reached 1 time-out - * we need to reset the interrupt bit. - */ - if (status) + /* As we reboot only on the second timeout, if we have already reached + * the first timeout we need to reset the interrupt bit. */ + if (status) { LM4_WATCHDOG_ICR(0) = status; + /* That doesn't seem to unpend the watchdog interrupt (even if + * we do dummy writes to force the write to be committed), so + * explicitly unpend the interrupt before re-enabling it. */ + task_clear_pending_irq(LM4_IRQ_WATCHDOG); + task_enable_irq(LM4_IRQ_WATCHDOG); + } - /* reload the watchdog counter */ + /* Reload the watchdog counter */ LM4_WATCHDOG_LOAD(0) = watchdog_period; - /* re-lock watchdog registers */ + /* Re-lock watchdog registers */ LM4_WATCHDOG_LOCK(0) = 0xdeaddead; } @@ -134,12 +141,11 @@ int watchdog_init(void) watchdog_clock_changed(clock_get_freq()); LM4_WATCHDOG_LOAD(0) = watchdog_period; - /* de-activate the watchdog when the JTAG stops the CPU */ + /* De-activate the watchdog when the JTAG stops the CPU */ LM4_WATCHDOG_TEST(0) |= 1 << 8; - /* reset after 2 time-out, - * activate the watchdog and lock the control register - */ + /* Reset after 2 time-out, activate the watchdog and lock the control + * register. */ LM4_WATCHDOG_CTL(0) = 0x3; /* Reset watchdog interrupt bits */ @@ -154,6 +160,7 @@ int watchdog_init(void) return EC_SUCCESS; } + /* Low priority task to reload the watchdog */ void watchdog_task(void) { @@ -166,12 +173,12 @@ void watchdog_task(void) #ifdef BOARD_bds gpio_set_level(GPIO_DEBUG_LED, 1); #endif - usleep(500000); + usleep(WATCHDOG_RELOAD_MS * 1000); watchdog_reload(); #ifdef BOARD_bds gpio_set_level(GPIO_DEBUG_LED, 0); #endif - usleep(500000); + usleep(WATCHDOG_RELOAD_MS * 1000); watchdog_reload(); } } diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c index e91212f735..de3b6f6fb7 100644 --- a/core/cortex-m/task.c +++ b/core/cortex-m/task.c @@ -302,6 +302,12 @@ void task_disable_irq(int irq) } +void task_clear_pending_irq(int irq) +{ + CPU_NVIC_UNPEND(irq / 32) = 1 << (irq % 32); +} + + void task_trigger_irq(int irq) { CPU_NVIC_SWTRIG = irq; diff --git a/include/task.h b/include/task.h index 5644d4078e..5855bdfeb5 100644 --- a/include/task.h +++ b/include/task.h @@ -94,6 +94,15 @@ void task_disable_irq(int irq); /* Software-triggers an interrupt. */ void task_trigger_irq(int irq); +/* Clears a pending interrupt. + * + * Note that most interrupts can be removed from the pending state simply by + * handling whatever caused the interrupt in the first place. This only needs + * to be called if an interrupt handler disables itself without clearing the + * reason for the interrupt, and then the interrupt is re-enabled from a + * different context. */ +void task_clear_pending_irq(int irq); + struct mutex { uint32_t lock; uint32_t waiters;