summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Hu <taohu@motorola.com>2009-11-10 18:55:17 -0800
committerTony Lindgren <tony@atomide.com>2009-11-10 18:55:17 -0800
commitee90732456fe8e75406fdd3cd136a4bfb7ce31f5 (patch)
tree0c0f49d8240d595e8162fbc02939266e3c268a9e
parentb419148e567728f6af0c3b01965c1cc141e3e13a (diff)
downloadlinux-ee90732456fe8e75406fdd3cd136a4bfb7ce31f5.tar.gz
linux-ee90732456fe8e75406fdd3cd136a4bfb7ce31f5.tar.bz2
linux-ee90732456fe8e75406fdd3cd136a4bfb7ce31f5.zip
omap: Fix race condition in omap dma driver
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>
-rw-r--r--arch/arm/plat-omap/dma.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index b53125f41293..02ed94526aa3 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -691,13 +691,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,
@@ -799,10 +802,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));