summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNitin Garg <nitin.garg@freescale.com>2012-03-06 14:38:37 -0600
committerNitin Garg <nitin.garg@freescale.com>2012-03-06 14:38:37 -0600
commitafe74364c97e282f0c65875136a28134ba3c968c (patch)
treed513b46f26fe5d5f1ee9104d50c92f71ffc2e5ea
parent13f46ff721427ec9929e4fd8d8b18b5eb320cc86 (diff)
ENGR00175823: Pll1 Relock failure due to missing spinlock
PLL1 fails to relock since the pll lock check was wrong. Due to missing spinlock, a context switch could happen and we may fail the check right away between the getnstimeofday's. Signed-off-by: Nitin Garg <nitin.garg@freescale.com>
-rw-r--r--arch/arm/mach-mx5/clock.c4
-rw-r--r--arch/arm/plat-mxc/clock.c29
2 files changed, 19 insertions, 14 deletions
diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c
index e881854bcd2e..08e44a75dfa1 100644
--- a/arch/arm/mach-mx5/clock.c
+++ b/arch/arm/mach-mx5/clock.c
@@ -5252,10 +5252,10 @@ static int cpu_clk_set_op(int op)
getnstimeofday(&nstimeofday);
do {
getnstimeofday(&curtime);
- if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY)
- panic("pll1 relock failed\n");
stat = __raw_readl(pll1_base + MXC_PLL_DP_CTL) &
MXC_PLL_DP_CTL_LRF;
+ if (((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) && (!stat))
+ panic("pll1 relock failed\n");
} while (!stat);
reg = __raw_readl(MXC_CCM_CCSR);
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 1814cdc237b9..7cabd0229836 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -4,7 +4,7 @@
* Copyright (C) 2004 - 2005 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
* Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
- * Copyright 2007-2011 Freescale Semiconductor, Inc.
+ * Copyright 2007-2012 Freescale Semiconductor, Inc.
* Copyright 2008 Juergen Beisert, kernel@pengutronix.de
*
* This program is free software; you can redistribute it and/or
@@ -56,6 +56,7 @@ extern int low_freq_bus_used(void);
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
/*-------------------------------------------------------------------------
* Standard clock functions defined in include/linux/clk.h
@@ -70,8 +71,9 @@ static void __clk_disable(struct clk *clk)
if (!(--clk->usecount)) {
if (clk->disable)
clk->disable(clk);
- __clk_disable(clk->parent);
+
__clk_disable(clk->secondary);
+ __clk_disable(clk->parent);
}
}
@@ -95,7 +97,7 @@ static int __clk_enable(struct clk *clk)
*/
int clk_enable(struct clk *clk)
{
- /* unsigned long flags; */
+ unsigned long flags;
int ret = 0;
if (in_interrupt()) {
@@ -127,9 +129,9 @@ int clk_enable(struct clk *clk)
}
}
- mutex_lock(&clocks_mutex);
+ spin_lock_irqsave(&clockfw_lock, flags);
ret = __clk_enable(clk);
- mutex_unlock(&clocks_mutex);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
}
@@ -141,7 +143,7 @@ EXPORT_SYMBOL(clk_enable);
*/
void clk_disable(struct clk *clk)
{
- /* unsigned long flags; */
+ unsigned long flags;
if (in_interrupt()) {
printk(KERN_ERR " clk_disable cannot be called in an interrupt context\n");
@@ -152,9 +154,10 @@ void clk_disable(struct clk *clk)
if (clk == NULL || IS_ERR(clk))
return;
- mutex_lock(&clocks_mutex);
+ spin_lock_irqsave(&clockfw_lock, flags);
__clk_disable(clk);
- mutex_unlock(&clocks_mutex);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+
if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
&& (clk_get_usecount(clk) == 0)) {
if (low_freq_bus_used() && !low_bus_freq_mode)
@@ -221,14 +224,15 @@ EXPORT_SYMBOL(clk_round_rate);
*/
int clk_set_rate(struct clk *clk, unsigned long rate)
{
+ unsigned long flags;
int ret = -EINVAL;
if (clk == NULL || IS_ERR(clk) || clk->set_rate == NULL || rate == 0)
return ret;
- mutex_lock(&clocks_mutex);
+ spin_lock_irqsave(&clockfw_lock, flags);
ret = clk->set_rate(clk, rate);
- mutex_unlock(&clocks_mutex);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
return ret;
}
@@ -237,6 +241,7 @@ EXPORT_SYMBOL(clk_set_rate);
/* Set the clock's parent to another clock source */
int clk_set_parent(struct clk *clk, struct clk *parent)
{
+ unsigned long flags;
int ret = -EINVAL;
struct clk *old;
@@ -247,7 +252,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (clk->usecount)
clk_enable(parent);
- mutex_lock(&clocks_mutex);
+ spin_lock_irqsave(&clockfw_lock, flags);
ret = clk->set_parent(clk, parent);
if (ret == 0) {
old = clk->parent;
@@ -255,7 +260,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
} else {
old = parent;
}
- mutex_unlock(&clocks_mutex);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
if (clk->usecount)
clk_disable(old);