xtensa/esp32s3: Tasks use SPIRAM as stack can do SPI flash read/write/erase/map/unmap

Signed-off-by: chenwen@espressif.com <chenwen@espressif.com>
This commit is contained in:
chenwen@espressif.com 2023-11-30 19:24:28 +08:00 committed by Xiang Xiao
parent 996625ec58
commit 62a6a0ab4d
5 changed files with 262 additions and 69 deletions

View file

@ -258,13 +258,6 @@ config XTENSA_INTBACKTRACE
---help---
Add necessary logic to be able to have a full backtrace from an interrupt context.
config XTENSA_USE_SPIRAM_HEAP
bool "Enable SPI RAM heap"
default n
---help---
If enabled, SPIRAM can be selected as the heap, of course, the premise is that
the device needs to support SPIRAM.
config XTENSA_IMEM_USE_SEPARATE_HEAP
bool "Use a separate heap for internal memory"
select ARCH_HAVE_EXTRA_HEAPS

View file

@ -40,18 +40,10 @@
# define UMM_FREE(p) xtensa_imm_free(p)
# define UMM_HEAPMEMEBER(p) xtensa_imm_heapmember(p)
#else
# ifdef CONFIG_XTENSA_USE_SPIRAM_HEAP
# define UMM_MALLOC(s) kmm_malloc(s)
# define UMM_MEMALIGN(a,s) kmm_memalign(a,s)
# define UMM_FREE(p) kmm_free(p)
# define UMM_HEAPMEMEBER(p) mm_heapmember(p)
# else
# define UMM_MALLOC(s) kumm_malloc(s)
# define UMM_MEMALIGN(a,s) kumm_memalign(a,s)
# define UMM_FREE(p) kumm_free(p)
# define UMM_HEAPMEMEBER(p) umm_heapmember(p)
# endif /* CONFIG_XTENSA_USE_SPIRAM_HEAP */
# define UMM_MALLOC(s) kumm_malloc(s)
# define UMM_MEMALIGN(a,s) kumm_memalign(a,s)
# define UMM_FREE(p) kumm_free(p)
# define UMM_HEAPMEMEBER(p) umm_heapmember(p)
#endif /* CONFIG_XTENSA_IMEM_USE_SEPARATE_HEAP */
#endif /* __ARCH_XTENSA_SRC_COMMON_XTENSA_MM_H */

View file

@ -905,12 +905,10 @@ choice ESP32S3_SPIRAM_HEAP
config ESP32S3_SPIRAM_COMMON_HEAP
bool "Additional region to kernel heap"
select XTENSA_USE_SPIRAM_HEAP
config ESP32S3_SPIRAM_USER_HEAP
bool "Separated userspace heap"
select MM_KERNEL_HEAP
select XTENSA_USE_SPIRAM_HEAP
endchoice # ESP32S3_SPIRAM_HEAP
@ -1843,6 +1841,23 @@ config ESP32S3_SPIFLASH_OP_TASK_STACKSIZE
to disable non-IRAM interrupts and wait for the SPI flash operation
to be finished.
config ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
bool "Support PSRAM As Task Stack"
default n
depends on ESP32S3_SPIRAM
select SCHED_LPWORK
---help---
Enable this option, Tasks which use PSRAM as stack
can do SPI Flash read/write/erase/map/unmap. Otherwise,
it may cause exception, the root cause is as following:
1. When operating SPI flash, cache is also disable,
then software can't access PSRAM by data cache.
2. SPI flash read/write/erase functions have instruction like
stack-pop and stack-push which may use stack buffer which is
PSRAM space or load/store temp variables which locate in PSRAM space too.
3. Once operation in step 2 triggers, CPU will trigger exception.
So related SPI flash functions should be sent and run in tasks which use SRAM as task stack.
if ESP32S3_APP_FORMAT_LEGACY
comment "Partition Table configuration"

View file

