aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap
diff options
context:
space:
mode:
authorNishanth Menon <nm@ti.com>2012-03-15 12:19:13 -0500
committerDmytro Kedrovskyi <x0169235@ti.com>2012-03-16 17:32:11 +0200
commit2185a3781e214dbaee2ae4142fe7b827e1c4eb36 (patch)
tree36e17e7db3182cde1511b66d18a963f1c6545d8d /arch/arm/plat-omap
parent4f066da1b1f479aba36472b26ed02e3540534f26 (diff)
downloadkernel_samsung_espresso10-2185a3781e214dbaee2ae4142fe7b827e1c4eb36.zip
kernel_samsung_espresso10-2185a3781e214dbaee2ae4142fe7b827e1c4eb36.tar.gz
kernel_samsung_espresso10-2185a3781e214dbaee2ae4142fe7b827e1c4eb36.tar.bz2
OMAP: clock: fix race in disable all clocks
clk_disable_unused is invoked when CONFIG_OMAP_RESET_CLOCKS=y. Since clk_disable_unused is called as lateinitcall, there can be more than a few workqueues executing off secondary CPU(s). The current code does the following: a) checks if clk is unused b) holds lock c) disables clk d) unlocks Between (a) and (b) being executed on CPU0, It is possible to have a driver executing on CPU1 which could do a get_sync->clk_get (and increase the use_count) of the clock which was just about to be disabled by clk_disable_unused. We ensure instead that the entire list traversal is protected by the lock allowing for parent child clock traversal which could be potentially be done by runtime operations to be safe as well. Change-Id: Iea5201233d89b8417576df4ed9026e1c05001596 Reported-by: Todd Poynor <toddpoynor@google.com> Signed-off-by: Nishanth Menon <nm@ti.com>
Diffstat (limited to 'arch/arm/plat-omap')
-rw-r--r--arch/arm/plat-omap/clock.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index e6a01f0..97c381f 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -643,6 +643,8 @@ static int __init clk_disable_unused(void)
return 0;
pr_info("clock: disabling unused clocks to save power\n");
+
+ spin_lock_irqsave(&clockfw_lock, flags);
list_for_each_entry(ck, &clocks, node) {
if (ck->ops == &clkops_null)
continue;
@@ -650,10 +652,9 @@ static int __init clk_disable_unused(void)
if (ck->usecount > 0 || !ck->enable_reg)
continue;
- spin_lock_irqsave(&clockfw_lock, flags);
arch_clock->clk_disable_unused(ck);
- spin_unlock_irqrestore(&clockfw_lock, flags);
}
+ spin_unlock_irqrestore(&clockfw_lock, flags);
return 0;
}