diff options
author | Santosh Shilimkar <santosh.shilimkar@ti.com> | 2009-04-23 14:10:40 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2009-04-23 14:10:40 -0400 |
commit | da1b94e6a68e1bdeb9cdda016cceb17228b37d25 (patch) | |
tree | 2c405438f9f296d15470382c00d4d00b4c42891a /arch/arm/plat-omap | |
parent | 091069740304c979f957ceacec39c461d0192158 (diff) |
ARM: OMAP: Fix for possible race condition in omap_free_dma()
Fix the possible race condition in omap_free_dma(). Function omap_free_dma()
sets the dev_id = -1 and then accesses the channel afterwards to clear it.
But setting the dev_id=-1 makes the channel available for allocation again.
So it is possible someone else can grab it and results are unpredictable.
To avod this DMA channle is cleared first and then the dev_id = -1 is set.
Thanks to McNeil, Sean <sean.mcneil@ti.com> for ointing out this issue.
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/plat-omap')
-rw-r--r-- | arch/arm/plat-omap/dma.c | 13 |
1 files changed, 6 insertions, 7 deletions
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 21cc0142b97a..7fc8c045ad5d 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c | |||
@@ -760,19 +760,12 @@ void omap_free_dma(int lch) | |||
760 | { | 760 | { |
761 | unsigned long flags; | 761 | unsigned long flags; |
762 | 762 | ||
763 | spin_lock_irqsave(&dma_chan_lock, flags); | ||
764 | if (dma_chan[lch].dev_id == -1) { | 763 | if (dma_chan[lch].dev_id == -1) { |
765 | pr_err("omap_dma: trying to free unallocated DMA channel %d\n", | 764 | pr_err("omap_dma: trying to free unallocated DMA channel %d\n", |
766 | lch); | 765 | lch); |
767 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
768 | return; | 766 | return; |
769 | } | 767 | } |
770 | 768 | ||
771 | dma_chan[lch].dev_id = -1; | ||
772 | dma_chan[lch].next_lch = -1; | ||
773 | dma_chan[lch].callback = NULL; | ||
774 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
775 | |||
776 | if (cpu_class_is_omap1()) { | 769 | if (cpu_class_is_omap1()) { |
777 | /* Disable all DMA interrupts for the channel. */ | 770 | /* Disable all DMA interrupts for the channel. */ |
778 | dma_write(0, CICR(lch)); | 771 | dma_write(0, CICR(lch)); |
@@ -798,6 +791,12 @@ void omap_free_dma(int lch) | |||
798 | dma_write(0, CCR(lch)); | 791 | dma_write(0, CCR(lch)); |
799 | omap_clear_dma(lch); | 792 | omap_clear_dma(lch); |
800 | } | 793 | } |
794 | |||
795 | spin_lock_irqsave(&dma_chan_lock, flags); | ||
796 | dma_chan[lch].dev_id = -1; | ||
797 | dma_chan[lch].next_lch = -1; | ||
798 | dma_chan[lch].callback = NULL; | ||
799 | spin_unlock_irqrestore(&dma_chan_lock, flags); | ||
801 | } | 800 | } |
802 | EXPORT_SYMBOL(omap_free_dma); | 801 | EXPORT_SYMBOL(omap_free_dma); |
803 | 802 | ||