diff options
author | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2013-08-23 11:03:43 -0400 |
---|---|---|
committer | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2013-12-04 11:19:30 -0500 |
commit | d6782c263661abd6c7e8a375141d69fdc457f9e1 (patch) | |
tree | 4e43750d3ddbcbe1de3696e1bcbe50e3e982acc2 | |
parent | 4eadfc38c4d6e30775d3764f9a1a3098789d2acc (diff) |
clk: Provide not locked variant of of_clk_get_from_provider()
Add helper functions for the of_clk_providers list locking and
an unlocked variant of of_clk_get_from_provider().
These functions are intended to be used in the clkdev to avoid
race condition in the device tree based clock look up in clk_get().
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | drivers/clk/clk.c | 38 | ||||
-rw-r--r-- | drivers/clk/clk.h | 16 |
2 files changed, 46 insertions, 8 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 77fcd069c64a..c687dc8d0b64 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
23 | 23 | ||
24 | #include "clk.h" | ||
25 | |||
24 | static DEFINE_SPINLOCK(enable_lock); | 26 | static DEFINE_SPINLOCK(enable_lock); |
25 | static DEFINE_MUTEX(prepare_lock); | 27 | static DEFINE_MUTEX(prepare_lock); |
26 | 28 | ||
@@ -2111,7 +2113,18 @@ static const struct of_device_id __clk_of_table_sentinel | |||
2111 | __used __section(__clk_of_table_end); | 2113 | __used __section(__clk_of_table_end); |
2112 | 2114 | ||
2113 | static LIST_HEAD(of_clk_providers); | 2115 | static LIST_HEAD(of_clk_providers); |
2114 | static DEFINE_MUTEX(of_clk_lock); | 2116 | static DEFINE_MUTEX(of_clk_mutex); |
2117 | |||
2118 | /* of_clk_provider list locking helpers */ | ||
2119 | void of_clk_lock(void) | ||
2120 | { | ||
2121 | mutex_lock(&of_clk_mutex); | ||
2122 | } | ||
2123 | |||
2124 | void of_clk_unlock(void) | ||
2125 | { | ||
2126 | mutex_unlock(&of_clk_mutex); | ||
2127 | } | ||
2115 | 2128 | ||
2116 | struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, | 2129 | struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, |
2117 | void *data) | 2130 | void *data) |
@@ -2155,9 +2168,9 @@ int of_clk_add_provider(struct device_node *np, | |||
2155 | cp->data = data; | 2168 | cp->data = data; |
2156 | cp->get = clk_src_get; | 2169 | cp->get = clk_src_get; |
2157 | 2170 | ||
2158 | mutex_lock(&of_clk_lock); | 2171 | mutex_lock(&of_clk_mutex); |
2159 | list_add(&cp->link, &of_clk_providers); | 2172 | list_add(&cp->link, &of_clk_providers); |
2160 | mutex_unlock(&of_clk_lock); | 2173 | mutex_unlock(&of_clk_mutex); |
2161 | pr_debug("Added clock from %s\n", np->full_name); | 2174 | pr_debug("Added clock from %s\n", np->full_name); |
2162 | 2175 | ||
2163 | return 0; | 2176 | return 0; |
@@ -2172,7 +2185,7 @@ void of_clk_del_provider(struct device_node *np) | |||
2172 | { | 2185 | { |
2173 | struct of_clk_provider *cp; | 2186 | struct of_clk_provider *cp; |
2174 | 2187 | ||
2175 | mutex_lock(&of_clk_lock); | 2188 | mutex_lock(&of_clk_mutex); |
2176 | list_for_each_entry(cp, &of_clk_providers, link) { | 2189 | list_for_each_entry(cp, &of_clk_providers, link) { |
2177 | if (cp->node == np) { | 2190 | if (cp->node == np) { |
2178 | list_del(&cp->link); | 2191 | list_del(&cp->link); |
@@ -2181,24 +2194,33 @@ void of_clk_del_provider(struct device_node *np) | |||
2181 | break; | 2194 | break; |
2182 | } | 2195 | } |
2183 | } | 2196 | } |
2184 | mutex_unlock(&of_clk_lock); | 2197 | mutex_unlock(&of_clk_mutex); |
2185 | } | 2198 | } |
2186 | EXPORT_SYMBOL_GPL(of_clk_del_provider); | 2199 | EXPORT_SYMBOL_GPL(of_clk_del_provider); |
2187 | 2200 | ||
2188 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) | 2201 | struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec) |
2189 | { | 2202 | { |
2190 | struct of_clk_provider *provider; | 2203 | struct of_clk_provider *provider; |
2191 | struct clk *clk = ERR_PTR(-ENOENT); | 2204 | struct clk *clk = ERR_PTR(-ENOENT); |
2192 | 2205 | ||
2193 | /* Check if we have such a provider in our array */ | 2206 | /* Check if we have such a provider in our array */ |
2194 | mutex_lock(&of_clk_lock); | ||
2195 | list_for_each_entry(provider, &of_clk_providers, link) { | 2207 | list_for_each_entry(provider, &of_clk_providers, link) { |
2196 | if (provider->node == clkspec->np) | 2208 | if (provider->node == clkspec->np) |
2197 | clk = provider->get(clkspec, provider->data); | 2209 | clk = provider->get(clkspec, provider->data); |
2198 | if (!IS_ERR(clk)) | 2210 | if (!IS_ERR(clk)) |
2199 | break; | 2211 | break; |
2200 | } | 2212 | } |
2201 | mutex_unlock(&of_clk_lock); | 2213 | |
2214 | return clk; | ||
2215 | } | ||
2216 | |||
2217 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) | ||
2218 | { | ||
2219 | struct clk *clk; | ||
2220 | |||
2221 | mutex_lock(&of_clk_mutex); | ||
2222 | clk = __of_clk_get_from_provider(clkspec); | ||
2223 | mutex_unlock(&of_clk_mutex); | ||
2202 | 2224 | ||
2203 | return clk; | 2225 | return clk; |
2204 | } | 2226 | } |
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h new file mode 100644 index 000000000000..795cc9f0dac0 --- /dev/null +++ b/drivers/clk/clk.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * linux/drivers/clk/clk.h | ||
3 | * | ||
4 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. | ||
5 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) | ||
13 | struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec); | ||
14 | void of_clk_lock(void); | ||
15 | void of_clk_unlock(void); | ||
16 | #endif | ||