You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ag...@apache.org on 2020/05/15 22:11:45 UTC

[incubator-nuttx] 02/07: arch/arm/src/stm32h7/stm32_sdmmc: check IDMA buffer address

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

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

commit 07bd520ccb36ac51aaa8347886d576fe68ec8979
Author: Pierre-Olivier Vauboin <po...@lambdaconcept.com>
AuthorDate: Tue Mar 31 17:51:01 2020 +0200

    arch/arm/src/stm32h7/stm32_sdmmc: check IDMA buffer address
    
    For SDMMC1, IDMA cannot access SRAM123 or SRAM4. Refer to ST AN5200 for
    details. This patch makes stm32_dmapreflight check the buffer address and
    return an error when the buffer is located in a invalid address space.
    
    This does not fix the hardware limitation but at least makes it visible.
---
 arch/arm/src/stm32h7/stm32_sdmmc.c | 64 ++++++++++++++++++++++++++++++++------
 1 file changed, 54 insertions(+), 10 deletions(-)

diff --git a/arch/arm/src/stm32h7/stm32_sdmmc.c b/arch/arm/src/stm32h7/stm32_sdmmc.c
index 99a98d9..93af586 100644
--- a/arch/arm/src/stm32h7/stm32_sdmmc.c
+++ b/arch/arm/src/stm32h7/stm32_sdmmc.c
@@ -98,6 +98,12 @@
  * be monitored off the an HP work thread for a residual of less than
  * FIFO_SIZE_IN_BYTES / 2.
  *
+ * HW Issues when using IDMA
+ *
+ *    The DMA buffer must be located in a zone accessible via IDMA.
+ * For SDMMC1, IDMA cannot access SRAM123 or SRAM4. Refer to ST AN5200.
+ * Buffer validity is checked when CONFIG_ARCH_HAVE_SDIO_PREFLIGHT is set.
+ *
  * MDMA is only available on for SDMMC1 and Not supported at this time.
  *
  * Required system configuration options:
@@ -110,13 +116,13 @@
  *     APIs to manage concurrent accesses on the SDMMC bus.  This is not
  *     needed for the simple case of a single SD card, for example.
  *   CONFIG_STM32H7_SDMMC_IDMA - Enable SDMMC IDMA.
- *     DMA support for SDMMC. If disabled disabled, the SDMMC will work in
+ *     DMA support for SDMMC. If disabled, the SDMMC will work in
  *     interrupt mode and still use the IDMA to a local buffer for data
  *     lengths less the 32 bytes due to the FIFO limitations.
  *   CONFIG_SDMMC1/2_WIDTH_D1_ONLY - This may be selected to force the driver
  *     operate with only a single data line (the default is to use all
  *     4 SD data lines).
