summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/imx-sdma.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 095dae712c12..3bbb04dcf212 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -761,6 +761,14 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
static void sdma_tasklet(unsigned long data)
{
struct sdma_channel *sdmac = (struct sdma_channel *) data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdmac->lock, flags);
+ if (sdmac->status != DMA_IN_PROGRESS) {
+ spin_unlock_irqrestore(&sdmac->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&sdmac->lock, flags);
if (sdmac->flags & IMX_DMA_SG_LOOP)
sdma_handle_channel_loop(sdmac);
@@ -771,7 +779,7 @@ static void sdma_tasklet(unsigned long data)
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
{
struct sdma_engine *sdma = dev_id;
- unsigned long stat;
+ unsigned long stat, flags;
stat = readl_relaxed(sdma->regs + SDMA_H_INTR);
/* not interested in channel 0 interrupts */
@@ -786,7 +794,10 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
(sdmac->peripheral_type != IMX_DMATYPE_HDMI))
sdma_update_channel_loop(sdmac);
- tasklet_schedule(&sdmac->tasklet);
+ spin_lock_irqsave(&sdmac->lock, flags);
+ if (sdmac->status == DMA_IN_PROGRESS)
+ tasklet_schedule(&sdmac->tasklet);
+ spin_unlock_irqrestore(&sdmac->lock, flags);
__clear_bit(channel, &stat);
}
@@ -964,9 +975,13 @@ static int sdma_disable_channel(struct dma_chan *chan)
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
+ unsigned long flags;
- writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
+ spin_lock_irqsave(&sdmac->lock, flags);
sdmac->status = DMA_ERROR;
+ spin_unlock_irqrestore(&sdmac->lock, flags);
+
+ writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
return 0;
}