dmaengine: stm32-dma: fix sleeping function called from invalid context
authorAmelie Delaunay <amelie.delaunay@st.com>
Wed, 29 Jan 2020 15:36:27 +0000 (16:36 +0100)
committerVinod Koul <vkoul@kernel.org>
Tue, 25 Feb 2020 05:45:05 +0000 (11:15 +0530)
This patch fixes BUG: sleeping function called from invalid context in
stm32_dma_disable_chan function.

The goal of this function is to force channel disable if it has not been
disabled by hardware. This consists in clearing STM32_DMA_SCR_EN bit and
read it as 0 to ensure the channel is well disabled and the last transfer
is over.

In previous implementation, the waiting loop was based on a do...while (1)
with a call to cond_resched to give the scheduler a chance to run a higher
priority process.

But in some conditions, stm32_dma_disable_chan can be called while
preemption is disabled, on a stm32_dma_stop call for example. So
cond_resched must not be used.

To avoid this, use readl_relaxed_poll_timeout_atomic to poll
STM32_DMA_SCR_EN bit cleared.

Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
Link: https://lore.kernel.org/r/20200129153628.29329-8-amelie.delaunay@st.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/stm32-dma.c

index 01a2374..b585e11 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/iopoll.h>
 #include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -421,29 +422,19 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags)
 static int stm32_dma_disable_chan(struct stm32_dma_chan *chan)
 {
        struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
-       unsigned long timeout = jiffies + msecs_to_jiffies(5000);
-       u32 dma_scr, id;
+       u32 dma_scr, id, reg;
 
        id = chan->id;
-       dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
+       reg = STM32_DMA_SCR(id);
+       dma_scr = stm32_dma_read(dmadev, reg);
 
        if (dma_scr & STM32_DMA_SCR_EN) {
                dma_scr &= ~STM32_DMA_SCR_EN;
-               stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr);
-
-               do {
-                       dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id));
-                       dma_scr &= STM32_DMA_SCR_EN;
-                       if (!dma_scr)
-                               break;
-
-                       if (time_after_eq(jiffies, timeout)) {
-                               dev_err(chan2dev(chan), "%s: timeout!\n",
-                                       __func__);
-                               return -EBUSY;
-                       }
-                       cond_resched();
-               } while (1);
+               stm32_dma_write(dmadev, reg, dma_scr);
+
+               return readl_relaxed_poll_timeout_atomic(dmadev->base + reg,
+                                       dma_scr, !(dma_scr & STM32_DMA_SCR_EN),
+                                       10, 1000000);
        }
 
        return 0;