linux-clk.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] clk: forbit multiple adding of clock providers and fix false positive EPROBE_DEFER
@ 2016-07-19  9:21 Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 1/5] clk: add a helper function __of_clk_find_provider() Masahiro Yamada
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Masahiro Yamada @ 2016-07-19  9:21 UTC (permalink / raw)
  To: linux-clk; +Cc: Masahiro Yamada, Stephen Boyd, Michael Turquette, linux-kernel


I dropped a question mail around 10 days ago,
https://lkml.org/lkml/2016/7/8/627

but I did not get any reply.

At least, nobody stopped me from going with this fix,
so here is the series to fix it.



Masahiro Yamada (5):
  clk: add a helper function __of_clk_find_provider()
  clk: avoid adding clock provider multiple times for one node
  clk: refactor of_clk_del_provider()
  clk: fix false positive EPROBE_DEFER of
    __of_clk_get_hw_from_provider()
  clk: return -EINVAL if clock provider has no .get callback

 drivers/clk/clk.c | 77 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 51 insertions(+), 26 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/5] clk: add a helper function __of_clk_find_provider()
  2016-07-19  9:21 [PATCH 0/5] clk: forbit multiple adding of clock providers and fix false positive EPROBE_DEFER Masahiro Yamada
@ 2016-07-19  9:21 ` Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 2/5] clk: avoid adding clock provider multiple times for one node Masahiro Yamada
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Masahiro Yamada @ 2016-07-19  9:21 UTC (permalink / raw)
  To: linux-clk; +Cc: Masahiro Yamada, Stephen Boyd, Michael Turquette, linux-kernel

This helper is useful to find an OF clock provider registered for a
device node.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/clk/clk.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 484acc2..e8c79a7 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -3010,6 +3010,21 @@ of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
 EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get);
 
 /**
+ * __of_clk_find_provider - Find a clock provider associated with a device node
+ * @np: device node to obtain the clock provider for
+ */
+static struct of_clk_provider *__of_clk_find_provider(struct device_node *np)
+{
+	struct of_clk_provider *cp;
+
+	list_for_each_entry(cp, &of_clk_providers, link)
+		if (cp->node == np)
+			return cp;
+
+	return NULL;
+}
+
+/**
  * of_clk_add_provider() - Register a clock provider for a node
  * @np: Device node pointer associated with clock provider
  * @clk_src_get: callback for decoding clock
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] clk: avoid adding clock provider multiple times for one node
  2016-07-19  9:21 [PATCH 0/5] clk: forbit multiple adding of clock providers and fix false positive EPROBE_DEFER Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 1/5] clk: add a helper function __of_clk_find_provider() Masahiro Yamada
@ 2016-07-19  9:21 ` Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 3/5] clk: refactor of_clk_del_provider() Masahiro Yamada
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Masahiro Yamada @ 2016-07-19  9:21 UTC (permalink / raw)
  To: linux-clk; +Cc: Masahiro Yamada, Stephen Boyd, Michael Turquette, linux-kernel

It is insane to add multiple OF clock providers against one device
node.

