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

xiaoxiang781216 pushed a commit to branch releases/13.0
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/releases/13.0 by this push:
     new 573c32f251e arch/arm/stm32h7: invalidate dcache after aligned SDMMC RX 
DMA
573c32f251e is described below

commit 573c32f251e87553b47cc394f6fc011dfa155f6c
Author: Yang-Rui Li <[email protected]>
AuthorDate: Thu Jul 23 12:00:57 2026 +0800

    arch/arm/stm32h7: invalidate dcache after aligned SDMMC RX DMA
    
    The aligned direct-DMA receive path only invalidated the destination
    buffer before the transfer in stm32_dmarecvsetup(). On the Cortex-M7
    the cache can speculatively prefetch into that cacheable buffer
    between the pre-DMA invalidate and DMA completion, leaving stale
    lines that shadow the data just written by the IDMA, so the CPU
    reads a previously cached sector instead of the freshly received
    data.
    
    Invalidate again in stm32_recvdma() once the aligned transfer
    completes, before the buffer is consumed. The buffer and length are
    cache-line aligned on this path, so no adjacent memory is affected.
    
    This matches the STM32 AN4839 guidance that a cache invalidate is
    required after DMA completion and before the CPU reads the updated
    region, not only before the transfer starts. A related instance of
    the same "invalidate too early" defect on STM32H7 SPI DMA is tracked
    in apache/nuttx#11594.
    
    Root-caused on a PX4 FMUv6C (STM32H743) board where MAVLink ULog
    downloads were intermittently corrupted: forensic diffing showed
    corrupted windows were exactly 32 bytes (the D-cache line size),
    cache-line aligned, and byte-for-byte equal to the previous 512-byte
    SD sector cached in the FAT single-sector buffer. Disabling the
    D-cache made the corruption disappear, isolating the defect to cache
    coherency. After this fix, downloaded files matched the source file
    byte-for-byte (sha256 identical) across a 5.8 MB log spanning
    thousands of sectors.
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
    Signed-off-by: Yang-Rui Li <[email protected]>
---
 arch/arm/src/stm32h7/stm32_sdmmc.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/arch/arm/src/stm32h7/stm32_sdmmc.c 
b/arch/arm/src/stm32h7/stm32_sdmmc.c
index 0e713eadb07..2176d2719b1 100644
--- a/arch/arm/src/stm32h7/stm32_sdmmc.c
+++ b/arch/arm/src/stm32h7/stm32_sdmmc.c
@@ -1355,7 +1355,22 @@ static void stm32_recvdma(struct stm32_dev_s *priv)
     }
   else
     {
-      /* In an aligned case, we have always received all blocks */
+      /* In an aligned case, we have always received all blocks.
+       *
+       * The destination buffer was invalidated before the DMA in
+       * stm32_dmarecvsetup(), but on the Cortex-M7 the cache can
+       * speculatively prefetch into this (cacheable) buffer between that
+       * point and DMA completion, leaving stale lines that shadow the
+       * data just written by the IDMA.  Invalidate again now that the
+       * transfer is complete, before the buffer is consumed, so the CPU
+       * reads the freshly received data instead of a previously cached
+       * sector.  The buffer and length are cache-line aligned here (that
+       * is why this aligned path was taken), so no adjacent memory is
+       * affected.
+       */
+
+      up_invalidate_dcache((uintptr_t)priv->buffer,
+                           (uintptr_t)priv->buffer + priv->receivecnt);
 
       priv->remaining = 0;
     }

Reply via email to