diff --git a/components/esp_system/include/esp_private/esp_int_wdt.h b/components/esp_system/include/esp_private/esp_int_wdt.h index 7166b2e2f05..a728e92c902 100644 --- a/components/esp_system/include/esp_private/esp_int_wdt.h +++ b/components/esp_system/include/esp_private/esp_int_wdt.h @@ -6,6 +6,7 @@ #pragma once +#include #include "sdkconfig.h" #ifdef __cplusplus @@ -36,6 +37,35 @@ void esp_int_wdt_init(void); */ void esp_int_wdt_cpu_init(void); +#if CONFIG_ESP_INT_WDT +/** + * @brief Pause (disable) the interrupt watchdog. + * + * @note Must be balanced by esp_int_wdt_resume(). Not nestable. + */ +void esp_int_wdt_pause(void); + +/** + * @brief Resume (re-enable and feed) the interrupt watchdog previously paused with esp_int_wdt_pause(). + */ +void esp_int_wdt_resume(void); + +#if CONFIG_ESP_INT_WDT_CHECK_CPU1 +/** + * @brief Pause or resume INT WDT CPU1 liveness checking. + * + * Distinct from esp_int_wdt_pause(): this does not disable the watchdog. + * With ESP_INT_WDT_CHECK_CPU1 enabled, CPU0 only feeds the watchdog after CPU1 has also ticked. + * When CPU1 is intentionally idle and no longer ticks (e.g. tickless WAITI). + * Call with pause=true so CPU0 can keep feeding (and stay protected). + * Call with pause=false when CPU1 is active again. + * + * @param pause true to pause the CPU1 liveness check, false to resume it + */ +void esp_int_wdt_pause_cpu1_checking(bool pause); +#endif // CONFIG_ESP_INT_WDT_CHECK_CPU1 +#endif // CONFIG_ESP_INT_WDT + #if CONFIG_ESP_INT_WDT && CONFIG_ESP32_ECO3_CACHE_LOCK_FIX /** * @brief Reconfigure WDT stage timeouts (ticks). diff --git a/components/esp_system/int_wdt.c b/components/esp_system/int_wdt.c index 8df87b8d095..b996be5a42e 100644 --- a/components/esp_system/int_wdt.c +++ b/components/esp_system/int_wdt.c @@ -114,6 +114,9 @@ void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_reconfigure_ticks(uint32_t stage0_ticks, u #if CONFIG_ESP_INT_WDT_CHECK_CPU1 volatile bool int_wdt_cpu1_ticked = false; +/* Set while CPU1 is intentionally idle (e.g. tickless idle) and therefore not ticking. The CPU1 + * liveness requirement is bypassed so CPU0 keeps feeding the watchdog (and stays protected). */ +static volatile bool s_int_wdt_cpu1_idle = false; #endif static void ESP_SYSTEM_IRAM_ATTR tick_hook(void) @@ -125,7 +128,7 @@ static void ESP_SYSTEM_IRAM_ATTR tick_hook(void) return; } #if CONFIG_ESP_INT_WDT_CHECK_CPU1 - if (int_wdt_cpu1_ticked) { + if (int_wdt_cpu1_ticked || s_int_wdt_cpu1_idle) { int_wdt_cpu1_ticked = false; } else { return; @@ -191,4 +194,26 @@ void esp_int_wdt_cpu_init(void) esp_intr_enable_source(ETS_INT_WDT_INUM); } +void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_pause(void) +{ + wdt_hal_write_protect_disable(&iwdt_context); + wdt_hal_disable(&iwdt_context); + wdt_hal_write_protect_enable(&iwdt_context); +} + +void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_resume(void) +{ + wdt_hal_write_protect_disable(&iwdt_context); + wdt_hal_feed(&iwdt_context); + wdt_hal_enable(&iwdt_context); + wdt_hal_write_protect_enable(&iwdt_context); +} + +#if CONFIG_ESP_INT_WDT_CHECK_CPU1 +void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_pause_cpu1_checking(bool pause) +{ + s_int_wdt_cpu1_idle = pause; +} +#endif // CONFIG_ESP_INT_WDT_CHECK_CPU1 + #endif // CONFIG_ESP_INT_WDT