diff options
-rw-r--r-- | drivers/dma/imx-sdma.c | 21 |
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; } |