esp32/irq: Allow IRAM ISRs to run during SPI flash operation

This commit provides an interface to register ISRs that run from
IRAM and keeps track of the non-IRAM interrupts. It enables, for
instance, to avoid disabling all the interrupts during a SPI flash
operation: IRAM-enabled ISRs are, then, able to run during these
operations.

It also makes the code look more similar to the ESP32-S3 SPI flash
implementation by creating a common `esp32_spiflash_init` that is
responsible to create the SPI flash operation tasks. The function
intended to initialize the SPI flash partions was, then, renamed to
`board_spiflash_init`.
This commit is contained in:
Tiago Medicci Serrano
2023-11-10 09:11:35 +08:00
committed by Xiang Xiao
parent 606190d9b3
commit 57b8fc9954
22 changed files with 832 additions and 45 deletions
+10
View File
@@ -35,6 +35,16 @@
* Pre-processor Definitions
****************************************************************************/
/* CPU interrupt flags:
* These flags can be used to specify which interrupt qualities the
* code calling esp32_setup_irq needs.
*/
#define ESP32_CPUINT_FLAG_LEVEL (1 << 0) /* Level-triggered interrupt */
#define ESP32_CPUINT_FLAG_EDGE (1 << 1) /* Edge-triggered interrupt */
#define ESP32_CPUINT_FLAG_SHARED (1 << 2) /* Interrupt can be shared between ISRs */
#define ESP32_CPUINT_FLAG_IRAM (1 << 3) /* ISR can be called if cache is disabled */
/* Interrupt Matrix
*
* The Interrupt Matrix embedded in the ESP32 independently allocates
+24
View File
@@ -758,6 +758,19 @@ config ESP32_WIFI_BT_COEXIST
default n
depends on ESP32_WIFI && ESP32_BLE
menu "Interrupt Configuration"
config ESP32_IRAM_ISR_DEBUG
bool "Enable debugging of the IRAM-enabled interrupts"
default n
---help---
This option enables keeping track of the IRAM-enabled interrupts by
registering its execution when non-IRAM interrupts are disabled. It
keeps track of the IRQ executed and register how many times since
boot it was executed.
endmenu # Interrupt Configuration
menu "Memory Configuration"
config ESP32_BT_RESERVE_DRAM
@@ -1858,6 +1871,17 @@ config ESP32_PARTITION_MOUNTPT
endif # ESP32_PARTITION_TABLE
config ESP32_SPIFLASH_OP_TASK_STACKSIZE
int "The SPI flash operation task stack size"
default 768
depends on SMP
---help---
When SMP is enabled, it is needed to create two tasks (one for each
core) to be able to run IRAM-enabled interrupts. These tasks ensures
that the core that isn't performing the SPI flash operation is able
to disable non-IRAM interrupts and wait for the SPI flash operation
to be finished.
endif # ESP32_SPIFLASH
endmenu # SPI Flash configuration
+354 -10
View File
@@ -35,6 +35,7 @@
#include <nuttx/board.h>
#include <arch/irq.h>
#include <arch/board/board.h>
#include <irq/irq.h>
#include "xtensa.h"
@@ -154,6 +155,24 @@ static volatile uint8_t g_irqmap[NR_IRQS];
static uint32_t g_intenable[CONFIG_SMP_NCPUS];
/* g_non_iram_int_mask[] is a bitmask of the interrupts that should be
* disabled during a SPI flash operation. Non-IRAM interrupts should always
* be disabled, but interrupts place on IRAM are able to run during a SPI
* flash operation.
*/
static uint32_t g_non_iram_int_mask[CONFIG_SMP_NCPUS];
/* g_non_iram_int_disabled[] keeps track of the interrupts disabled during
* a SPI flash operation.
*/
static uint32_t g_non_iram_int_disabled[CONFIG_SMP_NCPUS];
/* Per-CPU flag to indicate that non-IRAM interrupts were disabled */
static bool g_non_iram_int_disabled_flag[CONFIG_SMP_NCPUS];
/* Bitsets for free, unallocated CPU interrupts available to peripheral
* devices.
*/
@@ -176,6 +195,14 @@ static const uint32_t g_priority[5] =
ESP32_INTPRI5_MASK
};
#ifdef CONFIG_ESP32_IRAM_ISR_DEBUG
/* The g_iram_count keeps track of how many times such an IRQ ran when the
* non-IRAM interrupts were disabled.
*/
static uint64_t g_iram_count[NR_IRQS];
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -368,7 +395,13 @@ static int esp32_alloc_cpuint(int cpu, int priority, int type)
DEBUGASSERT(type == ESP32_CPUINT_LEVEL ||
type == ESP32_CPUINT_EDGE);
if (type == ESP32_CPUINT_LEVEL)
if ((type & (ESP32_CPUINT_LEVEL | ESP32_CPUINT_EDGE)) == 0)
{
irqerr("Either the level or edege-triggered flag must be selected");
return -EINVAL;
}
if ((type & ESP32_CPUINT_LEVEL) != 0)
{
/* Check if there are any level CPU interrupts available at the
* requested interrupt priority.
@@ -428,6 +461,33 @@ static void esp32_free_cpuint(int cpuint)
*freeints |= bitmask;
}
#ifdef CONFIG_ESP32_IRAM_ISR_DEBUG
/****************************************************************************
* Name: esp32_iram_interrupt_record
*
* Description:
* This function keeps track of the IRQs that ran when non-IRAM interrupts
* are disabled and enables debugging of the IRAM-enabled interrupts.
*
* Input Parameters:
* irq - The IRQ associated with a CPU interrupt
*
* Returned Value:
* None.
*
****************************************************************************/
void esp32_irq_iram_interrupt_record(int irq)
{
irqstate_t flags = enter_critical_section();
g_iram_count[irq]++;
leave_critical_section(flags);
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -440,6 +500,15 @@ void up_irqinitialize(void)
{
int i;
/* All CPU ints are non-IRAM interrupts at the beginning and should be
* disabled during a SPI flash operation
*/
for (i = 0; i < CONFIG_SMP_NCPUS; i++)
{
g_non_iram_int_mask[i] = UINT32_MAX;
}
for (i = 0; i < NR_IRQS; i++)
{
g_irqmap[i] = IRQ_UNMAPPED;
@@ -625,6 +694,21 @@ void up_enable_irq(int irq)
int cpu = IRQ_GETCPU(g_irqmap[irq]);
/* Check if the registered ISR for this IRQ is intended to be run from
* IRAM. If so, check if its interrupt handler is located in IRAM.
*/
bool isr_in_iram = !((g_non_iram_int_mask[cpu] & (1 << cpuint)) > 0);
xcpt_t handler = g_irqvector[irq].handler;
if (isr_in_iram && handler && !esp32_ptr_iram(handler))
{
irqerr("Interrupt handler isn't in IRAM (%08" PRIx32 ")",
(intptr_t)handler);
PANIC();
}
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
/* Attach the interrupt to the peripheral; the CPU interrupt was
@@ -780,14 +864,16 @@ int esp32_cpuint_initialize(void)
*
* Description:
* This function sets up the IRQ. It allocates a CPU interrupt of the given
* priority and type and attaches it to the given peripheral.
* priority and associated flags and attaches it to the given peripheral.
*
* Input Parameters:
* cpu - The CPU to receive the interrupt 0=PRO CPU 1=APP CPU
* periphid - The peripheral number from irq.h to be assigned to
* a CPU interrupt.
* priority - Interrupt's priority (1 - 5).
* type - Interrupt's type (level or edge).
* flags - An ORred mask of the ESP32_CPUINT_FLAG_* defines. These
* restrict the choice of interrupts that this routine can
* choose from.
*
* Returned Value:
* The allocated CPU interrupt on success, a negated errno value on
@@ -795,7 +881,7 @@ int esp32_cpuint_initialize(void)
*
****************************************************************************/
int esp32_setup_irq(int cpu, int periphid, int priority, int type)
int esp32_setup_irq(int cpu, int periphid, int priority, int flags)
{
irqstate_t irqstate;
uintptr_t regaddr;
@@ -809,13 +895,14 @@ int esp32_setup_irq(int cpu, int periphid, int priority, int type)
* 1. Allocate a CPU interrupt.
* 2. Attach that CPU interrupt to the peripheral.
* 3. Map the CPU interrupt to the IRQ to ease searching later.
* 4. Check if its ISR is intended to run from IRAM.
*/
cpuint = esp32_alloc_cpuint(cpu, priority, type);
cpuint = esp32_alloc_cpuint(cpu, priority, flags);
if (cpuint < 0)
{
irqerr("Unable to allocate CPU interrupt for priority=%d and type=%d",
priority, type);
irqerr("Unable to allocate CPU interrupt for priority=%d and flags=%d",
priority, flags);
leave_critical_section(irqstate);
return cpuint;
@@ -842,6 +929,15 @@ int esp32_setup_irq(int cpu, int periphid, int priority, int type)
intmap[cpuint] = CPUINT_ASSIGN(periphid + XTENSA_IRQ_FIRSTPERIPH);
g_irqmap[irq] = IRQ_MKMAP(cpu, cpuint);
if ((flags & ESP32_CPUINT_FLAG_IRAM) != 0)
{
esp32_irq_set_iram_isr(irq);
}
else
{
esp32_irq_unset_iram_isr(irq);
}
putreg32(cpuint, regaddr);
leave_critical_section(irqstate);
@@ -901,6 +997,65 @@ void esp32_teardown_irq(int cpu, int periphid, int cpuint)
leave_critical_section(irqstate);
}
/****************************************************************************
* Name: esp32_getirq
*
* Description:
* This function returns the IRQ associated with a CPU interrupt
*
* Input Parameters:
* cpu - The CPU core of the IRQ being queried
* cpuint - The CPU interrupt associated to the IRQ
*
* Returned Value:
* The IRQ associated with such CPU interrupt or CPUINT_UNASSIGNED if
* IRQ is not yet assigned to a CPU interrupt.
*
****************************************************************************/
int esp32_getirq(int cpu, int cpuint)
{
uint8_t *intmap;
#ifdef CONFIG_SMP
/* Select PRO or APP CPU interrupt mapping table */
if (cpu != 0)
{
intmap = g_cpu1_intmap;
}
else
#endif
{
intmap = g_cpu0_intmap;
}
return CPUINT_GETIRQ(intmap[cpuint]);
}
/****************************************************************************
* Name: esp32_getcpuint_from_irq
*
* Description:
* This function returns the CPU interrupt associated with an IRQ
*
* Input Parameters:
* irq - The IRQ associated with a CPU interrupt
* cpu - Pointer to store the CPU core of the CPU interrupt
*
* Returned Value:
* The CPU interrupt associated with such IRQ or IRQ_UNMAPPED if
* CPU interrupt is not mapped to an IRQ.
*
****************************************************************************/
int esp32_getcpuint_from_irq(int irq, int *cpu)
{
(*cpu) = (int)IRQ_GETCPU(g_irqmap[irq]);
return IRQ_GETCPUINT(g_irqmap[irq]);
}
/****************************************************************************
* Name: xtensa_int_decode
*
@@ -924,18 +1079,17 @@ uint32_t *xtensa_int_decode(uint32_t cpuints, uint32_t *regs)
uint8_t *intmap;
uint32_t mask;
int bit;
#ifdef CONFIG_SMP
int cpu;
#endif
#ifdef CONFIG_ARCH_LEDS_CPU_ACTIVITY
board_autoled_on(LED_CPU);
#endif
#ifdef CONFIG_SMP
/* Select PRO or APP CPU interrupt mapping table */
cpu = up_cpu_index();
#ifdef CONFIG_SMP
if (cpu != 0)
{
intmap = g_cpu1_intmap;
@@ -966,6 +1120,17 @@ uint32_t *xtensa_int_decode(uint32_t cpuints, uint32_t *regs)
DEBUGASSERT(CPUINT_GETEN(intmap[bit]));
DEBUGASSERT(irq != CPUINT_UNASSIGNED);
#ifdef CONFIG_ESP32_IRAM_ISR_DEBUG
/* Check if non-IRAM interrupts are disabled */
if (esp32_irq_noniram_status(cpu) == 0)
{
/* Sum-up the IRAM-enabled counter associated with the IRQ */
esp32_irq_iram_interrupt_record(irq);
}
#endif
/* Clear software or edge-triggered interrupt */
xtensa_intclear(mask);
@@ -986,6 +1151,185 @@ uint32_t *xtensa_int_decode(uint32_t cpuints, uint32_t *regs)
}
}
UNUSED(cpu);
return regs;
}
/****************************************************************************
* Name: esp32_irq_noniram_disable
*
* Description:
* Disable interrupts that aren't specifically marked as running from IRAM
*
* Input Parameters:
* None
*
* Input Parameters:
* None
*
****************************************************************************/
void esp32_irq_noniram_disable(void)
{
irqstate_t irqstate;
int cpu;
uint32_t oldint;
uint32_t non_iram_ints;
irqstate = enter_critical_section();
cpu = up_cpu_index();
non_iram_ints = g_non_iram_int_mask[cpu];
ASSERT(!g_non_iram_int_disabled_flag[cpu]);
g_non_iram_int_disabled_flag[cpu] = true;
oldint = g_intenable[cpu];
xtensa_disable_cpuint(&g_intenable[cpu], non_iram_ints);
g_non_iram_int_disabled[cpu] = oldint & non_iram_ints;
leave_critical_section(irqstate);
}
/****************************************************************************
* Name: esp32_irq_noniram_enable
*
* Description:
* Re-enable interrupts disabled by esp32_irq_noniram_disable
*
* Input Parameters:
* None
*
* Input Parameters:
* None
*
****************************************************************************/
void esp32_irq_noniram_enable(void)
{
irqstate_t irqstate;
int cpu;
uint32_t non_iram_ints;
irqstate = enter_critical_section();
cpu = up_cpu_index();
non_iram_ints = g_non_iram_int_disabled[cpu];
ASSERT(g_non_iram_int_disabled_flag[cpu]);
g_non_iram_int_disabled_flag[cpu] = false;
xtensa_enable_cpuint(&g_intenable[cpu], non_iram_ints);
leave_critical_section(irqstate);
}
/****************************************************************************
* Name: esp32_irq_noniram_status
*
* Description:
* Get the current status of non-IRAM interrupts on a specific CPU core
*
* Input Parameters:
* cpu - The CPU to check the non-IRAM interrupts state
*
* Returned Value:
* true if non-IRAM interrupts are enabled, false otherwise.
*
****************************************************************************/
bool esp32_irq_noniram_status(int cpu)
{
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS);
return !g_non_iram_int_disabled_flag[cpu];
}
/****************************************************************************
* Name: esp32_irq_set_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a IRAM-enabled ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp32_irq_set_iram_isr(int irq)
{
int cpu;
int cpuint = esp32_getcpuint_from_irq(irq, &cpu);
if (cpuint == IRQ_UNMAPPED)
{
return -EINVAL;
}
g_non_iram_int_mask[cpu] &= ~(1 << cpuint);
return OK;
}
/****************************************************************************
* Name: esp32_irq_unset_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a non-IRAM ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp32_irq_unset_iram_isr(int irq)
{
int cpu;
int cpuint = esp32_getcpuint_from_irq(irq, &cpu);
if (cpuint == IRQ_UNMAPPED)
{
return -EINVAL;
}
g_non_iram_int_mask[cpu] |= (1 << cpuint);
return OK;
}
#ifdef CONFIG_ESP32_IRAM_ISR_DEBUG
/****************************************************************************
* Name: esp32_get_iram_interrupt_records
*
* Description:
* This function copies the vector that keeps track of the IRQs that ran
* when non-IRAM interrupts were disabled.
*
* Input Parameters:
*
* irq_count - A previously allocated pointer to store the counter of the
* interrupts that ran when non-IRAM interrupts were disabled.
*
* Returned Value:
* None
*
****************************************************************************/
void esp32_get_iram_interrupt_records(uint64_t *irq_count)
{
irqstate_t flags = enter_critical_section();
memcpy(irq_count, &g_iram_count, sizeof(uint64_t) * NR_IRQS);
leave_critical_section(flags);
}
#endif
+145 -5
View File
@@ -46,8 +46,8 @@ extern "C"
/* CPU interrupt types. */
#define ESP32_CPUINT_LEVEL 0
#define ESP32_CPUINT_EDGE 1
#define ESP32_CPUINT_LEVEL ESP32_CPUINT_FLAG_LEVEL
#define ESP32_CPUINT_EDGE ESP32_CPUINT_FLAG_EDGE
/****************************************************************************
* Public Functions Prototypes
@@ -75,14 +75,16 @@ int esp32_cpuint_initialize(void);
*
* Description:
* This function sets up the IRQ. It allocates a CPU interrupt of the given
* priority and type and attaches it to the given peripheral.
* priority and associated flags and attaches it to the given peripheral.
*
* Input Parameters:
* cpu - The CPU to receive the interrupt 0=PRO CPU 1=APP CPU
* periphid - The peripheral number from irq.h to be assigned to
* a CPU interrupt.
* priority - Interrupt's priority (1 - 5).
* type - Interrupt's type (level or edge).
* flags - An ORred mask of the ESP32_CPUINT_FLAG_* defines. These
* restrict the choice of interrupts that this routine can
* choose from.
*
* Returned Value:
* The allocated CPU interrupt on success, a negated errno value on
@@ -90,7 +92,7 @@ int esp32_cpuint_initialize(void);
*
****************************************************************************/
int esp32_setup_irq(int cpu, int periphid, int priority, int type);
int esp32_setup_irq(int cpu, int periphid, int priority, int flags);
/****************************************************************************
* Name: esp32_teardown_irq
@@ -114,6 +116,144 @@ int esp32_setup_irq(int cpu, int periphid, int priority, int type);
void esp32_teardown_irq(int cpu, int periphid, int cpuint);
/****************************************************************************
* Name: esp32_getirq
*
* Description:
* This function returns the IRQ associated with a CPU interrupt
*
* Input Parameters:
* cpu - The CPU core of the IRQ being queried
* cpuint - The CPU interrupt associated to the IRQ
*
* Returned Value:
* The IRQ associated with such CPU interrupt or CPUINT_UNASSIGNED if
* IRQ is not yet assigned to a CPU interrupt.
*
****************************************************************************/
int esp32_getirq(int cpu, int cpuint);
/****************************************************************************
* Name: esp32_getcpuint_from_irq
*
* Description:
* This function returns the CPU interrupt associated with an IRQ
*
* Input Parameters:
* irq - The IRQ associated with a CPU interrupt
* cpu - Pointer to store the CPU core of the CPU interrupt
*
* Returned Value:
* The CPU interrupt associated with such IRQ or IRQ_UNMAPPED if
* CPU interrupt is not mapped to an IRQ.
*
****************************************************************************/
int esp32_getcpuint_from_irq(int irq, int *cpu);
/****************************************************************************
* Name: esp32_irq_noniram_disable
*
* Description:
* Disable interrupts that aren't specifically marked as running from IRAM
*
* Input Parameters:
* None
*
* Input Parameters:
* None
*
****************************************************************************/
void esp32_irq_noniram_disable(void);
/****************************************************************************
* Name: esp32_irq_noniram_enable
*
* Description:
* Re-enable interrupts disabled by esp32_irq_noniram_disable
*
* Input Parameters:
* None
*
* Input Parameters:
* None
*
****************************************************************************/
void esp32_irq_noniram_enable(void);
/****************************************************************************
* Name: esp32_irq_noniram_status
*
* Description:
* Get the current status of non-IRAM interrupts on a specific CPU core
*
* Input Parameters:
* cpu - The CPU to check the non-IRAM interrupts state
*
* Returned Value:
* true if non-IRAM interrupts are enabled, false otherwise.
*
****************************************************************************/
bool esp32_irq_noniram_status(int cpu);
/****************************************************************************
* Name: esp32_irq_set_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a IRAM-enabled ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp32_irq_set_iram_isr(int irq);
/****************************************************************************
* Name: esp32_irq_unset_iram_isr
*
* Description:
* Set the ISR associated to an IRQ as a non-IRAM ISR.
*
* Input Parameters:
* irq - The associated IRQ to set
*
* Returned Value:
* OK on success; A negated errno value on failure.
*
****************************************************************************/
int esp32_irq_unset_iram_isr(int irq);
#ifdef CONFIG_ESP32_IRAM_ISR_DEBUG
/****************************************************************************
* Name: esp32_get_iram_interrupt_records
*
* Description:
* This function copies the vector that keeps track of the IRQs that ran
* when non-IRAM interrupts were disabled.
*
* Input Parameters:
*
* irq_count - A previously allocated pointer to store the counter of the
* interrupts that ran when non-IRAM interrupts were disabled.
*
* Returned Value:
* None
*
****************************************************************************/
void esp32_get_iram_interrupt_records(uint64_t *irq_count);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
+226 -8
View File
@@ -37,9 +37,12 @@
#include <nuttx/arch.h>
#include <nuttx/init.h>
#include <nuttx/kthread.h>
#include <nuttx/mutex.h>
#include <nuttx/mtd/mtd.h>
#include "sched/sched.h"
#include "xtensa.h"
#include "xtensa_attr.h"
@@ -50,11 +53,12 @@
#include "hardware/esp32_dport.h"
#include "hardware/efuse_reg.h"
#include "esp32_spicache.h"
#ifdef CONFIG_ESP32_SPIRAM
#include "esp32_spiram.h"
#endif
#include "esp32_irq.h"
#include "esp32_spicache.h"
#include "esp32_spiflash.h"
/****************************************************************************
@@ -181,6 +185,7 @@ struct spiflash_cachestate_s
#endif
irqstate_t flags;
uint32_t val[CONFIG_SMP_NCPUS];
bool sched_suspended[CONFIG_SMP_NCPUS];
};
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
@@ -230,7 +235,7 @@ static inline void spi_reset_regbits(struct esp32_spiflash_s *priv,
static inline void IRAM_ATTR
esp32_spiflash_opstart(struct spiflash_cachestate_s *state);
static inline void IRAM_ATTR
esp32_spiflash_opdone(const struct spiflash_cachestate_s *state);
esp32_spiflash_opdone(struct spiflash_cachestate_s *state);
static bool IRAM_ATTR spiflash_pagecached(uint32_t phypage);
static void IRAM_ATTR spiflash_flushmapped(size_t start, size_t size);
@@ -346,13 +351,19 @@ static struct esp32_spiflash_s g_esp32_spiflash1_encrypt =
.dummies = g_rom_spiflash_dummy_len_plus
};
/* Enxusre exculisve access to the driver */
/* Ensure exclusive access to the driver */
static mutex_t g_lock = NXMUTEX_INITIALIZER;
#ifdef CONFIG_ESP32_SPI_FLASH_SUPPORT_PSRAM_STACK
static struct work_s g_work;
#endif
static volatile bool g_flash_op_can_start = false;
static volatile bool g_flash_op_complete = false;
#ifdef CONFIG_SMP
static sem_t g_disable_non_iram_isr_on_core[CONFIG_SMP_NCPUS];
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -459,7 +470,12 @@ static inline void spi_reset_regbits(struct esp32_spiflash_s *priv,
static inline void IRAM_ATTR
esp32_spiflash_opstart(struct spiflash_cachestate_s *state)
{
state->flags = enter_critical_section();
struct tcb_s *tcb = this_task();
int saved_priority = tcb->sched_priority;
/* Temporary raise schedule priority */
nxsched_set_priority(tcb, SCHED_PRIORITY_MAX);
state->cpu = up_cpu_index();
#ifdef CONFIG_SMP
@@ -467,12 +483,33 @@ esp32_spiflash_opstart(struct spiflash_cachestate_s *state)
#endif
DEBUGASSERT(state->cpu == 0 || state->cpu == 1);
#ifdef CONFIG_SMP
DEBUGASSERT(state->other == 0 || state->other == 1);
DEBUGASSERT(state->other != state->cpu);
up_cpu_pause(state->other);
if (OSINIT_OS_READY())
{
g_flash_op_can_start = false;
nxsem_post(&g_disable_non_iram_isr_on_core[state->other]);
while (!g_flash_op_can_start)
{
/* Busy loop and wait for spi_flash_op_block_task to disable cache
* on the other CPU
*/
}
}
#endif
state->sched_suspended[state->cpu] = true;
sched_lock();
nxsched_set_priority(tcb, saved_priority);
esp32_irq_noniram_disable();
spi_disable_cache(state->cpu, &state->val[state->cpu]);
#ifdef CONFIG_SMP
spi_disable_cache(state->other, &state->val[state->other]);
@@ -488,7 +525,7 @@ esp32_spiflash_opstart(struct spiflash_cachestate_s *state)
****************************************************************************/
static inline void IRAM_ATTR
esp32_spiflash_opdone(const struct spiflash_cachestate_s *state)
esp32_spiflash_opdone(struct spiflash_cachestate_s *state)
{
DEBUGASSERT(state->cpu == 0 || state->cpu == 1);
#ifdef CONFIG_SMP
@@ -499,10 +536,26 @@ static inline void IRAM_ATTR
spi_enable_cache(state->cpu, state->val[state->cpu]);
#ifdef CONFIG_SMP
spi_enable_cache(state->other, state->val[state->other]);
up_cpu_resume(state->other);
#endif
leave_critical_section(state->flags);
/* Signal to spi_flash_op_block_task that flash operation is complete */
g_flash_op_complete = true;
esp32_irq_noniram_enable();
sched_unlock();
state->sched_suspended[state->cpu] = false;
#ifdef CONFIG_SMP
while (state->sched_suspended[state->other])
{
/* Busy loop and wait for spi_flash_op_block_task to properly finish
* and resume scheduler
*/
}
#endif
}
/****************************************************************************
@@ -2300,10 +2353,175 @@ static int esp32_ioctl_encrypt(struct mtd_dev_s *dev, int cmd,
return ret;
}
#ifdef CONFIG_SMP
/****************************************************************************
* Name: spi_flash_op_block_task
*
* Description:
* Disable the non-IRAM interrupts on the other core (the one that isn't
* handling the SPI flash operation) and notify that the SPI flash
* operation can start. Wait on a busy loop until it's finished and then
* reenable the non-IRAM interrups.
*
* Input Parameters:
* argc - Not used.
* argv - Not used.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned to
* indicate the nature of any failure.
*
****************************************************************************/
static int spi_flash_op_block_task(int argc, char *argv[])
{
struct tcb_s *tcb = this_task();
int cpu = up_cpu_index();
for (; ; )
{
DEBUGASSERT((1 << cpu) & tcb->affinity);
/* Wait for a SPI flash operation to take place and this (the other
* core) being asked to disable its non-IRAM interrupts.
*/
nxsem_wait(&g_disable_non_iram_isr_on_core[cpu]);
sched_lock();
esp32_irq_noniram_disable();
/* g_flash_op_complete flag is cleared on *this* CPU, otherwise the
* other CPU may reset the flag back to false before this task has a
* chance to check it (if it's preempted by an ISR taking non-trivial
* amount of time).
*/
g_flash_op_complete = false;
g_flash_op_can_start = true;
while (!g_flash_op_complete)
{
/* Busy loop here and wait for the other CPU to finish the SPI
* flash operation.
*/
}
/* Flash operation is complete, re-enable cache */
#if 0
spi_enable_cache(cpu);
#endif
/* Restore interrupts that aren't located in IRAM */
esp32_irq_noniram_enable();
sched_unlock();
}
return OK;
}
/****************************************************************************
* Name: spiflash_init_spi_flash_op_block_task
*
* Description:
* Starts a kernel thread that waits for a semaphore indicating that a SPI
* flash operation is going to take place in the other CPU. It disables
* non-IRAM interrupts, indicates to the other core that the SPI flash
* operation can start and waits for it to be finished in a busy loop.
*
* Input Parameters:
* cpu - The CPU core that will run the created task to wait on a busy
* loop while the SPI flash operation finishes
*
* Returned Value:
* 0 (OK) on success; A negated errno value on failure.
*
****************************************************************************/
int spiflash_init_spi_flash_op_block_task(int cpu)
{
int pid;
int ret = OK;
char *argv[2];
char arg1[32];
cpu_set_t cpuset;
snprintf(arg1, sizeof(arg1), "%p", &cpu);
argv[0] = arg1;
argv[1] = NULL;
pid = kthread_create("spiflash_op",
SCHED_PRIORITY_MAX,
CONFIG_ESP32_SPIFLASH_OP_TASK_STACKSIZE,
spi_flash_op_block_task,
argv);
if (pid > 0)
{
if (cpu < CONFIG_SMP_NCPUS)
{
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
ret = nxsched_set_affinity(pid, sizeof(cpuset), &cpuset);
if (ret < 0)
{
return ret;
}
}
}
else
{
return -EPERM;
}
return ret;
}
#endif /* CONFIG_SMP */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: esp32_spiflash_init
*
* Description:
* Initialize ESP32 SPI flash driver.
*
* Returned Value:
* OK if success or a negative value if fail.
*
****************************************************************************/
int esp32_spiflash_init(void)
{
int cpu;
int ret = OK;
#ifdef CONFIG_SMP
sched_lock();
for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
{
nxsem_init(&g_disable_non_iram_isr_on_core[cpu], 0, 0);
ret = spiflash_init_spi_flash_op_block_task(cpu);
if (ret != OK)
{
return ret;
}
}
sched_unlock();
#else
UNUSED(cpu);
#endif
return ret;
}
/****************************************************************************
* Name: esp32_spiflash_alloc_mtdpart
*
+13
View File
@@ -48,6 +48,19 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: esp32_spiflash_init
*
* Description:
* Initialize ESP32 SPI flash driver.
*
* Returned Value:
* OK if success or a negative value if fail.
*
****************************************************************************/
int esp32_spiflash_init(void);
/****************************************************************************
* Name: esp32_spiflash_alloc_mtdpart
*
@@ -840,6 +840,25 @@ static inline bool IRAM_ATTR esp32_ptr_extram(const void *p)
(intptr_t)p < SOC_EXTRAM_DATA_HIGH);
}
/****************************************************************************
* Name: esp32_ptr_iram
*
* Description:
* Check if the pointer is in IRAM
*
* Parameters:
* p - Pointer to the address being checked.
*
* Return Value:
* True if the address is a member of the internal memory. False if not.
*
****************************************************************************/
static inline bool IRAM_ATTR esp32_ptr_iram(const void *p)
{
return ((intptr_t)p >= SOC_IRAM_LOW && (intptr_t)p < SOC_IRAM_HIGH);
}
/****************************************************************************
* Name: esp32_ptr_exec
*
@@ -43,7 +43,7 @@ extern "C"
****************************************************************************/
/****************************************************************************
* Name: esp32_spiflash_init
* Name: board_spiflash_init
*
* Description:
* Initialize the SPI Flash and register the MTD.
@@ -57,7 +57,7 @@ extern "C"
*
****************************************************************************/
int esp32_spiflash_init(void);
int board_spiflash_init(void);
#undef EXTERN
#if defined(__cplusplus)
@@ -76,18 +76,26 @@ SECTIONS
#ifdef CONFIG_STACK_CANARIES
*libc.a:lib_stackchk.*(.literal .text .literal.* .text.*)
#endif
*libarch.a:esp32_cpuindex.*(.literal .text .literal.* .text.*)
*libarch.a:esp32_irq.*(.literal .text .literal.* .text.*)
*libarch.a:esp32_spiflash.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_assert.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_cpuint.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_cpupause.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_copystate.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_interruptcontext.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_irqdispatch.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_modifyreg32.*(.literal .text .literal.* .text.*)
*libarch.a:xtensa_testset.*(.literal .text .literal.* .text.*)
*libsched.a:sched_suspendscheduler.*(.literal .text .literal.* .text.*)
*libsched.a:sched_note.*(.literal .text .literal.* .text.*)
*libsched.a:sched_thistask.*(.literal .text .literal.* .text.*)
*libsched.a:spinlock.*(.literal .text .literal.* .text.*)
*libdrivers.a:syslog_flush.*(.literal .text .literal.* .text.*)
*libsched.a:assert.*(.literal .text .literal.* .text.*)
*libsched.a:irq_csection.*(.literal .text .literal.* .text.*)
*libsched.a:irq_dispatch.*(.literal .text .literal.* .text.*)
*libsched.a:irq_spinlock.*(.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.*)
@@ -427,7 +427,7 @@ static int init_storage_partition(void)
****************************************************************************/
/****************************************************************************
* Name: esp32_spiflash_init
* Name: board_spiflash_init
*
* Description:
* Initialize the SPI Flash and register the MTD.
@@ -441,10 +441,16 @@ static int init_storage_partition(void)
*
****************************************************************************/
int esp32_spiflash_init(void)
int board_spiflash_init(void)
{
int ret = OK;
ret = esp32_spiflash_init();
if (ret < 0)
{
return ret;
}
#ifdef CONFIG_ESP32_HAVE_OTA_PARTITION
ret = init_ota_partitions();
if (ret < 0)
@@ -184,7 +184,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -6,7 +6,6 @@
# modifications.
#
# CONFIG_ARCH_LEDS is not set
# CONFIG_NDEBUG is not set
# CONFIG_NSH_ARGCAT is not set
# CONFIG_NSH_CMDOPT_HEXDUMP is not set
CONFIG_ALLOW_BSD_COMPONENTS=y
@@ -20,13 +19,18 @@ CONFIG_ARCH_CHIP_ESP32WROVER=y
CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_STACKDUMP=y
CONFIG_ARCH_XTENSA=y
CONFIG_BCH=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BTSAK=y
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DRIVERS_BLUETOOTH=y
CONFIG_DRIVERS_IEEE80211=y
CONFIG_DRIVERS_WIRELESS=y
CONFIG_ESP32_BLE=y
CONFIG_ESP32_IRAM_ISR_DEBUG=y
CONFIG_ESP32_SPIFLASH=y
CONFIG_ESP32_UART0=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
@@ -35,6 +39,7 @@ CONFIG_IDLETHREAD_STACKSIZE=3072
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_MM_REGIONS=3
CONFIG_MTD_PARTITION_NAMES=y
CONFIG_NETDEV_LATEINIT=y
CONFIG_NET_BLUETOOTH=y
CONFIG_NET_SOCKOPTS=y
@@ -255,7 +255,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -144,7 +144,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -184,7 +184,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -185,7 +185,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -190,7 +190,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -178,7 +178,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -174,7 +174,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -231,7 +231,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -174,7 +174,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");
@@ -234,7 +234,7 @@ int esp32_bringup(void)
#endif
#ifdef CONFIG_ESP32_SPIFLASH
ret = esp32_spiflash_init();
ret = board_spiflash_init();
if (ret)
{
syslog(LOG_ERR, "ERROR: Failed to initialize SPI Flash\n");