From a44d9d72453ea6b064380d4835e712e574e58d9b Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Fri, 20 Nov 2020 15:33:17 +0100 Subject: dmaengine: stm32-dma: rework irq handler to manage error before xfer events To better understand error that can be detected by the DMA controller, manage the error flags before the transfer flags. This way, it is possible to know if the FIFO error flag is set for an over/underrun condition or a FIFO level error. When a FIFO over/underrun condition occurs, the data is not lost because peripheral request is not acknowledged by the stream until the over/ underrun condition is cleared. If this acknowledge takes too much time, the peripheral itself may detect an over/underrun condition of its internal buffer and data might be lost. That's why in case the FIFO error flag is set, we check if the channel is disabled or not, and if a Transfer Complete flag is set, which means that the channel is disabled because of the end of transfer. Because channel is disabled by hardware either by a FIFO level error, or by an end of transfer. Signed-off-by: Amelie Delaunay Link: https://lore.kernel.org/r/20201120143320.30367-2-amelie.delaunay@st.com Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index d0055d2f0b9a..55a6bd381219 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -648,21 +648,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); - if (status & STM32_DMA_TCI) { - stm32_dma_irq_clear(chan, STM32_DMA_TCI); - if (scr & STM32_DMA_SCR_TCIE) - stm32_dma_handle_chan_done(chan); - status &= ~STM32_DMA_TCI; - } - if (status & STM32_DMA_HTI) { - stm32_dma_irq_clear(chan, STM32_DMA_HTI); - status &= ~STM32_DMA_HTI; - } if (status & STM32_DMA_FEI) { stm32_dma_irq_clear(chan, STM32_DMA_FEI); status &= ~STM32_DMA_FEI; if (sfcr & STM32_DMA_SFCR_FEIE) { - if (!(scr & STM32_DMA_SCR_EN)) + if (!(scr & STM32_DMA_SCR_EN) && + !(status & STM32_DMA_TCI)) dev_err(chan2dev(chan), "FIFO Error\n"); else dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); @@ -674,6 +665,19 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) if (sfcr & STM32_DMA_SCR_DMEIE) dev_dbg(chan2dev(chan), "Direct mode overrun\n"); } + + if (status & STM32_DMA_TCI) { + stm32_dma_irq_clear(chan, STM32_DMA_TCI); + if (scr & STM32_DMA_SCR_TCIE) + stm32_dma_handle_chan_done(chan); + status &= ~STM32_DMA_TCI; + } + + if (status & STM32_DMA_HTI) { + stm32_dma_irq_clear(chan, STM32_DMA_HTI); + status &= ~STM32_DMA_HTI; + } + if (status) { stm32_dma_irq_clear(chan, status); dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); -- cgit v1.2.3