Commit 409ffc4d authored by Amelie Delaunay's avatar Amelie Delaunay Committed by Vinod Koul

dmaengine: stm32-dma: fix sleeping function called from invalid context

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: default avatarAmelie Delaunay <amelie.delaunay@st.com>
Link: https://lore.kernel.org/r/20200129153628.29329-8-amelie.delaunay@st.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent 32ce1088
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/iopoll.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -421,29 +422,19 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) ...@@ -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) static int stm32_dma_disable_chan(struct stm32_dma_chan *chan)
{ {
struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan);
unsigned long timeout = jiffies + msecs_to_jiffies(5000); u32 dma_scr, id, reg;
u32 dma_scr, id;
id = chan->id; 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) { if (dma_scr & STM32_DMA_SCR_EN) {
dma_scr &= ~STM32_DMA_SCR_EN; dma_scr &= ~STM32_DMA_SCR_EN;
stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr); stm32_dma_write(dmadev, reg, dma_scr);
do { return readl_relaxed_poll_timeout_atomic(dmadev->base + reg,
dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); dma_scr, !(dma_scr & STM32_DMA_SCR_EN),
dma_scr &= STM32_DMA_SCR_EN; 10, 1000000);
if (!dma_scr)
break;
if (time_after_eq(jiffies, timeout)) {
dev_err(chan2dev(chan), "%s: timeout!\n",
__func__);
return -EBUSY;
}
cond_resched();
} while (1);
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment