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

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

commit d9a2e4225d945c2661092de1b4ae218f7368a968
Author: Sarthak Pandey <[email protected]>
AuthorDate: Thu Oct 22 23:02:10 2026 +0530

    arch/arm/imxrt: fix eDMA NCE error caused by zero-length split transfer
    
    - In imxrt_dma_send(), verify dev->dmatx.nlength > 0 before setting up
      a chained TCD. Chaining a TCD with iter == 0 causes eDMA NCE errors
      and halts the eDMA engine when HOE is enabled.
    - In imxrt_dmaterminate(), clear CITER and BITER registers so residual
      zero-iteration states do not trigger repeated NCE errors on channel
      re-activation.
    - In imxrt_dmach_xfrsetup(), return -EINVAL if config->iter is 0.
    
    Fixes #20881
    
    Signed-off-by: Sarthak Pandey <[email protected]>
---
 arch/arm/src/imxrt/imxrt_edma.c   | 20 +++++++++++++++++---
 arch/arm/src/imxrt/imxrt_serial.c |  2 +-
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/arch/arm/src/imxrt/imxrt_edma.c b/arch/arm/src/imxrt/imxrt_edma.c
index 52e0149f887..1f787509c0c 100644
--- a/arch/arm/src/imxrt/imxrt_edma.c
+++ b/arch/arm/src/imxrt/imxrt_edma.c
@@ -472,6 +472,14 @@ static void imxrt_dmaterminate(struct imxrt_dmach_s 
*dmach, int result)
   regaddr         = IMXRT_EDMA_TCD_DLASTSGA(chan);
   putreg32(0, regaddr);
 
+  /* Clear CITER and BITER to remove error source */
+
+  regaddr         = IMXRT_EDMA_TCD_CITER_ELINK(chan);
+  putreg16(0, regaddr);
+
+  regaddr         = IMXRT_EDMA_TCD_BITER_ELINK(chan);
+  putreg16(0, regaddr);
+
 #if CONFIG_IMXRT_EDMA_NTCD > 0
   /* Return all allocated TCDs to the free list */
 
@@ -481,10 +489,10 @@ static void imxrt_dmaterminate(struct imxrt_dmach_s 
*dmach, int result)
        * if not continue to free tcds in chain
        */
 
-       next = dmach->flags & EDMA_CONFIG_LOOPDEST ?
-              NULL : (struct imxrt_edmatcd_s *)tcd->dlastsga;
+      next = dmach->flags & EDMA_CONFIG_LOOPDEST ?
+             NULL : (struct imxrt_edmatcd_s *)tcd->dlastsga;
 
-       imxrt_tcd_free_nolock(tcd);
+      imxrt_tcd_free_nolock(tcd);
     }
 
   dmach->head = NULL;
@@ -992,6 +1000,11 @@ int imxrt_dmach_xfrsetup(DMACH_HANDLE handle,
   DEBUGASSERT(dmach != NULL);
   dmainfo("dmach%u: %p config: %p\n", dmach->chan, dmach, config);
 
+  if (config->iter == 0)
+    {
+      return -EINVAL;
+    }
+
   dmach->flags = config->flags;
 
 #if CONFIG_IMXRT_EDMA_NTCD > 0
@@ -1299,6 +1312,7 @@ unsigned int imxrt_dmach_getcount(DMACH_HANDLE handle)
 unsigned int imxrt_dmach_idle(DMACH_HANDLE handle)
 {
   struct imxrt_dmach_s *dmach = (struct imxrt_dmach_s *)handle;
+
   return dmach->state == IMXRT_DMA_IDLE ? 0 : -1;
 }
 
diff --git a/arch/arm/src/imxrt/imxrt_serial.c 
b/arch/arm/src/imxrt/imxrt_serial.c
index 2f4a0872c3f..905ff1188c7 100644
--- a/arch/arm/src/imxrt/imxrt_serial.c
+++ b/arch/arm/src/imxrt/imxrt_serial.c
@@ -3604,7 +3604,7 @@ static void imxrt_dma_send(struct uart_dev_s *dev)
 #if CONFIG_IMXRT_EDMA_NTCD > 1
   /* Is this a split transfer? */
 
-  if (dev->dmatx.nbuffer)
+  if (dev->dmatx.nbuffer && dev->dmatx.nlength > 0)
     {
       config.iter   = priv->dev.dmatx.nlength;
       config.saddr  = (uint32_t) priv->dev.dmatx.nbuffer;

Reply via email to