arch/arm/stm32h7: Fix UART TX DMA getting stuck

When closing a serial port an ongoing TX DMA transfer will be stopped. This can cause
one (or multiple) the following:

- dev->dmatx.length != 0
- dev->dmatx.nlength != 0
- stm32_dmaresidual returning a non-zero residual

This is caused by length/nlength not being set to 0 at startup or during closing.
In addition the DMA_SxNDTR register is not set to 0 at startup or during closing.

This commit solves the issue by setting the variables and register to 0 during closing.

Signed-off-by: Alexander Lerach <alexander@auterion.com>

arch/arm/stm32h7: Add review feedback regarding style

Removed non-needed spaces.
Aligned style of documentation.

Signed-off-by: Alexander Lerach <alexander@auterion.com>
This commit is contained in:
Alexander Lerach
2025-10-15 18:44:16 +02:00
committed by Xiang Xiao
parent fca1010a5b
commit a9b258aa68
2 changed files with 63 additions and 0 deletions
+60
View File
@@ -159,6 +159,10 @@ struct stm32_dma_ops_s
void (*dma_setup)(DMA_HANDLE handle, stm32_dmacfg_t *cfg);
/* Free the DMA */
void (*dma_free)(DMA_HANDLE handle);
/* Start the DMA */
void (*dma_start)(DMA_HANDLE handle, dma_callback_t callback,
@@ -185,6 +189,7 @@ struct stm32_dma_ops_s
static void stm32_mdma_disable(DMA_CHANNEL dmachan);
static int stm32_mdma_interrupt(int irq, void *context, void *arg);
static void stm32_mdma_setup(DMA_HANDLE handle, stm32_dmacfg_t *cfg);
static void stm32_mdma_free(DMA_HANDLE handle);
static void stm32_mdma_start(DMA_HANDLE handle, dma_callback_t callback,
void *arg, bool half);
static size_t stm32_mdma_residual(DMA_HANDLE handle);
@@ -200,6 +205,7 @@ static void stm32_mdma_dump(DMA_HANDLE handle, const char *msg);
static void stm32_sdma_disable(DMA_CHANNEL dmachan);
static int stm32_sdma_interrupt(int irq, void *context, void *arg);
static void stm32_sdma_setup(DMA_HANDLE handle, stm32_dmacfg_t *cfg);
static void stm32_sdma_free(DMA_HANDLE handle);
static void stm32_sdma_start(DMA_HANDLE handle, dma_callback_t callback,
void *arg, bool half);
static size_t stm32_sdma_residual(DMA_HANDLE handle);
@@ -215,6 +221,7 @@ static void stm32_sdma_dump(DMA_HANDLE handle, const char *msg);
static void stm32_bdma_disable(DMA_CHANNEL dmachan);
static int stm32_bdma_interrupt(int irq, void *context, void *arg);
static void stm32_bdma_setup(DMA_HANDLE handle, stm32_dmacfg_t *cfg);
static void stm32_bdma_free(DMA_HANDLE handle);
static void stm32_bdma_start(DMA_HANDLE handle, dma_callback_t callback,
void *arg, bool half);
static size_t stm32_bdma_residual(DMA_HANDLE handle);
@@ -265,6 +272,7 @@ struct stm32_dma_ops_s g_dma_ops[DMA_CONTROLLERS] =
.dma_disable = stm32_mdma_disable,
.dma_interrupt = stm32_mdma_interrupt,
.dma_setup = stm32_mdma_setup,
.dma_free = stm32_mdma_free,
.dma_start = stm32_mdma_start,
.dma_residual = stm32_mdma_residual,
#ifdef CONFIG_STM32H7_DMACAPABLE
@@ -287,6 +295,7 @@ struct stm32_dma_ops_s g_dma_ops[DMA_CONTROLLERS] =
.dma_disable = stm32_sdma_disable,
.dma_interrupt = stm32_sdma_interrupt,
.dma_setup = stm32_sdma_setup,
.dma_free = stm32_sdma_free,
.dma_start = stm32_sdma_start,
.dma_residual = stm32_sdma_residual,
#ifdef CONFIG_STM32H7_DMACAPABLE
@@ -309,6 +318,7 @@ struct stm32_dma_ops_s g_dma_ops[DMA_CONTROLLERS] =
.dma_disable = stm32_sdma_disable,
.dma_interrupt = stm32_sdma_interrupt,
.dma_setup = stm32_sdma_setup,
.dma_free = stm32_sdma_free,
.dma_start = stm32_sdma_start,
.dma_residual = stm32_sdma_residual,
#ifdef CONFIG_STM32H7_DMACAPABLE
@@ -331,6 +341,7 @@ struct stm32_dma_ops_s g_dma_ops[DMA_CONTROLLERS] =
.dma_disable = stm32_bdma_disable,
.dma_interrupt = stm32_bdma_interrupt,
.dma_setup = stm32_bdma_setup,
.dma_free = stm32_bdma_free,
.dma_start = stm32_bdma_start,
.dma_residual = stm32_bdma_residual,
#ifdef CONFIG_STM32H7_DMACAPABLE
@@ -959,6 +970,21 @@ static void stm32_mdma_setup(DMA_HANDLE handle, stm32_dmacfg_t *cfg)
#warning stm32_mdma_setup not implemented
}
/****************************************************************************
* Name: stm32_mdma_free
*
* Description:
* Free master DMA
*
****************************************************************************/
static void stm32_mdma_free(DMA_HANDLE handle)
{
DMA_CHANNEL dmachan = (DMA_CHANNEL)handle;
dmachan_putreg(dmachan, STM32_BDMACH_CNDTR_OFFSET, 0);
}
/****************************************************************************
* Name: stm32_mdma_start
*
@@ -1393,6 +1419,21 @@ static void stm32_sdma_setup(DMA_HANDLE handle, stm32_dmacfg_t *cfg)
dmachan_putreg(dmachan, STM32_DMA_SCR_OFFSET, regval);
}
/****************************************************************************
* Name: stm32_sdma_sfree
*
* Description:
* Free master DMA
*
****************************************************************************/
static void stm32_sdma_free(DMA_HANDLE handle)
{
DMA_CHANNEL dmachan = (DMA_CHANNEL)handle;
dmachan_putreg(dmachan, STM32_DMA_SNDTR_OFFSET, 0);
}
/****************************************************************************
* Name: stm32_sdma_start
*
@@ -1961,6 +2002,21 @@ static void stm32_bdma_setup(DMA_HANDLE handle, stm32_dmacfg_t *cfg)
dmachan_putreg(dmachan, STM32_BDMACH_CCR_OFFSET, regval);
}
/****************************************************************************
* Name: stm32_bdma_sfree
*
* Description:
* Free master DMA
*
****************************************************************************/
static void stm32_bdma_free(DMA_HANDLE handle)
{
DMA_CHANNEL dmachan = (DMA_CHANNEL)handle;
dmachan_putreg(dmachan, STM32_BDMACH_CNDTR_OFFSET, 0);
}
/****************************************************************************
* Name: stm32_bdma_start
*
@@ -2471,6 +2527,10 @@ void stm32_dmafree(DMA_HANDLE handle)
controller = dmachan->ctrl;
DEBUGASSERT(controller >= MDMA && controller <= BDMA);
/* Do controller specific free */
g_dma_ops[controller].dma_free(handle);
/* Get DMAMUX associated with DMA controller */
dmamux = g_dma[controller].dmamux;
+3
View File
@@ -2382,6 +2382,9 @@ static void up_dma_shutdown(struct uart_dev_s *dev)
stm32_dmafree(priv->txdma);
priv->txdma = NULL;
dev->dmatx.length = 0;
dev->dmatx.nlength = 0;
}
#endif
}