From patchwork Mon Mar 28 14:27:00 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: manjugk manjugk X-Patchwork-Id: 668541 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p2SEW8V0008304 for ; Mon, 28 Mar 2011 14:32:08 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754579Ab1C1OcH (ORCPT ); Mon, 28 Mar 2011 10:32:07 -0400 Received: from devils.ext.ti.com ([198.47.26.153]:60746 "EHLO devils.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754293Ab1C1OcF (ORCPT ); Mon, 28 Mar 2011 10:32:05 -0400 Received: from dbdp31.itg.ti.com ([172.24.170.98]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id p2SEVtCr024297 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Mon, 28 Mar 2011 09:31:58 -0500 Received: from ucmsshproxy.india.ext.ti.com (localhost [127.0.0.1]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with SMTP id p2SEVpqU003572; Mon, 28 Mar 2011 20:01:51 +0530 (IST) Received: from localhost (unknown [10.24.244.236]) by ucmsshproxy.india.ext.ti.com (Postfix) with ESMTP id 2581C158004; Mon, 28 Mar 2011 20:01:51 +0530 (IST) From: "G, Manjunath Kondaiah" To: linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: khilman@ti.com, paul@pwsan.com, tony@atomide.com Subject: [PATCH v4 2/4] OMAP2+: DMA: prevent races while setting M idle mode to nostandby Date: Mon, 28 Mar 2011 19:57:00 +0530 Message-Id: <1301322422-29886-3-git-send-email-manjugk@ti.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1301322422-29886-1-git-send-email-manjugk@ti.com> References: <1301322422-29886-1-git-send-email-manjugk@ti.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 28 Mar 2011 14:32:08 +0000 (UTC) diff --git a/arch/arm/mach-omap1/dma.c b/arch/arm/mach-omap1/dma.c index d855934..fa2d1b0 100644 --- a/arch/arm/mach-omap1/dma.c +++ b/arch/arm/mach-omap1/dma.c @@ -351,6 +351,7 @@ static int __init omap1_system_dma_init(void) p->dma_write = dma_write; p->dma_read = dma_read; p->disable_irq_lch = NULL; + p->midlemode = NULL; p->errata = configure_dma_errata(); diff --git a/arch/arm/mach-omap2/dma.c b/arch/arm/mach-omap2/dma.c index 34922b2..6e12e71 100644 --- a/arch/arm/mach-omap2/dma.c +++ b/arch/arm/mach-omap2/dma.c @@ -36,7 +36,9 @@ static u32 errata; static u8 dma_stride; +static u32 midlemode_save_cnt; +static struct platform_device *pdev; static struct omap_dma_dev_attr *d; static enum omap_reg_offsets dma_common_ch_start, dma_common_ch_end; @@ -117,6 +119,18 @@ static inline u32 dma_read(int reg, int lch) return val; } +static void midlemode_nostandby(bool nostandby) +{ + /* TODO: midlemode_save_cnt can be moved to hwmod layer? */ + if (nostandby) { + omap_device_require_no_mstandby(pdev); + midlemode_save_cnt += 1; + } else { + omap_device_release_no_mstandby(pdev); + midlemode_save_cnt -= 1; + } +} + static inline void omap2_disable_irq_lch(int lch) { u32 val; @@ -253,6 +267,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) p->clear_dma = omap2_clear_dma; p->dma_write = dma_write; p->dma_read = dma_read; + p->midlemode = midlemode_nostandby; p->clear_lch_regs = NULL; @@ -286,6 +301,7 @@ static int __init omap2_system_dma_init_dev(struct omap_hwmod *oh, void *unused) dev_err(&od->pdev.dev, "%s: kzalloc fail\n", __func__); return -ENOMEM; } + pdev = &od->pdev; return 0; } diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index 2ec3b5d..5af9bb2 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -38,8 +38,9 @@ #include #include -#include +#include +#include #include #undef DEBUG @@ -924,6 +925,7 @@ EXPORT_SYMBOL(omap_start_dma); void omap_stop_dma(int lch) { u32 l; + unsigned long flags; /* Disable all interrupts on the channel */ if (cpu_class_is_omap1()) @@ -933,14 +935,13 @@ void omap_stop_dma(int lch) if (IS_DMA_ERRATA(DMA_ERRATA_i541) && (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) { int i = 0; - u32 sys_cf; /* Configure No-Standby */ - l = p->dma_read(OCP_SYSCONFIG, lch); - sys_cf = l; - l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK; - l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE); - p->dma_write(l , OCP_SYSCONFIG, 0); + if (p->midlemode) { + spin_lock_irqsave(&dma_chan_lock, flags); + p->midlemode(true); + spin_unlock_irqrestore(&dma_chan_lock, flags); + } l = p->dma_read(CCR, lch); l &= ~OMAP_DMA_CCR_EN; @@ -958,7 +959,11 @@ void omap_stop_dma(int lch) printk(KERN_ERR "DMA drain did not complete on " "lch %d\n", lch); /* Restore OCP_SYSCONFIG */ - p->dma_write(sys_cf, OCP_SYSCONFIG, lch); + if (p->midlemode) { + spin_lock_irqsave(&dma_chan_lock, flags); + p->midlemode(false); + spin_unlock_irqrestore(&dma_chan_lock, flags); + } } else { l &= ~OMAP_DMA_CCR_EN; p->dma_write(l, CCR, lch); @@ -1610,7 +1615,7 @@ int omap_stop_dma_chain_transfers(int chain_id) { int *channels; u32 l, i; - u32 sys_cf = 0; + unsigned long flags; /* Check for input params */ if (unlikely((chain_id < 0 || chain_id >= dma_lch_count))) { @@ -1625,12 +1630,10 @@ int omap_stop_dma_chain_transfers(int chain_id) } channels = dma_linked_lch[chain_id].linked_dmach_q; - if (IS_DMA_ERRATA(DMA_ERRATA_i88)) { - sys_cf = p->dma_read(OCP_SYSCONFIG, 0); - l = sys_cf; - /* Middle mode reg set no Standby */ - l &= ~((1 << 12)|(1 << 13)); - p->dma_write(l, OCP_SYSCONFIG, 0); + if (IS_DMA_ERRATA(DMA_ERRATA_i88) && p->midlemode) { + spin_lock_irqsave(&dma_chan_lock, flags); + p->midlemode(true); + spin_unlock_irqrestore(&dma_chan_lock, flags); } for (i = 0; i < dma_linked_lch[chain_id].no_of_lchs_linked; i++) { @@ -1650,8 +1653,11 @@ int omap_stop_dma_chain_transfers(int chain_id) /* Reset the Queue pointers */ OMAP_DMA_CHAIN_QINIT(chain_id); - if (IS_DMA_ERRATA(DMA_ERRATA_i88)) - p->dma_write(sys_cf, OCP_SYSCONFIG, 0); + if (IS_DMA_ERRATA(DMA_ERRATA_i88 && p->midlemode)) { + spin_lock_irqsave(&dma_chan_lock, flags); + p->midlemode(false); + spin_unlock_irqrestore(&dma_chan_lock, flags); + } return 0; } diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h index d1c916f..b20dc5e 100644 --- a/arch/arm/plat-omap/include/plat/dma.h +++ b/arch/arm/plat-omap/include/plat/dma.h @@ -435,6 +435,7 @@ struct omap_system_dma_plat_info { void (*clear_dma)(int lch); void (*dma_write)(u32 val, int reg, int lch); u32 (*dma_read)(int reg, int lch); + void (*midlemode)(bool nostandby); }; extern void omap_set_dma_priority(int lch, int dst_port, int priority);