Let of_clk_add(_hw)_provider() fail with -EEXIST if the given node
is already associated with an OF clock provider.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/clk/clk.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index e8c79a7..7832343 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -3038,15 +3038,24 @@ int of_clk_add_provider(struct device_node *np,
 	struct of_clk_provider *cp;
 	int ret;
 
+	mutex_lock(&of_clk_mutex);
+
+	cp = __of_clk_find_provider(np);
+	if (cp) {
+		mutex_unlock(&of_clk_mutex);
+		return -EEXIST;
+	}
+
 	cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
-	if (!cp)
+	if (!cp) {
+		mutex_unlock(&of_clk_mutex);
 		return -ENOMEM;
+	}
 
 	cp->node = of_node_get(np);
 	cp->data = data;
 	cp->get = clk_src_get;
 
-	mutex_lock(&of_clk_mutex);
 	list_add(&cp->link, &of_clk_providers);
 	mutex_unlock(&of_clk_mutex);
 	pr_debug("Added clock from %s\n", np->full_name);
@@ -3073,15 +3082,24 @@ int of_clk_add_hw_provider(struct device_node *np,
 	struct of_clk_provider *cp;
 	int ret;
 
+	mutex_lock(&of_clk_mutex);
+
+	cp = __of_clk_find_provider(np);
+	if (cp) {
+		mutex_unlock(&of_clk_mutex);
+		return -EEXIST;
+	}
+
 	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
-	if (!cp)
+	if (!cp) {
+		mutex_unlock(&of_clk_mutex);
 		return -ENOMEM;
+	}
 
 	cp->node = of_node_get(np);
 	cp->data = data;
 	cp->get_hw = get;
 
-	mutex_lock(&of_clk_mutex);
 	list_add(&cp->link, &of_clk_providers);
 	mutex_unlock(&of_clk_mutex);
 	pr_debug("Added clk_hw provider from %s\n", np->full_name);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] clk: refactor of_clk_del_provider()
  2016-07-19  9:21 [PATCH 0/5] clk: forbit multiple adding of clock providers and fix false positive EPROBE_DEFER Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 1/5] clk: add a helper function __of_clk_find_provider() Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 2/5] clk: avoid adding clock provider multiple times for one node Masahiro Yamada
@ 2016-07-19  9:21 ` Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 4/5] clk: fix false positive EPROBE_DEFER of __of_clk_get_hw_from_provider() Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 5/5] clk: return -EINVAL if clock provider has no .get callback Masahiro Yamada
  4 siblings, 0 replies; 6+ messages in thread
From: Masahiro Yamada @ 2016-07-19  9:21 UTC (permalink / raw)
  To: linux-clk; +Cc: Masahiro Yamada, Stephen Boyd, Michael Turquette, linux-kernel

Now, it is guaranteed that a single node does not appear twice in
the list of OF clock providers.  So, of_clk_del_provider() only
needs to free the first occurrence.  This can be implemented more
simply with __of_clk_find_provider().

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/clk/clk.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 7832343..60daf60 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -3121,13 +3121,11 @@ void of_clk_del_provider(struct device_node *np)
 	struct of_clk_provider *cp;
 
 	mutex_lock(&of_clk_mutex);
-	list_for_each_entry(cp, &of_clk_providers, link) {
-		if (cp->node == np) {
-			list_del(&cp->link);
-			of_node_put(cp->node);
-			kfree(cp);
-			break;
-		}
+	cp = __of_clk_find_provider(np);
+	if (cp) {
+		list_del(&cp->link);
+		of_node_put(cp->node);
+		kfree(cp);
 	}
 	mutex_unlock(&of_clk_mutex);
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] clk: fix false positive EPROBE_DEFER of __of_clk_get_hw_from_provider()
  2016-07-19  9:21 [PATCH 0/5] clk: forbit multiple adding of clock providers and fix false positive EPROBE_DEFER Masahiro Yamada
                   ` (2 preceding siblings ...)
  2016-07-19  9:21 ` [PATCH 3/5] clk: refactor of_clk_del_provider() Masahiro Yamada
@ 2016-07-19  9:21 ` Masahiro Yamada
  2016-07-19  9:21 ` [PATCH 5/5] clk: return -EINVAL if clock provider has no .get callback Masahiro Yamada
  4 siblings, 0 replies; 6+ messages in thread
From: Masahiro Yamada @ 2016-07-19  9:21 UTC (permalink / raw)
  To: linux-clk; +Cc: Masahiro Yamada, Stephen Boyd, Michael Turquette, linux-kernel

Currently, this function iterates over the whole list of OF clock
providers.  If the given node is found and __of_clk_get_hw_provider()
fails, it continues to search for the next node.  In the end, it will
reach the end of the list and return -EPROBE_DEFER.  This is odd.
An OF clock provider is already registered for the given node, so it
is not deferred probe at all.

Actually, I was hit by this case when a clock is queried with a too
large index against an already registered OF clock provider.  In this
case, of_clk_src_onecell_get() returns -EINVAL (this is correct), but
clk_get() returns -EPROBE_DEFER, so the driver is visited later,
where it never succeeds in getting the clock.

Another good thing is this function is much more readable now.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/clk/clk.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 60daf60..2207098 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -3156,25 +3156,19 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
 {
 	struct of_clk_provider *provider;
 	struct clk *clk = ERR_PTR(-EPROBE_DEFER);
-	struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
+	struct clk_hw *hw;
 
 	if (!clkspec)
 		return ERR_PTR(-EINVAL);
 
-	/* Check if we have such a provider in our array */
 	mutex_lock(&of_clk_mutex);
-	list_for_each_entry(provider, &of_clk_providers, link) {
-		if (provider->node == clkspec->np)
-			hw = __of_clk_get_hw_from_provider(provider, clkspec);
-		if (!IS_ERR(hw)) {
-			clk = __clk_create_clk(hw, dev_id, con_id);
-
-			if (!IS_ERR(clk) && !__clk_get(clk)) {
-				__clk_free_clk(clk);
-				clk = ERR_PTR(-ENOENT);
-			}
-
-			break;
+	provider = __of_clk_find_provider(clkspec->np);
+	if (provider) {
+		hw = __of_clk_get_hw_from_provider(provider, clkspec);
+		clk = __clk_create_clk(hw, dev_id, con_id);
+		if (!IS_ERR(clk) && !__clk_get(clk)) {
+			__clk_free_clk(clk);
+			clk = ERR_PTR(-ENOENT);
 		}
 	}
 	mutex_unlock(&of_clk_mutex);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] clk: return -EINVAL if clock provider has no .get callback
  2016-07-19  9:21 [PATCH 0/5] clk: forbit multiple adding of clock providers and fix false positive EPROBE_DEFER Masahiro Yamada
                   ` (3 preceding siblings ...)
  2016-07-19  9:21 ` [PATCH 4/5] clk: fix false positive EPROBE_DEFER of __of_clk_get_hw_from_provider() Masahiro Yamada
@ 2016-07-19  9:21 ` Masahiro Yamada
  4 siblings, 0 replies; 6+ messages in thread
