dmaengine: stm32-dma: fix potential race between pause and resume
[platform/kernel/linux-starfive.git] / drivers / dma / stm32-dma.c
index 4891a17..3767402 100644 (file)
@@ -675,6 +675,8 @@ static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan)
 
        chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
 
+       chan->status = DMA_PAUSED;
+
        dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan);
 }
 
@@ -789,9 +791,7 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
        if (status & STM32_DMA_TCI) {
                stm32_dma_irq_clear(chan, STM32_DMA_TCI);
                if (scr & STM32_DMA_SCR_TCIE) {
-                       if (chan->status == DMA_PAUSED && !(scr & STM32_DMA_SCR_EN))
-                               stm32_dma_handle_chan_paused(chan);
-                       else
+                       if (chan->status != DMA_PAUSED)
                                stm32_dma_handle_chan_done(chan, scr);
                }
                status &= ~STM32_DMA_TCI;
@@ -838,13 +838,11 @@ static int stm32_dma_pause(struct dma_chan *c)
                return -EPERM;
 
        spin_lock_irqsave(&chan->vchan.lock, flags);
+
        ret = stm32_dma_disable_chan(chan);
-       /*
-        * A transfer complete flag is set to indicate the end of transfer due to the stream
-        * interruption, so wait for interrupt
-        */
        if (!ret)
-               chan->status = DMA_PAUSED;
+               stm32_dma_handle_chan_paused(chan);
+
        spin_unlock_irqrestore(&chan->vchan.lock, flags);
 
        return ret;