summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-06-27 14:36:58 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:47:30 -0800
commit4d04ca864ba7dfb6898f7c8065aa49d59b7eddde (patch)
tree0bf0def9a597dbd912ee9a5f922a94cd72e7bcfa
parentbcee00a3e0de825418c63d5340fbf794100610c3 (diff)
ARM: tegra: clock: Use bus lock to protect shared bus update
Protected shared bus update with bus lock - common for all shared bus users (update procedure was already covered by individual shared users locks, but it did not prevent concurrent access to shared rates list). Original-Change-Id: Ia0e6886265aff1f624802e0415fe8cecb887b507 Reviewed-on: http://git-master/r/39918 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R0e0ee997ce9347470e207910f7b4f6c42143717f
-rw-r--r--arch/arm/mach-tegra/clock.c10
-rw-r--r--arch/arm/mach-tegra/clock.h2
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c6
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c15
4 files changed, 28 insertions, 5 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 99fad6ebf034..94fe935ff810 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -644,6 +644,16 @@ int tegra_is_clk_enabled(struct clk *c)
}
EXPORT_SYMBOL(tegra_is_clk_enabled);
+int tegra_clk_shared_bus_update(struct clk *c)
+{
+ int ret = 0;
+
+ if (c->ops && c->ops->shared_bus_update)
+ ret = c->ops->shared_bus_update(c);
+
+ return ret;
+}
+
/* dvfs initialization may lower default maximum rate */
void __init tegra_init_max_rate(struct clk *c, unsigned long max_rate)
{
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 4e4adf1803e4..33325470a3d3 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -91,6 +91,7 @@ struct clk_ops {
long (*round_rate)(struct clk *, unsigned long);
int (*clk_cfg_ex)(struct clk *, enum tegra_clk_ex_param, u32);
void (*reset)(struct clk *, bool);
+ int (*shared_bus_update)(struct clk *);
};
struct clk_stats {
@@ -227,6 +228,7 @@ unsigned long clk_get_max_rate(struct clk *c);
unsigned long clk_get_min_rate(struct clk *c);
unsigned long clk_get_rate_locked(struct clk *c);
int clk_set_rate_locked(struct clk *c, unsigned long rate);
+int tegra_clk_shared_bus_update(struct clk *c);
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
int tegra_emc_set_rate(unsigned long rate);
long tegra_emc_round_rate(unsigned long rate);
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 3c5561e02e11..f5125eaeddcd 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -159,6 +159,8 @@ static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
#define MISC_GP_HIDREV 0x804
+static int tegra2_clk_shared_bus_update(struct clk *bus);
+
/*
* Some clocks share a register with other clocks. Any clock op that
* non-atomically modifies a register used by another clock must lock
@@ -525,6 +527,7 @@ static struct clk_ops tegra_virtual_sclk_ops = {
.init = tegra2_virtual_sclk_init,
.set_rate = tegra2_virtual_sclk_set_rate,
.round_rate = tegra2_virtual_sclk_round_rate,
+ .shared_bus_update = tegra2_clk_shared_bus_update,
};
/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
@@ -1280,6 +1283,7 @@ static struct clk_ops tegra_emc_clk_ops = {
.set_rate = &tegra2_emc_clk_set_rate,
.round_rate = &tegra2_emc_clk_round_rate,
.reset = &tegra2_periph_clk_reset,
+ .shared_bus_update = &tegra2_clk_shared_bus_update,
};
/* Clock doubler ops */
@@ -1452,7 +1456,7 @@ static struct clk_ops tegra_cdev_clk_ops = {
* enabled shared_bus_user clock, with a minimum value set by the
* shared bus.
*/
-static int tegra_clk_shared_bus_update(struct clk *bus)
+static int tegra2_clk_shared_bus_update(struct clk *bus)
{
struct clk *c;
unsigned long rate = bus->min_rate;
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 369bd7194a78..a530998e4034 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -295,6 +295,8 @@
/* FIXME: recommended safety delay after lock is detected */
#define PLL_POST_LOCK_DELAY 100
+static int tegra3_clk_shared_bus_update(struct clk *bus);
+
static bool detach_shared_bus;
module_param(detach_shared_bus, bool, 0644);
@@ -1162,6 +1164,7 @@ static struct clk_ops tegra_sbus_cmplx_ops = {
.init = tegra3_sbus_cmplx_init,
.set_rate = tegra3_sbus_cmplx_set_rate,
.round_rate = tegra3_sbus_cmplx_round_rate,
+ .shared_bus_update = tegra3_clk_shared_bus_update,
};
/* Blink output functions */
@@ -2359,6 +2362,7 @@ static struct clk_ops tegra_emc_clk_ops = {
.set_rate = &tegra3_emc_clk_set_rate,
.round_rate = &tegra3_emc_clk_round_rate,
.reset = &tegra3_periph_clk_reset,
+ .shared_bus_update = &tegra3_clk_shared_bus_update,
};
/* Clock doubler ops */
@@ -2641,6 +2645,7 @@ static struct clk_ops tegra_clk_cbus_ops = {
.enable = tegra3_clk_cbus_enable,
.set_rate = tegra3_clk_cbus_set_rate,
.round_rate = tegra3_clk_cbus_round_rate,
+ .shared_bus_update = tegra3_clk_shared_bus_update,
};
/* shared bus ops */
@@ -2651,7 +2656,7 @@ static struct clk_ops tegra_clk_cbus_ops = {
* enabled shared_bus_user clock, with a minimum value set by the
* shared bus.
*/
-static void tegra_clk_shared_bus_update(struct clk *bus)
+static int tegra3_clk_shared_bus_update(struct clk *bus)
{
struct clk *c;
unsigned long rate = bus->min_rate;
@@ -2659,7 +2664,7 @@ static void tegra_clk_shared_bus_update(struct clk *bus)
unsigned long ceiling = bus->max_rate;
if (detach_shared_bus)
- return;
+ return 0;
list_for_each_entry(c, &bus->shared_bus_list,
u.shared_bus_user.node) {
@@ -2683,8 +2688,10 @@ static void tegra_clk_shared_bus_update(struct clk *bus)
}
rate = min(max(rate, bw), ceiling);
- if (rate != clk_get_rate(bus))
- clk_set_rate(bus, rate);
+ if (rate == clk_get_rate_locked(bus))
+ return 0;
+
+ return clk_set_rate_locked(bus, rate);
};
static void tegra_clk_shared_bus_init(struct clk *c)