summaryrefslogtreecommitdiffstats
path: root/drivers/clk/clk.c
diff options
context:
space:
mode:
authorStephen Boyd2019-04-30 19:22:30 +0200
committerStephen Boyd2019-05-03 19:38:01 +0200
commit1a079560b1450b72ff4e944bb9185e77633d74c4 (patch)
tree813133407b3a887e7525350ab5bed50848a10e59 /drivers/clk/clk.c
parentclk: fixed-factor: Initialize clk_init_data on stack (diff)
downloadkernel-qcow2-linux-1a079560b1450b72ff4e944bb9185e77633d74c4.tar.gz
kernel-qcow2-linux-1a079560b1450b72ff4e944bb9185e77633d74c4.tar.xz
kernel-qcow2-linux-1a079560b1450b72ff4e944bb9185e77633d74c4.zip
clk: Cache core in clk_fetch_parent_index() without names
If a clk has specified parents via clk_hw pointers it won't specify the globally unique names for the parents. Without the unique names, we can't fallback to comparing them against the name of the 'parent' pointer here. Therefore, do a pointer comparison against the clk_hw pointers too and cache the clk_core structure if they match. This fixes parent lookup code for clks that only specify clk_hw pointers and nothing else, like muxes that are purely inside a clk controller. Similarly, if the parent pointer isn't cached after trying to match clk_core or clk_hw pointers, lookup the pointer from DT or via clkdev lookups instead of relying purely on the globally unique clk name match. This should allow us to move away from having to specify global names for clk parents entirely. While we're in the area, add some comments so it's clearer what's going on. The if statements don't lend themselves to much clarity in their raw form. Fixes: fc0c209c147f ("clk: Allow parents to be specified without string names") Reported-by: Charles Keepax <ckeepax@opensource.cirrus.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Diffstat (limited to 'drivers/clk/clk.c')
-rw-r--r--drivers/clk/clk.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index dc05cb339761..dcb7e1cddd2d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -327,8 +327,7 @@ static struct clk_core *clk_core_lookup(const char *name)
/**
* clk_core_get - Find the clk_core parent of a clk
* @core: clk to find parent of
- * @name: name to search for (if string based)
- * @index: index to use for search (if DT index based)
+ * @p_index: parent index to search for
*
* This is the preferred method for clk providers to find the parent of a
* clk when that parent is external to the clk controller. The parent_names
@@ -360,9 +359,10 @@ static struct clk_core *clk_core_lookup(const char *name)
* provider knows about the clk but it isn't provided on this system.
* A valid clk_core pointer when the clk can be found in the provider.
*/
-static struct clk_core *clk_core_get(struct clk_core *core, const char *name,
- int index)
+static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
{
+ const char *name = core->parents[p_index].fw_name;
+ int index = core->parents[p_index].index;
struct clk_hw *hw = ERR_PTR(-ENOENT);
struct device *dev = core->dev;
const char *dev_id = dev ? dev_name(dev) : NULL;
@@ -400,7 +400,7 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
if (!parent)
parent = ERR_PTR(-EPROBE_DEFER);
} else {
- parent = clk_core_get(core, entry->fw_name, entry->index);
+ parent = clk_core_get(core, index);
if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT)
parent = clk_core_lookup(entry->name);
}
@@ -1612,20 +1612,37 @@ static int clk_fetch_parent_index(struct clk_core *core,
return -EINVAL;
for (i = 0; i < core->num_parents; i++) {
+ /* Found it first try! */
if (core->parents[i].core == parent)
return i;
+ /* Something else is here, so keep looking */
if (core->parents[i].core)
continue;
- /* Fallback to comparing globally unique names */
- if (!strcmp(parent->name, core->parents[i].name)) {
- core->parents[i].core = parent;
- return i;
+ /* Maybe core hasn't been cached but the hw is all we know? */
+ if (core->parents[i].hw) {
+ if (core->parents[i].hw == parent->hw)
+ break;
+
+ /* Didn't match, but we're expecting a clk_hw */
+ continue;
}
+
+ /* Maybe it hasn't been cached (clk_set_parent() path) */
+ if (parent == clk_core_get(core, i))
+ break;
+
+ /* Fallback to comparing globally unique names */
+ if (!strcmp(parent->name, core->parents[i].name))
+ break;
}
- return -EINVAL;
+ if (i == core->num_parents)
+ return -EINVAL;
+
+ core->parents[i].core = parent;
+ return i;
}
/*