@ -63,6 +63,19 @@
* Private Types
****************************************************************************/
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
/* SPI flash work operation code */
enum spiflash_op_code_e
{
SPIFLASH_OP_CODE_WRITE = 0,
SPIFLASH_OP_CODE_READ,
SPIFLASH_OP_CODE_ERASE,
SPIFLASH_OP_CODE_ENCRYPT_READ,
SPIFLASH_OP_CODE_ENCRYPT_WRITE
};
#endif
/* ESP32-S3 SPI Flash device private data */
struct esp32s3_mtd_dev_s
@ -74,6 +87,26 @@ struct esp32s3_mtd_dev_s
const struct spiflash_legacy_data_s **data;
};
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
/* SPI flash work operation arguments */
struct spiflash_work_arg
{
enum spiflash_op_code_e op_code;
struct
{
uint32_t addr;
uint8_t *buffer;
uint32_t size;
} op_arg;
volatile int ret;
sem_t sem;
};
#endif
/****************************************************************************
* Private Functions Prototypes
****************************************************************************/
@ -105,6 +138,15 @@ static ssize_t esp32s3_bwrite_encrypt(struct mtd_dev_s *dev,
static int esp32s3_ioctl(struct mtd_dev_s *dev, int cmd,
unsigned long arg);
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
static inline bool IRAM_ATTR stack_is_psram(void);
static void esp32s3_spiflash_work(void *arg);
static int esp32s3_async_op(enum spiflash_op_code_e opcode,
uint32_t addr,
const uint8_t *buffer,
uint32_t size);
#endif
/****************************************************************************
* Private Data
****************************************************************************/
@ -149,10 +191,141 @@ static const struct esp32s3_mtd_dev_s g_esp32s3_spiflash_encrypt =
static mutex_t g_lock = NXMUTEX_INITIALIZER;
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
static struct work_s g_work;
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: stack_is_psram
*
* Description:
* Check if current task's stack space is in PSRAM.
*
* Input Parameters:
* None
*
* Returned Value:
* true if it is in PSRAM or false if not.
*
****************************************************************************/
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
static inline bool IRAM_ATTR stack_is_psram(void)
{
void *sp = (void *)up_getsp();
return esp32s3_ptr_extram(sp);
}
#endif
/****************************************************************************
* Name: esp32s3_spiflash_work
*
* Description:
* Do SPI Flash operation, cache result and send semaphore to wake up
* blocked task.
*
* Input Parameters:
* arg - Reference to SPI flash work arguments structure (cast to void*)
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
static void esp32s3_spiflash_work(void *arg)
{
struct spiflash_work_arg *work_arg = (struct spiflash_work_arg *)arg;
if (work_arg->op_code == SPIFLASH_OP_CODE_WRITE)
{
work_arg->ret = spi_flash_write(work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_READ)
{
work_arg->ret = spi_flash_read(work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_ERASE)
{
work_arg->ret = spi_flash_erase_range(work_arg->op_arg.addr,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_READ)
{
work_arg->ret = spi_flash_read_encrypted(work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else if (work_arg->op_code == SPIFLASH_OP_CODE_ENCRYPT_WRITE)
{
work_arg->ret = spi_flash_write_encrypted(work_arg->op_arg.addr,
work_arg->op_arg.buffer,
work_arg->op_arg.size);
}
else
{
ferr("ERROR: op_code=%d is not supported\n", work_arg->op_code);
}
nxsem_post(&work_arg->sem);
}
/****************************************************************************
* Name: esp32s3_async_op
*
* Description:
* Send operation code and arguments to workqueue so that workqueue do SPI
* Flash operation actually.
*
* Input Parameters:
* opcode - SPI flash work operation code
* addr - target address
* buffer - data buffer pointer
* size - data number
*
* Returned Value:
* 0 if success or a negative value if fail.
*
****************************************************************************/
static int esp32s3_async_op(enum spiflash_op_code_e opcode,
uint32_t addr,
const uint8_t *buffer,
uint32_t size)
{
int ret;
struct spiflash_work_arg work_arg =
{
.op_code = opcode,
.op_arg =
{
.addr = addr,
.buffer = (uint8_t *)buffer,
.size = size,
},
.sem = NXSEM_INITIALIZER(0, 0)
};
ret = work_queue(LPWORK, &g_work, esp32s3_spiflash_work, &work_arg, 0);
if (ret == 0)
{
nxsem_wait(&work_arg.sem);
ret = work_arg.ret;
}
return ret;
}
#endif
/****************************************************************************
* Name: esp32s3_erase
*
@ -194,9 +367,18 @@ static int esp32s3_erase(struct mtd_dev_s *dev, off_t startblock,
return ret;
}
ret = spi_flash_erase_range(offset, nbytes);
nxmutex_unlock(&g_lock);
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32s3_async_op(SPIFLASH_OP_CODE_ERASE, offset, NULL, nbytes);
}
else
#endif
{
ret = spi_flash_erase_range(offset, nbytes);
}
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nblocks;
@ -252,9 +434,19 @@ static ssize_t esp32s3_read(struct mtd_dev_s *dev, off_t offset,
return ret;
}
ret = spi_flash_read(offset, buffer, nbytes);
nxmutex_unlock(&g_lock);
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32s3_async_op(SPIFLASH_OP_CODE_READ, offset,
buffer, nbytes);
}
else
#endif
{
ret = spi_flash_read(offset, buffer, nbytes);
}
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nbytes;
@ -294,20 +486,10 @@ static ssize_t esp32s3_bread(struct mtd_dev_s *dev, off_t startblock,
#ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, nblocks,
buffer);
finfo("spi_flash_read(0x%x, %p, %d)\n", addr, buffer, size);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_read(addr, buffer, size);
nxmutex_unlock(&g_lock);
if (ret == OK)
ret = esp32s3_read(dev, addr, size, buffer);
if (ret == size)
{
ret = nblocks;
}
@ -347,8 +529,7 @@ static ssize_t esp32s3_read_decrypt(struct mtd_dev_s *dev,
#ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, offset, nbytes, buffer);
finfo("spi_flash_read_encrypted(0x%x, %p, %d)\n", offset, buffer,
nbytes);
finfo("spi_flash_read_encrypted(0x%x, %p, %d)\n", offset, buffer, nbytes);
#endif
/* Acquire the mutex. */
@ -359,9 +540,19 @@ static ssize_t esp32s3_read_decrypt(struct mtd_dev_s *dev,
return ret;
}
ret = spi_flash_read_encrypted(offset, buffer, nbytes);
nxmutex_unlock(&g_lock);
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_READ, offset,
buffer, nbytes);
}
else
#endif
{
ret = spi_flash_read_encrypted(offset, buffer, nbytes);
}
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nbytes;
@ -403,20 +594,10 @@ static ssize_t esp32s3_bread_decrypt(struct mtd_dev_s *dev,
#ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock, nblocks,
buffer);
finfo("spi_flash_read_encrypted(0x%x, %p, %d)\n", addr, buffer, size);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_read_encrypted(addr, buffer, size);
nxmutex_unlock(&g_lock);
if (ret == OK)
ret = esp32s3_read_decrypt(dev, addr, size, buffer);
if (ret == size)
{
ret = nblocks;
}
@ -471,9 +652,19 @@ static ssize_t esp32s3_write(struct mtd_dev_s *dev, off_t offset,
return ret;
}
ret = spi_flash_write(offset, buffer, nbytes);
nxmutex_unlock(&g_lock);
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32s3_async_op(SPIFLASH_OP_CODE_WRITE, offset,
buffer, nbytes);
}
else
#endif
{
ret = spi_flash_write(offset, buffer, nbytes);
}
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nbytes;
@ -525,9 +716,19 @@ static ssize_t esp32s3_bwrite_encrypt(struct mtd_dev_s *dev,
return ret;
}
ret = spi_flash_write_encrypted(addr, buffer, size);
nxmutex_unlock(&g_lock);
#ifdef CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK
if (stack_is_psram())
{
ret = esp32s3_async_op(SPIFLASH_OP_CODE_ENCRYPT_WRITE, addr,
buffer, size);
}
else
#endif
{
ret = spi_flash_write_encrypted(addr, buffer, size);
}
nxmutex_unlock(&g_lock);
if (ret == OK)
{
ret = nblocks;
@ -567,20 +768,10 @@ static ssize_t esp32s3_bwrite(struct mtd_dev_s *dev, off_t startblock,
#ifdef CONFIG_ESP32S3_STORAGE_MTD_DEBUG
finfo("%s(%p, 0x%x, %d, %p)\n", __func__, dev, startblock,
nblocks, buffer);
finfo("spi_flash_write(0x%x, %p, %d)\n", addr, buffer, size);
#endif
ret = nxmutex_lock(&g_lock);
if (ret < 0)
{
return ret;
}
ret = spi_flash_write(addr, buffer, size);
nxmutex_unlock(&g_lock);
if (ret == OK)
ret = esp32s3_write(dev, addr, size, buffer);
if (ret == size)
{
ret = nblocks;
}

View file

@ -21,9 +21,11 @@ CONFIG_ARCH_XTENSA=y
CONFIG_BOARD_LOOPSPERMSEC=16717
CONFIG_BUILTIN=y
CONFIG_ESP32S3_FLASH_FREQ_80M=y
CONFIG_ESP32S3_SPIFLASH=y
CONFIG_ESP32S3_SPIRAM=y
CONFIG_ESP32S3_SPIRAM_MODE_OCT=y
CONFIG_ESP32S3_SPIRAM_USER_HEAP=y
CONFIG_ESP32S3_SPI_FLASH_SUPPORT_PSRAM_STACK=y
CONFIG_ESP32S3_UART0=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y