From 7e808c82ea91d0e855611f9f2029512e1f434044 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Fri, 17 Jul 2026 15:37:11 +0800 Subject: [PATCH] fix(spi_flash): disable branch prediction on the parked core during flash ops --- .../port/arch/riscv/esp_ipc_isr_routines.c | 13 +++++++++++++ components/esp_system/port/panic_handler.c | 9 +++++++++ components/spi_flash/cache_utils.c | 9 ++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c b/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c index bbb100eef29..c818fb7ce0c 100644 --- a/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c +++ b/components/esp_system/port/arch/riscv/esp_ipc_isr_routines.c @@ -7,6 +7,7 @@ #include "stdint.h" #include "soc/interrupt_reg.h" #include "soc/soc_caps.h" +#include "esp_cpu.h" #include "esp_ipc_isr.h" #include "esp_private/esp_ipc_isr.h" #include "esp_private/esp_system_attr.h" @@ -46,6 +47,15 @@ void ESP_SYSTEM_IRAM_ATTR esp_ipc_isr_record_interrupted_context(void) void ESP_SYSTEM_IRAM_ATTR esp_ipc_isr_waiting_for_finish_cmd(void* arg) { +#if SOC_BRANCH_PREDICTOR_SUPPORTED + /* The branch predictor keeps issuing speculative instruction fetches while + * this core spins here. Callers of esp_ipc_isr_stall_other_cpu() may + * suspend the external memory cache during the stall (e.g. sleep flows + * powering down flash), in which case a speculative fetch into cached + * address space raises a cache access-fail interrupt. Keep the predictor + * disabled until the stall is released. */ + esp_cpu_branch_prediction_disable(); +#endif esp_ipc_isr_stall_fl = 1; while (esp_ipc_isr_stall_args.cmd == ESP_IPC_ISR_CMD_RESET_STATE) { if (esp_ipc_isr_stall_args.func != NULL) { @@ -53,4 +63,7 @@ void ESP_SYSTEM_IRAM_ATTR esp_ipc_isr_waiting_for_finish_cmd(void* arg) esp_ipc_isr_stall_args.func = NULL; } } +#if SOC_BRANCH_PREDICTOR_SUPPORTED + esp_cpu_branch_prediction_enable(); +#endif } diff --git a/components/esp_system/port/panic_handler.c b/components/esp_system/port/panic_handler.c index e59cf50e63c..ee28045bbf5 100644 --- a/components/esp_system/port/panic_handler.c +++ b/components/esp_system/port/panic_handler.c @@ -122,6 +122,15 @@ static void frame_to_panic_info(void *frame, panic_info_t *info, bool pseudo_exc FORCE_INLINE_ATTR __attribute__((__noreturn__)) void busy_wait(void) { +#if SOC_BRANCH_PREDICTOR_SUPPORTED + /* This core parks here while the offending core handles the panic, which + * may include flash accesses with the cache suspended (e.g. writing a core + * dump). Stop the branch predictor so its speculative fetches cannot latch + * spurious cache access-fail errors that would corrupt the cache error + * status of the panic being reported. This core never resumes, so the + * predictor is not re-enabled. */ + esp_cpu_branch_prediction_disable(); +#endif ESP_INFINITE_LOOP(); } #endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index 227a0efd6ba..2c5646e352c 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -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 */ @@ -87,6 +87,13 @@ void IRAM_ATTR spi_flash_op_block_func(void *arg) // Restore interrupts that aren't located in IRAM esp_intr_noniram_disable(); uint32_t cpuid = (uint32_t) arg; +#if SOC_BRANCH_PREDICTOR_SUPPORTED + /* 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. */ + esp_cpu_branch_prediction_disable(); +#endif // s_flash_op_complete flag is cleared on *this* CPU, otherwise the other // CPU may reset the flag back to false before IPC task has a chance to check it // (if it is preempted by an ISR taking non-trivial amount of time)