From 63364a52ffc094cad645f3f6948b37b4a0d6c8b4 Mon Sep 17 00:00:00 2001 From: Tiago Medicci Serrano Date: Fri, 19 May 2023 16:37:52 -0300 Subject: [PATCH] esp32s3/spiflash: pause other CPU before SPI flash operations Whenever a SPI flash operation is going to take place, it's necessary to disable both the instruction and data cache. In order to avoid the other CPU (if SMP is enabled) to retrieve data from the SPI flash, it needs to be paused until the current SPI flash operation finishes. All the code that "pauses" the other CPU (in fact, the CPU spins until `up_cpu_resume` is called) needs to run from the instruction RAM. --- arch/xtensa/src/esp32s3/esp32s3_spiflash.c | 32 +++++++++++++++++++ .../esp32s3/common/scripts/legacy_sections.ld | 11 +++++++ 2 files changed, 43 insertions(+) diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c index 01b66cc3f9..99c47e2a61 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_spiflash.c +++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash.c @@ -122,6 +122,10 @@ struct spiflash_cachestate_s { uint32_t value; irqstate_t flags; + int cpu; +#ifdef CONFIG_SMP + int other; +#endif }; /**************************************************************************** @@ -137,7 +141,9 @@ static void spiflash_end(void); extern void spi_flash_guard_set(const struct spiflash_guard_funcs_s *funcs); extern uint32_t cache_suspend_icache(void); +extern uint32_t cache_suspend_dcache(void); extern void cache_resume_icache(uint32_t val); +extern void cache_resume_dcache(uint32_t val); extern int cache_invalidate_addr(uint32_t addr, uint32_t size); /**************************************************************************** @@ -167,7 +173,20 @@ static struct spiflash_cachestate_s g_state; static IRAM_ATTR void spiflash_start(void) { g_state.flags = enter_critical_section(); + g_state.cpu = up_cpu_index(); +#ifdef CONFIG_SMP + g_state.other = g_state.cpu ? 0 : 1; +#endif + + DEBUGASSERT(g_state.cpu == 0 || g_state.cpu == 1); +#ifdef CONFIG_SMP + DEBUGASSERT(g_state.other == 0 || g_state.other == 1); + DEBUGASSERT(g_state.other != g_state.cpu); + up_cpu_pause(g_state.other); +#endif + g_state.value = cache_suspend_icache() << 16; + g_state.value |= cache_suspend_dcache(); } /**************************************************************************** @@ -180,7 +199,20 @@ static IRAM_ATTR void spiflash_start(void) static IRAM_ATTR void spiflash_end(void) { + DEBUGASSERT(g_state.cpu == 0 || g_state.cpu == 1); + +#ifdef CONFIG_SMP + DEBUGASSERT(g_state.other == 0 || g_state.other == 1); + DEBUGASSERT(g_state.other != g_state.cpu); +#endif + cache_resume_icache(g_state.value >> 16); + cache_resume_dcache(g_state.value & 0xffff); + +#ifdef CONFIG_SMP + up_cpu_resume(g_state.other); +#endif + leave_critical_section(g_state.flags); } diff --git a/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld b/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld index 97869c1080..8f4be6ebf8 100644 --- a/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld +++ b/boards/xtensa/esp32s3/common/scripts/legacy_sections.ld @@ -76,6 +76,17 @@ SECTIONS *(.iram1 .iram1.*) + *libarch.a:esp32s3_spiflash.*(.literal .text .literal.* .text.*) + *libarch.a:xtensa_cpupause.*(.literal .text .literal.* .text.*) + *libarch.a:xtensa_testset.*(.literal .text .literal.* .text.*) + + *libsched.a:irq_csection.*(.literal .text .literal.* .text.*) + *libsched.a:irq_dispatch.*(.literal .text .literal.* .text.*) + *libsched.a:sched_note.*(.literal .text .literal.* .text.*) + *libsched.a:sched_suspendscheduler.*(.literal .text .literal.* .text.*) + *libsched.a:sched_thistask.*(.literal .text .literal.* .text.*) + *libsched.a:spinlock.*(.literal .text .literal.* .text.*) + *(.wifirxiram .wifirxiram.*) *(.wifi0iram .wifi0iram.*) *(.wifiorslpiram .wifiorslpiram.*)