omap: dma: Clear status registers on enable/disable irq.
Subsystems (2)
PATCH v2 1/1 omap: dma: Clear status registers on enable/disable irq.
Use omap_disable_channel_irq() function instead of directly accessing CICR. The omap_disable_chanel_irq() function clears pending interrupts and disables interrupt on channel.
Functions omap2_enable_irq_lch()/omap2_disable_irq_lch() clear interrupt status register.
---
v1 initial revision
v2 Review by Tony Lindgren
--- arch/arm/plat-omap/dma.c | 59 +++++++++++++++++++++------------------------ 1 files changed, 28 insertions(+), 31 deletions(-)
arch/arm/plat-omap/dma.c +28 -31
@@ -563,22 +563,25 @@ EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);static inline void omap_enable_channel_irq (int lch) { -u32 status; -/* Clear CSR */ if (cpu_class_is_omap1 ()) - status = p->dma_read (CSR , lch); -else if (cpu_class_is_omap2 ()) + p->dma_read (CSR , lch); +else p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , lch);/* Enable some nice interrupts. */ p->dma_write (dma_chan[lch].enabled_irqs,CICR , lch); } -static void omap_disable_channel_irq (int lch) +static inline void omap_disable_channel_irq (int lch) { -if (cpu_class_is_omap2 ()) - p->dma_write (0 ,CICR , lch); +/* disable channel interrupts */ + p->dma_write (0 ,CICR , lch); +/* Clear CSR */ +if (cpu_class_is_omap1 ()) + p->dma_read (CSR , lch); +else + p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , lch); }void omap_enable_dma_irq (int lch,u16 bits)
@@ -622,14 +625,14 @@ static inline void disable_lnk(int lch) l = p->dma_read (CLNK_CTRL , lch);/* Disable interrupts */ +omap_disable_channel_irq (lch); +if (cpu_class_is_omap1 ()) { - p->dma_write (0 ,CICR , lch);/* Set the STOP_LNK bit */ l |=1 <<14 ; }if (cpu_class_is_omap2 ()) { -omap_disable_channel_irq (lch);/* Clear the ENABLE_LNK bit */ l &= ~(1 <<15 ); }
@@ -647,6 +650,9 @@ static inline void omap2_enable_irq_lch(int lch)return ;spin_lock_irqsave (&dma_chan_lock, flags); +/* clear IRQ STATUS */ + p->dma_write (1 << lch,IRQSTATUS_L0 , lch); +/* Enable interrupt */ val = p->dma_read (IRQENABLE_L0 , lch); val |=1 << lch; p->dma_write (val,IRQENABLE_L0 , lch);
@@ -662,9 +668,12 @@ static inline void omap2_disable_irq_lch(int lch)return ;spin_lock_irqsave (&dma_chan_lock, flags); +/* Disable interrupt */ val = p->dma_read (IRQENABLE_L0 , lch); val &= ~(1 << lch); p->dma_write (val,IRQENABLE_L0 , lch); +/* clear IRQ STATUS */ + p->dma_write (1 << lch,IRQSTATUS_L0 , lch);spin_unlock_irqrestore (&dma_chan_lock, flags); }
@@ -735,11 +744,8 @@ int omap_request_dma(int dev_id, const char *dev_name, }if (cpu_class_is_omap2 ()) { -omap2_enable_irq_lch (free_ch);omap_enable_channel_irq (free_ch); -/* Clear the CSR register and IRQ status register */ - p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , free_ch); - p->dma_write (1 << free_ch,IRQSTATUS_L0 ,0 ); +omap2_enable_irq_lch (free_ch); } *dma_ch_out = free_ch;
@@ -758,27 +764,19 @@ void omap_free_dma(int lch)return ; } -if (cpu_class_is_omap1 ()) { -/* Disable all DMA interrupts for the channel. */ - p->dma_write (0 ,CICR , lch); -/* Make sure the DMA transfer is stopped. */ - p->dma_write (0 ,CCR , lch); - } - -if (cpu_class_is_omap2 ()) { +/* Disable interrupt for logical channel */ +if (cpu_class_is_omap2 ())omap2_disable_irq_lch (lch); -/* Clear the CSR register and IRQ status register */ - p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , lch); - p->dma_write (1 << lch,IRQSTATUS_L0 , lch); +/* Disable all DMA interrupts for the channel. */ +omap_disable_channel_irq (lch); -/* Disable all DMA interrupts for the channel. */ - p->dma_write (0 ,CICR , lch); +/* Make sure the DMA transfer is stopped. */ + p->dma_write (0 ,CCR , lch); -/* Make sure the DMA transfer is stopped. */ - p->dma_write (0 ,CCR , lch); +/* Clear registers */ +if (cpu_class_is_omap2 ())omap_clear_dma (lch); - }spin_lock_irqsave (&dma_chan_lock, flags); dma_chan[lch].dev_id =-1 ;
@@ -926,8 +924,7 @@ void omap_stop_dma(int lch)u32 l;/* Disable all interrupts on the channel */ -if (cpu_class_is_omap1 ()) - p->dma_write (0 ,CICR , lch); +omap_disable_channel_irq (lch); l = p->dma_read (CCR , lch); if (IS_DMA_ERRATA(DMA_ERRATA_i541) &&
Signature · 1 line
1.7.4.1
PATCH v2 1/1 omap: dma: Clear status registers on enable/disable irq.
Quoted 7 lines · Oleg Matcovschi
Use
omap_disable_channel_irq()function instead of directly accessing CICR. Theomap_disable_chanel_irq()function clears pending interrupts and disables interrupt on channel.
Functions omap2_enable_irq_lch()/omap2_disable_irq_lch() clear interrupt status register.
Quoted 8 lines
Signed-off-by Oleg Matcovschi <[email protected]>---
v1 initial revision
v2 Review by Tony Lindgren--- arch/arm/plat-omap/dma.c | 59 +++++++++++++++++++++------------------------ 1 files changed, 28 insertions(+), 31 deletions(-)
Tested on BeagleBoard by using mmc and audio
PATCH v2 1/1 omap: dma: Clear status registers on enable/disable irq.
In reply to Oleg MatcovschiQuoted 5 lines · Oleg Matcovschi
Use
omap_disable_channel_irq()function instead of directly accessing CICR. Theomap_disable_chanel_irq()function clears pending interrupts and disables interrupt on channel.
Functions omap2_enable_irq_lch()/omap2_disable_irq_lch() clear interrupt status register.
Looking at this again, I'll apply this into cleanup-dma instead of fixes.
If it fixes something that I can't see, please reply with a description what it fixes and I'll move it into fixes.
Regards,
Tony
PATCH v2 1/1 omap: dma: Clear status registers on enable/disable irq.
Quoted 7 lines
Quoted 6 lines · Oleg Matcovschi
Use
omap_disable_channel_irq()function instead of directly accessing CICR. Theomap_disable_chanel_irq()function clears pending interrupts and disables interrupt on channel.
Functions omap2_enable_irq_lch()/omap2_disable_irq_lch() clear interrupt status register.
Quoted 5 lines
Looking at this again, I'll apply this into cleanup-dma instead of fixes.
If it fixes something that I can't see, please reply with a description what it fixes and I'll move it into fixes. Regards,
Tony
Sure, cleanup-dma sounds ok.
Code covers:
- my test case for 4460:
I could reproduce 2 interrupts @ omap-pcm driver after omap_stop_dma function call.
1st irq CSR: 0x42 (half & drop)
2nd irq CSR: 0x02 (drop)
Only 1 interrupt occurs after applying this patch(overnight test results) Test case was created to reproduce problem reported by customer(without clear description):
contiguous playback of 0.5 wav file (frequent start/stop audio transitions) contiguous data transfers on 15 self-linked dma channels.
- omap_request_dma could cause spurious interrupt
(enable irq, clear irq status instead of clear irq status, enable irq)
thanks,
Oleg
PATCH v2 1/1 omap: dma: Clear status registers on enable/disable irq.
In reply to Oleg MatcovschiQuoted 11 lines · On Tue, 15 May 2012 14:35:08 Oleg Matcovschi wrote:
Use
omap_disable_channel_irq()function instead of directly accessing CICR. Theomap_disable_chanel_irq()function clears pending interrupts and disables interrupt on channel.
Functions omap2_enable_irq_lch()/omap2_disable_irq_lch() clear interrupt status register.Signed-off-by Oleg Matcovschi <[email protected]>---
v1 initial revision
v2 Review by Tony Lindgren
My Tested-by: on OMAP1 still valid for v2 if you care.
Thanks,
Janusz
Quoted 141 lines
--- arch/arm/plat-omap/dma.c | 59 +++++++++++++++++++++------------------------ 1 files changed, 28 insertions(+), 31 deletions(-)arch/arm/plat-omap/dma.c +28
-31@@ -563,22 +563,25 @@ EXPORT_SYMBOL(omap_set_dma_dest_burst_mode);static inline void omap_enable_channel_irq (int lch) { -u32 status; -/* Clear CSR */ if (cpu_class_is_omap1 ()) - status = p->dma_read (CSR , lch); -else if (cpu_class_is_omap2 ()) + p->dma_read (CSR , lch); +else p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , lch);/* Enable some nice interrupts. */ p->dma_write (dma_chan[lch].enabled_irqs,CICR , lch); } -static void omap_disable_channel_irq (int lch) +static inline void omap_disable_channel_irq (int lch) { -if (cpu_class_is_omap2 ()) - p->dma_write (0 ,CICR , lch); +/* disable channel interrupts */ + p->dma_write (0 ,CICR , lch); +/* Clear CSR */ +if (cpu_class_is_omap1 ()) + p->dma_read (CSR , lch); +else + p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , lch); }void omap_enable_dma_irq (int lch,u16 bits)@@ -622,14 +625,14 @@ static inline void disable_lnk(int lch) l = p->dma_read (CLNK_CTRL , lch);/* Disable interrupts */ +omap_disable_channel_irq (lch); +if (cpu_class_is_omap1 ()) { - p->dma_write (0 ,CICR , lch);/* Set the STOP_LNK bit */ l |=1 <<14 ; }if (cpu_class_is_omap2 ()) { -omap_disable_channel_irq (lch);/* Clear the ENABLE_LNK bit */ l &= ~(1 <<15 ); }@@ -647,6 +650,9 @@ static inline void omap2_enable_irq_lch(int lch)return ;spin_lock_irqsave (&dma_chan_lock, flags); +/* clear IRQ STATUS */ + p->dma_write (1 << lch,IRQSTATUS_L0 , lch); +/* Enable interrupt */ val = p->dma_read (IRQENABLE_L0 , lch); val |=1 << lch; p->dma_write (val,IRQENABLE_L0 , lch);@@ -662,9 +668,12 @@ static inline void omap2_disable_irq_lch(int lch)return ;spin_lock_irqsave (&dma_chan_lock, flags); +/* Disable interrupt */ val = p->dma_read (IRQENABLE_L0 , lch); val &= ~(1 << lch); p->dma_write (val,IRQENABLE_L0 , lch); +/* clear IRQ STATUS */ + p->dma_write (1 << lch,IRQSTATUS_L0 , lch);spin_unlock_irqrestore (&dma_chan_lock, flags); }@@ -735,11 +744,8 @@ int omap_request_dma(int dev_id, const char *dev_name, }if (cpu_class_is_omap2 ()) { -omap2_enable_irq_lch (free_ch);omap_enable_channel_irq (free_ch); -/* Clear the CSR register and IRQ status register */ - p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , free_ch); - p->dma_write (1 << free_ch,IRQSTATUS_L0 ,0 ); +omap2_enable_irq_lch (free_ch); } *dma_ch_out = free_ch;@@ -758,27 +764,19 @@ void omap_free_dma(int lch)return ; } -if (cpu_class_is_omap1 ()) { -/* Disable all DMA interrupts for the channel. */ - p->dma_write (0 ,CICR , lch); -/* Make sure the DMA transfer is stopped. */ - p->dma_write (0 ,CCR , lch); - } - -if (cpu_class_is_omap2 ()) { +/* Disable interrupt for logical channel */ +if (cpu_class_is_omap2 ())omap2_disable_irq_lch (lch); -/* Clear the CSR register and IRQ status register */ - p->dma_write (OMAP2_DMA_CSR_CLEAR_MASK ,CSR , lch); - p->dma_write (1 << lch,IRQSTATUS_L0 , lch); +/* Disable all DMA interrupts for the channel. */ +omap_disable_channel_irq (lch); -/* Disable all DMA interrupts for the channel. */ - p->dma_write (0 ,CICR , lch); +/* Make sure the DMA transfer is stopped. */ + p->dma_write (0 ,CCR , lch); -/* Make sure the DMA transfer is stopped. */ - p->dma_write (0 ,CCR , lch); +/* Clear registers */ +if (cpu_class_is_omap2 ())omap_clear_dma (lch); - }spin_lock_irqsave (&dma_chan_lock, flags); dma_chan[lch].dev_id =-1 ;@@ -926,8 +924,7 @@ void omap_stop_dma(int lch)u32 l;/* Disable all interrupts on the channel */ -if (cpu_class_is_omap1 ()) - p->dma_write (0 ,CICR , lch); +omap_disable_channel_irq (lch); l = p->dma_read (CCR , lch); if (IS_DMA_ERRATA(DMA_ERRATA_i541) &&
PATCH v2 1/1 omap: dma: Clear status registers on enable/disable irq.
Quoted 8 lines · Janusz Krzysztofik
Quoted 7 lines · On Tue, 15 May 2012 14:35:08 Oleg Matcovschi wrote:
Use
omap_disable_channel_irq()function instead of directly accessing CICR. Theomap_disable_chanel_irq()function clears pending interrupts and disables interrupt on channel.
Functions omap2_enable_irq_lch()/omap2_disable_irq_lch() clear interrupt status register.
Quoted 6 lines
Quoted 4 lines
Signed-off-by Oleg Matcovschi <[email protected]>---
v1 initial revision
v2 Review by Tony LindgrenMy Tested-by: on OMAP1 still valid for v2 if you care.
OK good to hear, will add that.
Regards,
Tony