mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
refactor(esp_system): ind_wdt.c refactor & code clean
1. introduce reconfigure_ticks function for wdt configuration 2. move esp32eco3 cache livelock workaround code out from int_wdt.c
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define IWDT_INITIAL_TIMEOUT_S (5)
|
||||
#define IWDT_TICKS_PER_US (500)
|
||||
#define IWDT_STAGE0_TIMEOUT_US (CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US)
|
||||
#define IWDT_STAGE1_TIMEOUT_US (2 * IWDT_STAGE0_TIMEOUT_US)
|
||||
#define IWDT_INITIAL_TIMEOUT_US (IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US)
|
||||
|
||||
/**
|
||||
* @brief Initialize the non-CPU-specific parts of interrupt watchdog.
|
||||
*
|
||||
@@ -28,6 +36,18 @@ void esp_int_wdt_init(void);
|
||||
*/
|
||||
void esp_int_wdt_cpu_init(void);
|
||||
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
/**
|
||||
* @brief Reconfigure WDT stage timeouts (ticks).
|
||||
*
|
||||
* Low-level API used by the livelock workaround. Prefer esp_int_wdt_livelock_workaround() for sleep flows.
|
||||
*
|
||||
* @param stage0_ticks Stage0 timeout ticks
|
||||
* @param stage1_ticks Stage1 timeout ticks
|
||||
*/
|
||||
void esp_int_wdt_reconfigure_ticks(uint32_t stage0_ticks, uint32_t stage1_ticks);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "hal/wdt_hal.h"
|
||||
#include "soc/system_intr.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
@@ -28,14 +29,16 @@
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
#include "esp_private/eco3_livelock_workaround.h"
|
||||
#endif
|
||||
|
||||
#if TIMG_LL_GET(INST_NUM) > 1
|
||||
|
||||
/* If we have two hardware timer groups, use the second one for interrupt watchdog. */
|
||||
#define WDT_LEVEL_INTR_SOURCE SYS_TG1_WDT_INTR_SOURCE
|
||||
#define IWDT_PRESCALER MWDT_LL_DEFAULT_CLK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
|
||||
#define IWDT_TICKS_PER_US 500
|
||||
#define IWDT_INSTANCE WDT_MWDT1
|
||||
#define IWDT_INITIAL_TIMEOUT_S 5
|
||||
#define IWDT_PERIPH PERIPH_TIMG1_MODULE
|
||||
#define IWDT_TIMER_GROUP 1
|
||||
|
||||
@@ -43,9 +46,7 @@
|
||||
|
||||
#define WDT_LEVEL_INTR_SOURCE SYS_TG0_WDT_INTR_SOURCE
|
||||
#define IWDT_PRESCALER MWDT_LL_DEFAULT_CLK_PRESCALER // Tick period of 500us if WDT source clock is 80MHz
|
||||
#define IWDT_TICKS_PER_US 500
|
||||
#define IWDT_INSTANCE WDT_MWDT0
|
||||
#define IWDT_INITIAL_TIMEOUT_S 5
|
||||
#define IWDT_PERIPH PERIPH_TIMG0_MODULE
|
||||
#define IWDT_TIMER_GROUP 0
|
||||
|
||||
@@ -86,14 +87,24 @@ static esp_err_t esp_int_wdt_retention_enable(uint32_t group_id)
|
||||
#endif
|
||||
|
||||
static wdt_hal_context_t iwdt_context;
|
||||
static portMUX_TYPE s_iwdt_configure_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static void ESP_SYSTEM_IRAM_ATTR reconfigure_ticks(uint32_t stage0_ticks, uint32_t stage1_ticks)
|
||||
{
|
||||
portENTER_CRITICAL_SAFE(&s_iwdt_configure_lock);
|
||||
wdt_hal_write_protect_disable(&iwdt_context);
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, stage0_ticks, WDT_STAGE_ACTION_INT);
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, stage1_ticks, WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||
wdt_hal_feed(&iwdt_context);
|
||||
wdt_hal_write_protect_enable(&iwdt_context);
|
||||
portEXIT_CRITICAL_SAFE(&s_iwdt_configure_lock);
|
||||
}
|
||||
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
/*
|
||||
* This parameter is used to indicate the response time of Interrupt watchdog to
|
||||
* identify the live lock.
|
||||
*/
|
||||
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
|
||||
extern uint32_t _lx_intr_livelock_counter, _lx_intr_livelock_max;
|
||||
void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_reconfigure_ticks(uint32_t stage0_ticks, uint32_t stage1_ticks)
|
||||
{
|
||||
reconfigure_ticks(stage0_ticks, stage1_ticks);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_INT_WDT_CHECK_CPU1
|
||||
@@ -102,41 +113,25 @@ volatile bool int_wdt_cpu1_ticked = false;
|
||||
|
||||
static void ESP_SYSTEM_IRAM_ATTR tick_hook(void)
|
||||
{
|
||||
if (esp_cpu_get_core_id() != 0) {
|
||||
#if CONFIG_ESP_INT_WDT_CHECK_CPU1
|
||||
if (esp_cpu_get_core_id() != 0) {
|
||||
int_wdt_cpu1_ticked = true;
|
||||
} else {
|
||||
// Only feed wdt if app cpu also ticked.
|
||||
if (int_wdt_cpu1_ticked) {
|
||||
// Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
|
||||
wdt_hal_write_protect_disable(&iwdt_context);
|
||||
// Reconfigure stage timeouts
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
_lx_intr_livelock_counter = 0;
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0,
|
||||
CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / (_lx_intr_livelock_max + 1), WDT_STAGE_ACTION_INT); // Set timeout before interrupt
|
||||
#else
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); // Set timeout before interrupt
|
||||
#endif
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); // Set timeout before reset
|
||||
wdt_hal_feed(&iwdt_context);
|
||||
wdt_hal_write_protect_enable(&iwdt_context);
|
||||
int_wdt_cpu1_ticked = false;
|
||||
}
|
||||
}
|
||||
#else // CONFIG_ESP_INT_WDT_CHECK_CPU1
|
||||
if (esp_cpu_get_core_id() != 0) {
|
||||
return;
|
||||
} else {
|
||||
// Todo: Check if there's a way to avoid reconfiguring the stages on each feed.
|
||||
wdt_hal_write_protect_disable(&iwdt_context);
|
||||
// Reconfigure stage timeouts
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); // Set timeout before interrupt
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); // Set timeout before reset
|
||||
wdt_hal_feed(&iwdt_context);
|
||||
wdt_hal_write_protect_enable(&iwdt_context);
|
||||
}
|
||||
#endif // CONFIG_ESP_INT_WDT_CHECK_CPU1
|
||||
#if CONFIG_ESP_INT_WDT_CHECK_CPU1
|
||||
if (int_wdt_cpu1_ticked) {
|
||||
int_wdt_cpu1_ticked = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
esp_int_wdt_set_livelock_params(CONFIG_ESP_INT_WDT_TIMEOUT_MS);
|
||||
reconfigure_ticks(esp_int_wdt_livelock_get_feed_stage0_ticks(), IWDT_STAGE1_TIMEOUT_US);
|
||||
#else
|
||||
reconfigure_ticks(IWDT_STAGE0_TIMEOUT_US, IWDT_STAGE1_TIMEOUT_US);
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_int_wdt_init(void)
|
||||
@@ -153,9 +148,9 @@ void esp_int_wdt_init(void)
|
||||
* Todo: Fix this
|
||||
*/
|
||||
wdt_hal_init(&iwdt_context, IWDT_INSTANCE, IWDT_PRESCALER, true);
|
||||
reconfigure_ticks(IWDT_INITIAL_TIMEOUT_US, IWDT_INITIAL_TIMEOUT_US);
|
||||
|
||||
wdt_hal_write_protect_disable(&iwdt_context);
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT);
|
||||
wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM);
|
||||
wdt_hal_enable(&iwdt_context);
|
||||
wdt_hal_write_protect_enable(&iwdt_context);
|
||||
|
||||
@@ -163,34 +158,14 @@ void esp_int_wdt_init(void)
|
||||
esp_int_wdt_retention_enable(IWDT_TIMER_GROUP);
|
||||
#endif
|
||||
|
||||
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
|
||||
#define APB_DCRSET (0x200c)
|
||||
#define APB_ITCTRL (0x3f00)
|
||||
#define ERI_ADDR(APB) (0x100000 + (APB))
|
||||
#define _SYM2STR(x) # x
|
||||
#define SYM2STR(x) _SYM2STR(x)
|
||||
|
||||
uint32_t eriadrs, scratch = 0, immediate = 0;
|
||||
if (soc_has_cache_lock_bug()) {
|
||||
if (xPortGetCoreID() != CONFIG_BTDM_CTRL_PINNED_TO_CORE) {
|
||||
__asm__ __volatile__(
|
||||
/* Enable Xtensa Debug Module Integration Mode */
|
||||
"movi %[ERI], " SYM2STR(ERI_ADDR(APB_ITCTRL)) "\n"
|
||||
"rer %[REG], %[ERI]\n"
|
||||
"movi %[IMM], 1\n"
|
||||
"or %[REG], %[IMM], %[REG]\n"
|
||||
"wer %[REG], %[ERI]\n"
|
||||
/* Enable Xtensa Debug Module Break_In signal */
|
||||
"movi %[ERI], " SYM2STR(ERI_ADDR(APB_DCRSET)) "\n"
|
||||
"rer %[REG], %[ERI]\n"
|
||||
"movi %[IMM], 0x10000\n"
|
||||
"or %[REG], %[IMM], %[REG]\n"
|
||||
"wer %[REG], %[ERI]\n"
|
||||
: [ERI] "=r"(eriadrs), [REG] "+r"(scratch), [IMM] "+r"(immediate)
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif // (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
/*
|
||||
* This is a workaround for issue WDT-3.15 in "ESP32 ECO and workarounds for
|
||||
* Bugs" document.
|
||||
*/
|
||||
esp_int_wdt_init_for_livelock_fix();
|
||||
esp_int_wdt_set_livelock_params(CONFIG_ESP_INT_WDT_TIMEOUT_MS);
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_int_wdt_cpu_init(void)
|
||||
@@ -207,18 +182,6 @@ void esp_int_wdt_cpu_init(void)
|
||||
#if SOC_CPU_HAS_FLEXIBLE_INTC
|
||||
esp_cpu_intr_set_type(ETS_INT_WDT_INUM, INTR_TYPE_LEVEL);
|
||||
esp_cpu_intr_set_priority(ETS_INT_WDT_INUM, SOC_INTERRUPT_LEVEL_MEDIUM);
|
||||
#endif
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
/*
|
||||
* This is a workaround for issue WDT-3.15 in "ESP32 ECO and workarounds for
|
||||
* Bugs" document.
|
||||
*/
|
||||
_lx_intr_livelock_counter = 0;
|
||||
if (soc_has_cache_lock_bug()) {
|
||||
assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS);
|
||||
assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS * 3));
|
||||
_lx_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1;
|
||||
}
|
||||
#endif
|
||||
esp_intr_enable_source(ETS_INT_WDT_INUM);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the livelock workaround and reconfigure the interrupt WDT.
|
||||
*
|
||||
* @param enable true to enable livelock workaround, false to disable
|
||||
*/
|
||||
void esp_int_wdt_livelock_workaround(bool enable);
|
||||
|
||||
/**
|
||||
* @brief Get stage0 ticks for a feed (from current livelock params).
|
||||
*
|
||||
* @return stage0 timeout ticks
|
||||
*/
|
||||
uint32_t esp_int_wdt_livelock_get_feed_stage0_ticks(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize interrupt watchdog for livelock fix workaround
|
||||
*/
|
||||
void esp_int_wdt_init_for_livelock_fix(void);
|
||||
|
||||
/**
|
||||
* @brief Set livelock workaround params (window count from timeout, reset counter)
|
||||
*
|
||||
* Call at CPU init and when (re-)enabling the livelock workaround.
|
||||
*
|
||||
* @param timeout_ms Interrupt watchdog timeout in milliseconds
|
||||
*/
|
||||
void esp_int_wdt_set_livelock_params(uint32_t timeout_ms);
|
||||
|
||||
/**
|
||||
* @brief Reset livelock params (counter and max to 0) when disabling the livelock workaround
|
||||
*/
|
||||
void esp_int_wdt_reset_livelock_params(void);
|
||||
|
||||
#endif // CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -4,6 +4,10 @@ set(srcs "highint_hdl.S"
|
||||
"system_internal.c"
|
||||
"cache_err_int.c")
|
||||
|
||||
if(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX)
|
||||
list(APPEND srcs "eco3_livelock_workaround.c")
|
||||
endif()
|
||||
|
||||
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs})
|
||||
|
||||
target_sources(${COMPONENT_LIB} PRIVATE ${srcs})
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "esp_chip_info.h"
|
||||
#include "esp_private/esp_system_attr.h"
|
||||
#include "esp_private/esp_int_wdt.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#define IWDT_LIVELOCK_TIMEOUT_MS (20)
|
||||
|
||||
extern uint32_t _lx_intr_livelock_counter, _lx_intr_livelock_max;
|
||||
|
||||
void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_reset_livelock_params(void)
|
||||
{
|
||||
if (soc_has_cache_lock_bug()) {
|
||||
_lx_intr_livelock_counter = 0;
|
||||
_lx_intr_livelock_max = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_Static_assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS, "portTICK_PERIOD_MS must be less than or equal to IWDT_LIVELOCK_TIMEOUT_MS");
|
||||
_Static_assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS * 3), "CONFIG_ESP_INT_WDT_TIMEOUT_MS must be greater than or equal to IWDT_LIVELOCK_TIMEOUT_MS * 3");
|
||||
|
||||
ESP_SYSTEM_IRAM_ATTR void esp_int_wdt_set_livelock_params(uint32_t timeout_ms)
|
||||
{
|
||||
_lx_intr_livelock_counter = 0;
|
||||
if (soc_has_cache_lock_bug()) {
|
||||
_lx_intr_livelock_max = timeout_ms / IWDT_LIVELOCK_TIMEOUT_MS - 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ESP_SYSTEM_IRAM_ATTR esp_int_wdt_livelock_get_feed_stage0_ticks(void)
|
||||
{
|
||||
return IWDT_STAGE0_TIMEOUT_US / (_lx_intr_livelock_max + 1);
|
||||
}
|
||||
|
||||
void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_livelock_workaround(bool enable)
|
||||
{
|
||||
uint32_t stage0_ticks = IWDT_STAGE0_TIMEOUT_US;
|
||||
if (enable) {
|
||||
esp_int_wdt_set_livelock_params(CONFIG_ESP_INT_WDT_TIMEOUT_MS);
|
||||
stage0_ticks = esp_int_wdt_livelock_get_feed_stage0_ticks();
|
||||
} else {
|
||||
esp_int_wdt_reset_livelock_params();
|
||||
}
|
||||
esp_int_wdt_reconfigure_ticks(stage0_ticks, IWDT_STAGE1_TIMEOUT_US);
|
||||
}
|
||||
|
||||
void esp_int_wdt_init_for_livelock_fix(void)
|
||||
{
|
||||
#if CONFIG_BTDM_CTRL_HLI
|
||||
#define APB_DCRSET (0x200c)
|
||||
#define APB_ITCTRL (0x3f00)
|
||||
#define ERI_ADDR(APB) (0x100000 + (APB))
|
||||
#define _SYM2STR(x) # x
|
||||
#define SYM2STR(x) _SYM2STR(x)
|
||||
|
||||
if (soc_has_cache_lock_bug()) {
|
||||
if (xPortGetCoreID() != CONFIG_BTDM_CTRL_PINNED_TO_CORE) {
|
||||
uint32_t eriadrs, scratch = 0, immediate = 0;
|
||||
__asm__ __volatile__(
|
||||
/* Enable Xtensa Debug Module Integration Mode */
|
||||
"movi %[ERI], " SYM2STR(ERI_ADDR(APB_ITCTRL)) "\n"
|
||||
"rer %[REG], %[ERI]\n"
|
||||
"movi %[IMM], 1\n"
|
||||
"or %[REG], %[IMM], %[REG]\n"
|
||||
"wer %[REG], %[ERI]\n"
|
||||
/* Enable Xtensa Debug Module Break_In signal */
|
||||
"movi %[ERI], " SYM2STR(ERI_ADDR(APB_DCRSET)) "\n"
|
||||
"rer %[REG], %[ERI]\n"
|
||||
"movi %[IMM], 0x10000\n"
|
||||
"or %[REG], %[IMM], %[REG]\n"
|
||||
"wer %[REG], %[ERI]\n"
|
||||
: [ERI] "=r"(eriadrs), [REG] "+r"(scratch), [IMM] "+r"(immediate)
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_BTDM_CTRL_HLI
|
||||
}
|
||||
Reference in New Issue
Block a user