This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 62a6a0ab4d xtensa/esp32s3: Tasks use SPIRAM as stack can do SPI flash 
read/write/erase/map/unmap
62a6a0ab4d is described below

commit 62a6a0ab4de4825df356341e35cac41698e52eac
Author: chen...@espressif.com <chen...@espressif.com>
AuthorDate: Thu Nov 30 19:24:28 2023 +0800

    xtensa/esp32s3: Tasks use SPIRAM as stack can do SPI flash 
read/write/erase/map/unmap
    
    Signed-off-by: chen...@espressif.com <chen...@espressif.com>
---
 arch/xtensa/Kconfig                                |   7 -
 arch/xtensa/src/common/xtensa_mm.h                 |  16 +-
 arch/xtensa/src/esp32s3/Kconfig                    |  19 +-
 arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c     | 287 +++++++++++++++++----
 .../esp32s3-devkit/configs/psram_usrheap/defconfig |   2 +
 5 files changed, 262 insertions(+), 69 deletions(-)

diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 7efcb1b360..0c7f1f60ab 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -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
diff --git a/arch/xtensa/src/common/xtensa_mm.h 
b/arch/xtensa/src/common/xtensa_mm.h
index 75f4ca7919..9c1d6ddebb 100644
--- a/arch/xtensa/src/common/xtensa_mm.h
+++ b/arch/xtensa/src/common/xtensa_mm.h
@@ -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 */
diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index a7ecb1f5ff..11a5c3bee3 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -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"
diff --git a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c 
b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c
index fad0d5a959..2ac6d66424 100644
--- a/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c
+++ b/arch/xtensa/src/esp32s3/esp32s3_spiflash_mtd.c
@@ -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;
     }
diff --git 
a/boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig 
b/boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig
index 47a5f71ce6..6124a2b8ad 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/psram_usrheap/defconfig
@@ -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

Reply via email to