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: 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>
This commit is contained in:
parent
32ce108833
commit
409ffc4d99
|
@ -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);
|
||||
stm32_dma_write(dmadev, reg, 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);
|
||||
return readl_relaxed_poll_timeout_atomic(dmadev->base + reg,
|
||||
dma_scr, !(dma_scr & STM32_DMA_SCR_EN),
|
||||
10, 1000000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue