> -----Original Message-----
> From: Adrian Hunter [mailto:[email protected]]
> Sent: Tuesday, November 30, 2010 6:54 PM
> To: Tony Lindgren
> Cc: Adrian Hunter; Manjunatha GK; Santosh Shilimkar; linux-omap Mailing
> List
> Subject: [PATCH 1/2] OMAP: DMA: prevent races while setting M idle mode
to
> nostandby
>
> From 8c0f4490d93b67326ff24f6ce1c7e925b08d96b3 Mon Sep 17 00:00:00 2001
> From: Adrian Hunter <[email protected]>
> Date: Mon, 22 Nov 2010 11:32:48 +0200
> Subject: [PATCH 1/2] OMAP: DMA: prevent races while setting M idle mode
to
> nostandby
>
> In a couple of OMAP errata cases, sDMA M idle mode must be
> set temporarily to nostandby. If two DMA users were to do
> that at the same time, a race condition would arise.
> Prevent that by using a spin lock and counting up/down the
> number of times nostandby is set/reset.
>
> Signed-off-by: Adrian Hunter <[email protected]>
Acked-by: Santosh Shilimkar <[email protected]>
> ---
> arch/arm/plat-omap/dma.c | 59
++++++++++++++++++++++++++++++++++-------
> ----
> 1 files changed, 44 insertions(+), 15 deletions(-)
>
> diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
> index a863f55..6158c99 100644
> --- a/arch/arm/plat-omap/dma.c
> +++ b/arch/arm/plat-omap/dma.c
> @@ -139,6 +139,9 @@ static spinlock_t dma_chan_lock;
> static struct omap_dma_lch *dma_chan;
> static void __iomem *omap_dma_base;
>
> +static u32 midlemode_saved;
> +static int midlemode_save_cnt;
> +
> static const u8 omap1_dma_irq[OMAP1_LOGICAL_DMA_CH_COUNT] = {
> INT_DMA_CH0_6, INT_DMA_CH1_7, INT_DMA_CH2_8, INT_DMA_CH3,
> INT_DMA_CH4, INT_DMA_CH5, INT_1610_DMA_CH6, INT_1610_DMA_CH7,
> @@ -1016,6 +1019,41 @@ void omap_start_dma(int lch)
> }
> EXPORT_SYMBOL(omap_start_dma);
>
> +static void midlemode_nostandby(void)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dma_chan_lock, flags);
> + if (!midlemode_save_cnt) {
> + u32 l;
> +
> + midlemode_saved = dma_read(OCP_SYSCONFIG);
> + l = midlemode_saved;
> + l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
> + l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
> + dma_write(l, OCP_SYSCONFIG);
> + }
> + midlemode_save_cnt += 1;
> + spin_unlock_irqrestore(&dma_chan_lock, flags);
> +}
> +
> +static void midlemode_restore(void)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dma_chan_lock, flags);
> + midlemode_save_cnt -= 1;
> + if (!midlemode_save_cnt) {
> + u32 l;
> +
> + l = dma_read(OCP_SYSCONFIG);
> + l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
> + l |= midlemode_saved & DMA_SYSCONFIG_MIDLEMODE_MASK;
> + dma_write(l, OCP_SYSCONFIG);
> + }
> + spin_unlock_irqrestore(&dma_chan_lock, flags);
> +}
> +
> void omap_stop_dma(int lch)
> {
> u32 l;
> @@ -1028,16 +1066,10 @@ void omap_stop_dma(int lch)
> /* OMAP3 Errata i541: sDMA FIFO draining does not finish */
> if (cpu_is_omap34xx() && (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
> int i = 0;
> - u32 sys_cf;
>
> /* Configure No-Standby */
> - l = dma_read(OCP_SYSCONFIG);
> - sys_cf = l;
> - l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
> - l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
> - dma_write(l , OCP_SYSCONFIG);
> + midlemode_nostandby();
>
> - l = dma_read(CCR(lch));
> l &= ~OMAP_DMA_CCR_EN;
> dma_write(l, CCR(lch));
>
> @@ -1053,7 +1085,7 @@ void omap_stop_dma(int lch)
> printk(KERN_ERR "DMA drain did not complete on "
> "lch %d\n", lch);
> /* Restore OCP_SYSCONFIG */
> - dma_write(sys_cf, OCP_SYSCONFIG);
> + midlemode_restore();
> } else {
> l &= ~OMAP_DMA_CCR_EN;
> dma_write(l, CCR(lch));
> @@ -1711,7 +1743,6 @@ int omap_stop_dma_chain_transfers(int chain_id)
> {
> int *channels;
> u32 l, i;
> - u32 sys_cf;
>
> /* Check for input params */
> if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) {
> @@ -1730,11 +1761,9 @@ int omap_stop_dma_chain_transfers(int chain_id)
> * DMA Errata:
> * Special programming model needed to disable DMA before end of
> block
> */
> - sys_cf = dma_read(OCP_SYSCONFIG);
> - l = sys_cf;
> - /* Middle mode reg set no Standby */
> - l &= ~((1 << 12)|(1 << 13));
> - dma_write(l, OCP_SYSCONFIG);
> +
> + /* M idle mode reg set no Standby */
> + midlemode_nostandby();
>
> for (i = 0; i < dma_linked_lch[chain_id].no_of_lchs_linked; i++) {
>
> @@ -1754,7 +1783,7 @@ int omap_stop_dma_chain_transfers(int chain_id)
> OMAP_DMA_CHAIN_QINIT(chain_id);
>
> /* Errata - put in the old value */
> - dma_write(sys_cf, OCP_SYSCONFIG);
> + midlemode_restore();
>
> return 0;
> }
> --
> 1.7.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html