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.
This commit is contained in:
Tiago Medicci Serrano 2023-05-19 16:37:52 -03:00 committed by Xiang Xiao
parent 218aa63af3
commit 63364a52ff
2 changed files with 43 additions and 0 deletions

View File

@ -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);
}

View File

@ -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.*)