From 54a15b81f98692bafc062c729dd5b73fa98e51c2 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 26 Feb 2024 12:09:07 +0800 Subject: [PATCH] feat: support cache safe assertion check in sleep process - Add support for cache safe assertion check to ensure that code expected to be in RAM is in IRAM --- components/esp_hw_support/Kconfig | 11 +++++ components/esp_hw_support/sleep_modes.c | 49 ++++++++++++++++--- .../sdkconfig.ci.pd_vddsdio | 3 ++ 3 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.pd_vddsdio diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 5aa11dc938..8cd5bee961 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -192,6 +192,17 @@ menu "Hardware Settings" NOTE: Enabling these callbacks may change sleep duration calculations based on time spent in callback and hence it is highly recommended to keep them as short as possible. + + config ESP_SLEEP_CACHE_SAFE_ASSERTION + bool "Check the cache safety of the sleep wakeup code in sleep process" + default n + select ESP_PANIC_HANDLER_IRAM + help + Enabling it will check the cache safety of the code before the flash power is ready after + light sleep wakeup, and check PM_SLP_IRAM_OPT related code cache safety. This option is + only for code quality inspection. Enabling it will increase the time overhead of entering + and exiting sleep. It is not recommended to enable it in the release version. + endmenu menu "ESP_SLEEP_WORKAROUND" diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index b6f30498b8..f793c8104d 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -404,6 +404,23 @@ void esp_deep_sleep_deregister_hook(esp_deep_sleep_cb_t old_dslp_cb) portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); } +static int s_cache_suspend_cnt = 0; + +static void IRAM_ATTR suspend_cache(void) { + s_cache_suspend_cnt++; + if (s_cache_suspend_cnt == 1) { + cache_hal_suspend(CACHE_TYPE_ALL); + } +} + +static void IRAM_ATTR resume_cache(void) { + s_cache_suspend_cnt--; + assert(s_cache_suspend_cnt >= 0 && "cache resume doesn't match suspend ops"); + if (s_cache_suspend_cnt == 0) { + cache_hal_resume(CACHE_TYPE_ALL); + } +} + // [refactor-todo] provide target logic for body of uart functions below static void IRAM_ATTR flush_uarts(void) { @@ -477,7 +494,12 @@ static bool light_sleep_uart_prepare(uint32_t pd_flags, int64_t sleep_duration) #if !SOC_PM_SUPPORT_TOP_PD || !CONFIG_ESP_CONSOLE_UART suspend_uarts(); #else - if (pd_flags & PMU_SLEEP_PD_TOP) { +#ifdef CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION +#define FORCE_FLUSH_CONSOLE_UART 1 +#else +#define FORCE_FLUSH_CONSOLE_UART 0 +#endif + if (FORCE_FLUSH_CONSOLE_UART || (pd_flags & PMU_SLEEP_PD_TOP)) { if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) && // +1 is for cover the last character flush time (sleep_duration < (int64_t)((UART_LL_FIFO_DEF_LEN - uart_ll_get_txfifo_len(CONSOLE_UART_DEV) + 1) * UART_FLUSH_US_PER_CHAR) + SLEEP_UART_FLUSH_DONE_TO_SLEEP_US)) { @@ -775,8 +797,8 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif #endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY } else { - /* Wait cache idle in cache suspend to avoid cache load wrong data after spi io isolation */ - cache_hal_suspend(CACHE_TYPE_ALL); + /* Cache Suspend 1: will wait cache idle in cache suspend to avoid cache load wrong data after spi io isolation */ + suspend_cache(); /* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode. In order to avoid the leakage of the SPI cs pin, hold it here */ #if (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND) @@ -809,8 +831,8 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m } #endif #endif - /* Resume cache for continue running */ - cache_hal_resume(CACHE_TYPE_ALL); + /* Cache Resume 1: Resume cache for continue running*/ + resume_cache(); } #if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND @@ -820,6 +842,14 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m #endif } +#if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION + if (pd_flags & RTC_SLEEP_PD_VDDSDIO) { + /* Cache Suspend 2: If previous sleep powerdowned the flash, suspend cache here so that the + access to flash before flash ready can be explicitly exposed. */ + suspend_cache(); + } +#endif + // Restore CPU frequency #if SOC_PM_SUPPORT_PMU_MODEM_STATE if (pmu_sleep_pll_already_enabled()) { @@ -1009,6 +1039,13 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, esp_rom_delay_us(flash_enable_time_us); } +#if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION + if (pd_flags & RTC_SLEEP_PD_VDDSDIO) { + /* Cache Resume 2: flash is ready now, we can resume the cache and access flash safely after */ + resume_cache(); + } +#endif + return reject; } diff --git a/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.pd_vddsdio b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.pd_vddsdio new file mode 100644 index 0000000000..42890166e9 --- /dev/null +++ b/components/esp_system/test_apps/esp_system_unity_tests/sdkconfig.ci.pd_vddsdio @@ -0,0 +1,3 @@ +CONFIG_PM_SLP_IRAM_OPT=y +CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y +CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION=y