RE: [PATCH 1/2] OMAP: DMA: prevent races while setting M idle mode to nostandby

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter@xxxxxxxxx]
> 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 <adrian.hunter@xxxxxxxxx>
> 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 <adrian.hunter@xxxxxxxxx>
Acked-by: Santosh Shilimkar <santosh.shilimkar@xxxxxx>
> ---
>  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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux