diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2011-07-22 15:03:04 +0530 |
---|---|---|
committer | Manish Tuteja <mtuteja@nvidia.com> | 2011-07-25 02:44:05 -0700 |
commit | caa12c3b3d1aac557599313be83fbd8715cc7694 (patch) | |
tree | 69055135b3d2201ff4718a27942c1caf9ba46aab | |
parent | 047c82473b70803b21566f43bbabe9b7bf7423be (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).
Reviewed-on: http://git-master/r/39918
(cherry picked from commit 09ca93ccf0c8400a876a23eef3cd771f2f4ac9d2)
Change-Id: Ie660fcb8c962712ceaa230a9dead684fcaf37d24
Reviewed-on: http://git-master/r/42589
Reviewed-by: Manish Tuteja <mtuteja@nvidia.com>
Tested-by: Manish Tuteja <mtuteja@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 25 | ||||
-rw-r--r-- | arch/arm/mach-tegra/clock.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 10 |
3 files changed, 31 insertions, 7 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 0a61e08dcb2e..2de6093fe2e0 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -347,15 +347,12 @@ struct clk *clk_get_parent(struct clk *c) } EXPORT_SYMBOL(clk_get_parent); -int clk_set_rate(struct clk *c, unsigned long rate) +int clk_set_rate_locked(struct clk *c, unsigned long rate) { int ret = 0; - unsigned long flags; unsigned long old_rate; long new_rate; - clk_lock_save(c, flags); - if (!c->ops || !c->ops->set_rate) { ret = -ENOSYS; goto out; @@ -391,6 +388,16 @@ int clk_set_rate(struct clk *c, unsigned long rate) ret = tegra_dvfs_set_rate(c, rate); out: + return ret; +} + +int clk_set_rate(struct clk *c, unsigned long rate) +{ + int ret; + unsigned long flags; + + clk_lock_save(c, flags); + ret = clk_set_rate_locked(c, rate); clk_unlock_restore(c, flags); return ret; } @@ -516,6 +523,16 @@ void tegra_periph_reset_assert(struct clk *c) } EXPORT_SYMBOL(tegra_periph_reset_assert); +void tegra_clk_shared_bus_update(struct clk *c) +{ + unsigned long flags; + + clk_lock_save(c, flags); + if (c->ops && c->ops->shared_bus_update) + c->ops->shared_bus_update(c); + clk_unlock_restore(c, flags); +} + void __init tegra_init_clock(void) { tegra2_init_clocks(); diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index 6a1c5ba96a8a..acbabaa94b60 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -68,6 +68,7 @@ struct clk_ops { int (*set_rate)(struct clk *, unsigned long); long (*round_rate)(struct clk *, unsigned long); void (*reset)(struct clk *, bool); + void (*shared_bus_update)(struct clk *); }; enum clk_state { @@ -177,6 +178,8 @@ int clk_reparent(struct clk *c, struct clk *parent); void tegra_clk_init_from_table(struct tegra_clk_init_table *table); void clk_set_cansleep(struct clk *c); unsigned long clk_get_rate_locked(struct clk *c); +int clk_set_rate_locked(struct clk *c, unsigned long rate); +void tegra_clk_shared_bus_update(struct clk *c); void tegra2_sdmmc_tap_delay(struct clk *c, int delay); #ifdef CONFIG_CPU_FREQ diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 2331b675b510..95b7a9cbc7a1 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -154,6 +154,8 @@ static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); +static void tegra2_clk_shared_bus_update(struct clk *bus); + /* * Some peripheral clocks share an enable bit, so refcount the enable bits * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U @@ -494,6 +496,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 @@ -1138,6 +1141,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 */ @@ -1299,7 +1303,7 @@ static struct clk_ops tegra_cdev_clk_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 void tegra2_clk_shared_bus_update(struct clk *bus) { struct clk *c; unsigned long rate = bus->min_rate; @@ -1310,8 +1314,8 @@ static void tegra_clk_shared_bus_update(struct clk *bus) rate = max(c->u.shared_bus_user.rate, rate); } - if (rate != clk_get_rate(bus)) - clk_set_rate(bus, rate); + if (rate != clk_get_rate_locked(bus)) + clk_set_rate_locked(bus, rate); }; static void tegra_clk_shared_bus_init(struct clk *c) |