omap: Fix race condition in omap dma driver
authorTao Hu <taohu@motorola.com>
Wed, 11 Nov 2009 02:55:17 +0000 (18:55 -0800)
committerGrazvydas Ignotas <notasas@gmail.com>
Thu, 10 Jun 2010 13:17:24 +0000 (16:17 +0300)
The bug could cause irq enable bit of one DMA channel is
cleared/set unexpectedly when 2 (or more) drivers are calling
omap_request_dma()/omap_free_dma() simultaneously

Signed-off-by: Fei Yang <AFY095@motorola.com>
Signed-off-by: Tao Hu <taohu@motorola.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/plat-omap/dma.c

index 25b832d..e356322 100755 (executable)
@@ -690,13 +690,16 @@ static inline void disable_lnk(int lch)
 static inline void omap2_enable_irq_lch(int lch)
 {
        u32 val;
+       unsigned long flags;
 
        if (!cpu_class_is_omap2())
                return;
 
+       spin_lock_irqsave(&dma_chan_lock, flags);
        val = dma_read(IRQENABLE_L0);
        val |= 1 << lch;
        dma_write(val, IRQENABLE_L0);
+       spin_unlock_irqrestore(&dma_chan_lock, flags);
 }
 
 int omap_request_dma(int dev_id, const char *dev_name,
@@ -805,10 +808,13 @@ void omap_free_dma(int lch)
 
        if (cpu_class_is_omap2()) {
                u32 val;
+
+               spin_lock_irqsave(&dma_chan_lock, flags);
                /* Disable interrupts */
                val = dma_read(IRQENABLE_L0);
                val &= ~(1 << lch);
                dma_write(val, IRQENABLE_L0);
+               spin_unlock_irqrestore(&dma_chan_lock, flags);
 
                /* Clear the CSR register and IRQ status register */
                dma_write(OMAP2_DMA_CSR_CLEAR_MASK, CSR(lch));