Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <amelie.delaunay@st.com>
Link: https://lore.kernel.org/r/20201120143320.30367-2-amelie.delaunay@st.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Amelie Delaunay and committed by
Vinod Koul
a44d9d72 4421fe53

+15 -11
+15 -11
drivers/dma/stm32-dma.c
··· 648 648 scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 649 649 sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); 650 650 651 - if (status & STM32_DMA_TCI) { 652 - stm32_dma_irq_clear(chan, STM32_DMA_TCI); 653 - if (scr & STM32_DMA_SCR_TCIE) 654 - stm32_dma_handle_chan_done(chan); 655 - status &= ~STM32_DMA_TCI; 656 - } 657 - if (status & STM32_DMA_HTI) { 658 - stm32_dma_irq_clear(chan, STM32_DMA_HTI); 659 - status &= ~STM32_DMA_HTI; 660 - } 661 651 if (status & STM32_DMA_FEI) { 662 652 stm32_dma_irq_clear(chan, STM32_DMA_FEI); 663 653 status &= ~STM32_DMA_FEI; 664 654 if (sfcr & STM32_DMA_SFCR_FEIE) { 665 - if (!(scr & STM32_DMA_SCR_EN)) 655 + if (!(scr & STM32_DMA_SCR_EN) && 656 + !(status & STM32_DMA_TCI)) 666 657 dev_err(chan2dev(chan), "FIFO Error\n"); 667 658 else 668 659 dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); ··· 665 674 if (sfcr & STM32_DMA_SCR_DMEIE) 666 675 dev_dbg(chan2dev(chan), "Direct mode overrun\n"); 667 676 } 677 + 678 + if (status & STM32_DMA_TCI) { 679 + stm32_dma_irq_clear(chan, STM32_DMA_TCI); 680 + if (scr & STM32_DMA_SCR_TCIE) 681 + stm32_dma_handle_chan_done(chan); 682 + status &= ~STM32_DMA_TCI; 683 + } 684 + 685 + if (status & STM32_DMA_HTI) { 686 + stm32_dma_irq_clear(chan, STM32_DMA_HTI); 687 + status &= ~STM32_DMA_HTI; 688 + } 689 + 668 690 if (status) { 669 691 stm32_dma_irq_clear(chan, status); 670 692 dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status);