- *   CONFIG_CONFIG_STM32H7_SDMMC_XFRDEBUG - Enables some very low-level debug
+ *   CONFIG_STM32H7_SDMMC_XFRDEBUG - Enables some very low-level debug
  *     output This also requires CONFIG_DEBUG_FS and CONFIG_DEBUG_INFO
  *   CONFIG_SDMMC1/2_SDIO_MODE
  *     Build ins additional support needed only for SDIO cards (vs. SD memory
@@ -141,6 +147,11 @@
 
 #if !defined(CONFIG_STM32H7_SDMMC_IDMA)
 #  warning "Large Non-DMA transfer may result in RX overrun failures"
+#elif defined(CONFIG_STM32H7_SDMMC1)
+#  define SRAM123_START STM32_SRAM123_BASE
+#  define SRAM123_END   (SRAM123_START + STM32H7_SRAM123_SIZE)
+#  define SRAM4_START   STM32_SRAM4_BASE
+#  define SRAM4_END     (SRAM4_START + STM32H7_SRAM4_SIZE)
 #endif
 
 #ifndef CONFIG_SCHED_WORKQUEUE
@@ -153,7 +164,7 @@
 #endif
 
 #if !defined(CONFIG_DEBUG_FS) || !defined(CONFIG_DEBUG_FEATURES)
-#  undef CONFIG_CONFIG_STM32H7_SDMMC_XFRDEBUG
+#  undef CONFIG_STM32H7_SDMMC_XFRDEBUG
 #endif
 
 #ifdef CONFIG_SDMMC1_SDIO_PULLUP
@@ -1515,6 +1526,21 @@ static void stm32_endtransfer(struct stm32_dev_s *priv,
 
   sdmmc_putreg32(priv, STM32_SDMMC_XFRDONE_ICR, STM32_SDMMC_ICR_OFFSET);
 
+#if defined(CONFIG_STM32H7_SDMMC_IDMA) && \
+    !defined(CONFIG_ARCH_HAVE_SDIO_DELAYED_INVLDT)
+  /* invalidate dcache in case of DMA receive. */
+
+  if (priv->receivecnt)
+    {
+      up_invalidate_dcache((uintptr_t)priv->buffer,
+                           (uintptr_t)priv->buffer + priv->remaining);
+    }
+#endif
+
+  /* DMA debug instrumentation */
+
+  stm32_sample(priv, SAMPLENDX_END_TRANSFER);
+
   /* Mark the transfer finished */
 
   priv->remaining = 0;
@@ -3038,7 +3064,29 @@ static int stm32_registercallback(FAR struct sdio_dev_s *dev,
 static int stm32_dmapreflight(FAR struct sdio_dev_s *dev,
                               FAR const uint8_t *buffer, size_t buflen)
 {
-  /* DMA must be possible to the buffer */
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
+
+  /* IDMA must be possible to the buffer */
+
+#if defined(CONFIG_STM32H7_SDMMC1)
+  if (priv->base == STM32_SDMMC1_BASE)
+    {
+      /* For SDMMC1, IDMA cannot access SRAM123 or SRAM4. */
+
+      if (((uintptr_t)buffer >= SRAM123_START &&
+          (uintptr_t)buffer + buflen <= SRAM123_END) ||
+          ((uintptr_t)buffer >= SRAM4_START &&
+          (uintptr_t)buffer + buflen <= SRAM4_END))
+        {
+          mcerr("invalid IDMA address "
+                  "buffer:0x%08x end:0x%08x\n",
+                  buffer, buffer + buflen - 1);
+          return -EFAULT;
+        }
+    }
+#endif
 
 #  if defined(CONFIG_ARMV7M_DCACHE) && !defined(CONFIG_ARMV7M_DCACHE_WRITETHROUGH)
   /* buffer alignment is required for DMA transfers with dcache in buffered
@@ -3048,15 +3096,11 @@ static int stm32_dmapreflight(FAR struct sdio_dev_s *dev,
    * ARMV7M_DCACHE_LINESIZE boundaries.
    */
 
-  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
-
-  DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
-
   if (buffer != priv->rxfifo &&
       (((uintptr_t)buffer & (ARMV7M_DCACHE_LINESIZE - 1)) != 0 ||
       ((uintptr_t)(buffer + buflen) & (ARMV7M_DCACHE_LINESIZE - 1)) != 0))
     {
-      dmainfo("stm32_dmapreflight: dcache unaligned "
+      mcerr("dcache unaligned "
               "buffer:0x%08x end:0x%08x\n",
               buffer, buffer + buflen - 1);
       return -EFAULT;
@@ -3276,7 +3320,7 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
 static int stm32_dmadelydinvldt(FAR struct sdio_dev_s *dev,
                               FAR const uint8_t *buffer, size_t buflen)
 {
-  /* Invaliate cache to physical memory when not in DTCM memory. */
+  /* Invalidate cache to physical memory when not in DTCM memory. */
 
   if ((uintptr_t)buffer < DTCM_START ||
       (uintptr_t)buffer + buflen > DTCM_END)