Skip to content

Commit 7d34eca

Browse files
ADESTMfourmone
authored andcommitted
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. Change-Id: I8d07cd3a2cbb9ff3056b104fea6cab10d90c32fd Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com> Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/linux-stm32/+/252593 Reviewed-by: CITOOLS <MDG-smet-aci-reviews@list.st.com> Reviewed-by: Fabien DESSENNE <fabien.dessenne@foss.st.com>
1 parent 85c7123 commit 7d34eca

File tree

1 file changed

+6
-8
lines changed

1 file changed

+6
-8
lines changed

drivers/dma/stm32-dma.c

+6-8
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,8 @@ static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan)
10651065

10661066
chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id));
10671067

1068+
chan->status = DMA_PAUSED;
1069+
10681070
dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan);
10691071
}
10701072

@@ -1182,9 +1184,7 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid)
11821184
if (status & STM32_DMA_TCI) {
11831185
stm32_dma_irq_clear(chan, STM32_DMA_TCI);
11841186
if (scr & STM32_DMA_SCR_TCIE) {
1185-
if (chan->status == DMA_PAUSED && !(scr & STM32_DMA_SCR_EN))
1186-
stm32_dma_handle_chan_paused(chan);
1187-
else
1187+
if (chan->status != DMA_PAUSED)
11881188
stm32_dma_handle_chan_done(chan, scr);
11891189
}
11901190
status &= ~STM32_DMA_TCI;
@@ -1237,13 +1237,11 @@ static int stm32_dma_pause(struct dma_chan *c)
12371237
return -EPERM;
12381238

12391239
spin_lock_irqsave(&chan->vchan.lock, flags);
1240+
12401241
ret = stm32_dma_disable_chan(chan);
1241-
/*
1242-
* A transfer complete flag is set to indicate the end of transfer due to the stream
1243-
* interruption, so wait for interrupt
1244-
*/
12451242
if (!ret)
1246-
chan->status = DMA_PAUSED;
1243+
stm32_dma_handle_chan_paused(chan);
1244+
12471245
spin_unlock_irqrestore(&chan->vchan.lock, flags);
12481246

12491247
return ret;

0 commit comments

Comments
 (0)