From: "G, Manjunath Kondaiah" <manjugk@ti.com> 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 [thread overview] Message-ID: <1301322422-29886-3-git-send-email-manjugk@ti.com> (raw) In-Reply-To: <1301322422-29886-1-git-send-email-manjugk@ti.com> If two DMA users tries to set no mstandby mode 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. Initial patch is created by Adrian Hunter <adrian.hunter@nokia.com> https://patchwork.kernel.org/patch/366831/ Patch reworked to use API implemented at hwmod layer. Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com> Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> --- arch/arm/mach-omap1/dma.c | 1 + arch/arm/mach-omap2/dma.c | 16 +++++++++++++ arch/arm/plat-omap/dma.c | 40 +++++++++++++++++++-------------- arch/arm/plat-omap/include/plat/dma.h | 1 + 4 files changed, 41 insertions(+), 17 deletions(-) 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 <asm/system.h> #include <mach/hardware.h> -#include <plat/dma.h> +#include <plat/dma.h> +#include <plat/omap_device.h> #include <plat/tc.h> #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); -- 1.7.1
WARNING: multiple messages have this Message-ID (diff)
From: manjugk@ti.com (G, Manjunath Kondaiah) To: linux-arm-kernel@lists.infradead.org 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 [thread overview] Message-ID: <1301322422-29886-3-git-send-email-manjugk@ti.com> (raw) In-Reply-To: <1301322422-29886-1-git-send-email-manjugk@ti.com> If two DMA users tries to set no mstandby mode 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. Initial patch is created by Adrian Hunter <adrian.hunter@nokia.com> https://patchwork.kernel.org/patch/366831/ Patch reworked to use API implemented at hwmod layer. Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com> Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> --- arch/arm/mach-omap1/dma.c | 1 + arch/arm/mach-omap2/dma.c | 16 +++++++++++++ arch/arm/plat-omap/dma.c | 40 +++++++++++++++++++-------------- arch/arm/plat-omap/include/plat/dma.h | 1 + 4 files changed, 41 insertions(+), 17 deletions(-) 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 <asm/system.h> #include <mach/hardware.h> -#include <plat/dma.h> +#include <plat/dma.h> +#include <plat/omap_device.h> #include <plat/tc.h> #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); -- 1.7.1
next prev parent reply other threads:[~2011-03-28 14:32 UTC|newest] Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top 2011-03-28 14:26 [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support G, Manjunath Kondaiah 2011-03-28 14:26 ` G, Manjunath Kondaiah 2011-03-28 14:26 ` [PATCH v4 1/4] OMAP2+: PM: omap device: API's for handling mstandby mode G, Manjunath Kondaiah 2011-03-28 14:26 ` G, Manjunath Kondaiah 2011-05-06 20:24 ` Paul Walmsley 2011-05-06 20:24 ` Paul Walmsley 2011-03-28 14:27 ` G, Manjunath Kondaiah [this message] 2011-03-28 14:27 ` [PATCH v4 2/4] OMAP2+: DMA: prevent races while setting M idle mode to nostandby G, Manjunath Kondaiah 2011-03-28 14:27 ` [PATCH v4 3/4] OMAP: PM: DMA: Enable runtime pm G, Manjunath Kondaiah 2011-03-28 14:27 ` G, Manjunath Kondaiah 2011-03-28 14:27 ` [PATCH v4 4/4] OMAP: DMA: Fix: context restore during off mode G, Manjunath Kondaiah 2011-03-28 14:27 ` G, Manjunath Kondaiah 2011-04-07 0:45 ` [PATCH v4 0/4] OMAP: DMA: mstandby mode and runtime pm support G, Manjunath Kondaiah 2011-04-07 0:45 ` G, Manjunath Kondaiah 2011-04-19 11:05 ` Tony Lindgren 2011-04-19 11:05 ` Tony Lindgren 2011-04-28 13:56 ` Russell King - ARM Linux 2011-04-28 13:56 ` Russell King - ARM Linux
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1301322422-29886-3-git-send-email-manjugk@ti.com \ --to=manjugk@ti.com \ --cc=khilman@ti.com \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-omap@vger.kernel.org \ --cc=paul@pwsan.com \ --cc=tony@atomide.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.