From: Masahiro Yamada @ 2016-07-19  9:21 UTC (permalink / raw)
  To: linux-clk; +Cc: Masahiro Yamada, Stephen Boyd, Michael Turquette, linux-kernel

Currently, __of_clk_get_hw_from_provider() returns -EPROBE_DEFER
if neither .get_hw nor .get is registered for the given provider.
This means of_clk_add(_hw)_provider() has been already called for
the node in a wrong way; it is not deferred probing at all.  EINVAL
is a better fit for the case.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---

 drivers/clk/clk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 2207098..3004388 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -3136,7 +3136,7 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider,
 			      struct of_phandle_args *clkspec)
 {
 	struct clk *clk;
-	struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
+	struct clk_hw *hw = ERR_PTR(-EINVAL);
 
 	if (provider->get_hw) {
 		hw = provider->get_hw(clkspec, provider->data);
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-07-19  9:21 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-19  9:21 [PATCH 0/5] clk: forbit multiple adding of clock providers and fix false positive EPROBE_DEFER Masahiro Yamada
2016-07-19  9:21 ` [PATCH 1/5] clk: add a helper function __of_clk_find_provider() Masahiro Yamada
2016-07-19  9:21 ` [PATCH 2/5] clk: avoid adding clock provider multiple times for one node Masahiro Yamada
2016-07-19  9:21 ` [PATCH 3/5] clk: refactor of_clk_del_provider() Masahiro Yamada
2016-07-19  9:21 ` [PATCH 4/5] clk: fix false positive EPROBE_DEFER of __of_clk_get_hw_from_provider() Masahiro Yamada
2016-07-19  9:21 ` [PATCH 5/5] clk: return -EINVAL if clock provider has no .get callback Masahiro Yamada

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).