diff --git a/components/esp_hw_support/mspi/mspi_timing_tuning/mspi_timing_tuning.c b/components/esp_hw_support/mspi/mspi_timing_tuning/mspi_timing_tuning.c index d709392f6f4..6d2f9b9c502 100644 --- a/components/esp_hw_support/mspi/mspi_timing_tuning/mspi_timing_tuning.c +++ b/components/esp_hw_support/mspi/mspi_timing_tuning/mspi_timing_tuning.c @@ -23,6 +23,7 @@ #include "hal/cache_hal.h" #endif #include "esp_private/cache_utils.h" +#include "esp_cpu.h" #include "esp_private/mspi_timing_tuning.h" #include "esp_private/mspi_timing_config.h" #include "esp_private/mspi_timing_by_mspi_delay.h" @@ -646,8 +647,21 @@ static void restore_cache(uint32_t cpuid, uint32_t saved_state) } #else // ESP_TEE_BUILD -#define disable_cache(cpuid, saved_state) spi_flash_disable_cache(cpuid, saved_state) -#define restore_cache(cpuid, saved_state) spi_flash_restore_cache(cpuid, saved_state) +static void disable_cache(uint32_t cpuid, uint32_t *saved_state) +{ +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_disable(); +#endif + spi_flash_disable_cache(cpuid, saved_state); +} + +static void restore_cache(uint32_t cpuid, uint32_t saved_state) +{ + spi_flash_restore_cache(cpuid, saved_state); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif +} #endif diff --git a/components/esp_hw_support/sleep_cache.c b/components/esp_hw_support/sleep_cache.c index 0ef117801ee..6c94767e954 100644 --- a/components/esp_hw_support/sleep_cache.c +++ b/components/esp_hw_support/sleep_cache.c @@ -31,6 +31,9 @@ void sleep_cache_suspend(void) // If the access to external memory hits in the cache, it will not trigger a cache error. So in order to // fully check the access to external memory, writeback & invalidate is needed here. Cache_WriteBack_Invalidate_All(CACHE_MAP_MASK); +#endif +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_disable(); #endif spi_flash_disable_cache(esp_cpu_get_core_id(), &s_cache_state); } @@ -43,6 +46,9 @@ void sleep_cache_resume(void) assert(s_cache_suspend_cnt >= 0 && DRAM_STR("cache resume doesn't match suspend ops")); if (s_cache_suspend_cnt == 0) { spi_flash_restore_cache(esp_cpu_get_core_id(), s_cache_state); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif } } diff --git a/components/esp_rom/patches/esp_rom_spiflash.c b/components/esp_rom/patches/esp_rom_spiflash.c index e60b6f3ae28..c03169df81e 100644 --- a/components/esp_rom/patches/esp_rom_spiflash.c +++ b/components/esp_rom/patches/esp_rom_spiflash.c @@ -13,9 +13,6 @@ #include "soc/spi_mem_reg.h" #endif -#if SOC_BRANCH_PREDICTOR_SUPPORTED -#include "riscv/rv_utils.h" -#endif #include "esp_rom_spiflash.h" #define SPI_IDX 1 @@ -800,10 +797,6 @@ void esp_rom_spiflash_cache_mode_config(esp_rom_spiflash_read_mode_t mode, const extern void rom_spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state); void spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state) { -#if SOC_BRANCH_PREDICTOR_SUPPORTED - //branch predictor will start cache request as well - rv_utils_dis_branch_predictor(); -#endif rom_spi_flash_disable_cache(cpuid, saved_state); } @@ -811,8 +804,5 @@ extern void rom_spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state); void spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state) { rom_spi_flash_restore_cache(cpuid, saved_state); -#if SOC_BRANCH_PREDICTOR_SUPPORTED - rv_utils_en_branch_predictor(); -#endif } #endif diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index 2c5646e352c..d18f81dc474 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -30,6 +30,7 @@ #include "esp_private/esp_ipc.h" #endif #include "esp_attr.h" +#include "esp_cpu.h" #include "esp_memory_utils.h" #include "esp_intr_alloc.h" #include "esp_private/esp_cache_private.h" @@ -91,7 +92,7 @@ void IRAM_ATTR spi_flash_op_block_func(void *arg) /* The branch predictor issues speculative cache requests while this core * spins in IRAM. The flash-op core is about to suspend the (shared) cache, * so speculative fetches into flash would raise a cache access-fail on - * this core. spi_flash_restore_cache() below re-enables prediction. */ + * this core. */ esp_cpu_branch_prediction_disable(); #endif // s_flash_op_complete flag is cleared on *this* CPU, otherwise the other @@ -104,6 +105,9 @@ void IRAM_ATTR spi_flash_op_block_func(void *arg) } // Flash operation is complete, re-enable cache spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif // Restore interrupts that aren't located in IRAM esp_intr_noniram_enable(); #if ( ( CONFIG_FREERTOS_SMP ) && ( !CONFIG_FREERTOS_UNICORE ) ) @@ -176,6 +180,9 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) // Kill interrupts that aren't located in IRAM esp_intr_noniram_disable(); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_disable(); +#endif // This CPU executes this routine, with non-IRAM interrupts and the scheduler // disabled. The other CPU is spinning in the spi_flash_op_block_func task, also // with non-iram interrupts and the scheduler disabled. None of these CPUs will @@ -212,6 +219,9 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void) s_flash_op_complete = true; } +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif // Re-enable non-iram interrupts esp_intr_noniram_enable(); @@ -238,6 +248,12 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void) const uint32_t cpuid = xPortGetCoreID(); const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0; +#if SOC_BRANCH_PREDICTOR_SUPPORTED + /* Disable BP before the first disable_cache(): on shared-cache chips that + * call suspends external memory for all cores, so speculative fetches must + * already be stopped. */ + esp_cpu_branch_prediction_disable(); +#endif // do not care about other CPU, it was halted upon entering panic handler spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]); // Kill interrupts that aren't located in IRAM @@ -252,6 +268,9 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void) // Re-enable cache on this CPU spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif // Re-enable non-iram interrupts esp_intr_noniram_enable(); } @@ -291,12 +310,18 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) { spi_flash_op_lock(); esp_intr_noniram_disable(); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_disable(); +#endif spi_flash_disable_cache(0, &s_flash_op_cache_state[0]); } void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu(void) { spi_flash_restore_cache(0, s_flash_op_cache_state[0]); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif esp_intr_noniram_enable(); spi_flash_op_unlock(); } @@ -305,6 +330,9 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os(void) { // Kill interrupts that aren't located in IRAM esp_intr_noniram_disable(); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_disable(); +#endif // Disable cache on this CPU as well spi_flash_disable_cache(0, &s_flash_op_cache_state[0]); } @@ -313,6 +341,9 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void) { // Re-enable cache on this CPU spi_flash_restore_cache(0, s_flash_op_cache_state[0]); +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif // Re-enable non-iram interrupts esp_intr_noniram_enable(); } @@ -335,19 +366,12 @@ void IRAM_ATTR spi_flash_enable_cache(uint32_t cpuid) #if !CONFIG_SPI_FLASH_ROM_IMPL void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state) { -#if SOC_BRANCH_PREDICTOR_SUPPORTED - //branch predictor will start cache request as well - esp_cpu_branch_prediction_disable(); -#endif esp_cache_suspend_ext_mem_cache(); } void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state) { esp_cache_resume_ext_mem_cache(); -#if SOC_BRANCH_PREDICTOR_SUPPORTED - esp_cpu_branch_prediction_enable(); -#endif } bool IRAM_ATTR spi_flash_cache_enabled(void) diff --git a/components/spi_flash/include/esp_private/cache_utils.h b/components/spi_flash/include/esp_private/cache_utils.h index f90c3768e68..468cc7ce65f 100644 --- a/components/spi_flash/include/esp_private/cache_utils.h +++ b/components/spi_flash/include/esp_private/cache_utils.h @@ -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 */ @@ -97,7 +97,11 @@ bool spi_flash_cache_enabled(void); void spi_flash_enable_cache(uint32_t cpuid); /** - * @brief Suspend the Cache access to external memory, will disable branch predictor if supported. + * @brief Suspend the Cache access to external memory. + * + * @note Callers must disable branch prediction around this window when + * SOC_BRANCH_PREDICTOR_SUPPORTED, otherwise speculative fetches can + * raise cache access-fail errors while the cache is suspended. * * @param cpuid the core number to enable the cache for, meaning less on shared cache. * @param saved_state Cache status hold by hal (Used only on ROM impl. in idf, this param unused) @@ -105,7 +109,10 @@ void spi_flash_enable_cache(uint32_t cpuid); void spi_flash_disable_cache(uint32_t cpuid, uint32_t *saved_state); /** - * @brief Resume the Cache access to external memory, will enable branch predictor if supported. + * @brief Resume the Cache access to external memory. + * + * @note Callers that disabled branch prediction for the suspend window must + * re-enable it after this call when SOC_BRANCH_PREDICTOR_SUPPORTED. * * @param cpuid the core number to enable the cache for, meaning less on shared cache. * @param saved_state Cache status hold by hal (Used only on ROM impl. in idf, this param unused)