[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20221024083611.132588-1-amelie.delaunay@foss.st.com>
Date: Mon, 24 Oct 2022 10:36:11 +0200
From: Amelie Delaunay <amelie.delaunay@...s.st.com>
To: Vinod Koul <vkoul@...nel.org>,
Maxime Coquelin <mcoquelin.stm32@...il.com>,
Alexandre Torgue <alexandre.torgue@...s.st.com>,
Amelie Delaunay <amelie.delaunay@...s.st.com>
CC: <dmaengine@...r.kernel.org>,
<linux-stm32@...md-mailman.stormreply.com>,
<linux-arm-kernel@...ts.infradead.org>,
<linux-kernel@...r.kernel.org>
Subject: [PATCH] dmaengine: stm32-dma: fix potential race between pause and resume
When disabling dma channel, a TCF flag is set and as TCIE is enabled, an
interrupt is raised.
On a busy system, the interrupt may have latency and the user can ask for
dmaengine_resume while stm32-dma driver has not yet managed the complete
pause (backup of registers to restore state in resume).
To avoid such a case, instead of waiting the interrupt to backup the
registers, do it just after disabling the channel and discard Transfer
Complete interrupt in case the channel is paused.
Fixes: 099a9a94be0e ("dmaengine: stm32-dma: add device_pause/device_resume support")
Signed-off-by: Amelie Delaunay <amelie.delaunay@...s.st.com>
---
drivers/dma/stm32-dma.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c
index 4891a1767e5a..37674029cb42 100644
--- a/drivers/dma/stm32-dma.c
+++ b/drivers/dma/stm32-dma.c
@@ -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;
--
2.25.1
Powered by blists - more mailing lists