Skip to content

Commit 4f8c6ab

Browse files
committed
clk: Fix falling back to legacy parent string matching
Calls to clk_core_get() will return ERR_PTR(-EINVAL) if we've started migrating a clk driver to use the DT based style of specifying parents but we haven't made any DT updates yet. This happens when we pass a non-NULL value as the 'name' argument of of_parse_clkspec(). That function returns -EINVAL in such a situation, instead of -ENOENT like we expected. The return value comes back up to clk_core_fill_parent_index() which proceeds to skip calling clk_core_lookup() because the error pointer isn't equal to -ENOENT, it's -EINVAL. Furthermore, we blindly overwrite the error pointer returned by clk_core_get() with NULL when there isn't a legacy .name member specified in the parent map. This isn't too bad right now because we don't really care to differentiate NULL from an error, but in the future we should only try to do a legacy lookup if we know we might find something. This way DT lookups that fail don't try to lookup based on strings when there isn't any string to match, hiding the error from DT parsing. Fix both these problems so that clk provider drivers can use the new style of parent mapping without having to also update their DT at the same time. This patch is based on an earlier patch from Taniya Das which checked for -EINVAL in addition to -ENOENT return values from clk_core_get(). Fixes: 601b6e9 ("clk: Allow parents to be specified via clkspec index") Cc: Taniya Das <[email protected]> Cc: Jerome Brunet <[email protected]> Cc: Chen-Yu Tsai <[email protected]> Reported-by: Taniya Das <[email protected]> Signed-off-by: Stephen Boyd <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Tested-by: Taniya Das <[email protected]>
1 parent c7ec75e commit 4f8c6ab

File tree

1 file changed

+34
-12
lines changed

1 file changed

+34
-12
lines changed

drivers/clk/clk.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,25 @@ static struct clk_core *clk_core_lookup(const char *name)
324324
return NULL;
325325
}
326326

327+
#ifdef CONFIG_OF
328+
static int of_parse_clkspec(const struct device_node *np, int index,
329+
const char *name, struct of_phandle_args *out_args);
330+
static struct clk_hw *
331+
of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec);
332+
#else
333+
static inline int of_parse_clkspec(const struct device_node *np, int index,
334+
const char *name,
335+
struct of_phandle_args *out_args)
336+
{
337+
return -ENOENT;
338+
}
339+
static inline struct clk_hw *
340+
of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec)
341+
{
342+
return ERR_PTR(-ENOENT);
343+
}
344+
#endif
345+
327346
/**
328347
* clk_core_get - Find the clk_core parent of a clk
329348
* @core: clk to find parent of
@@ -355,8 +374,9 @@ static struct clk_core *clk_core_lookup(const char *name)
355374
* };
356375
*
357376
* Returns: -ENOENT when the provider can't be found or the clk doesn't
358-
* exist in the provider. -EINVAL when the name can't be found. NULL when the
359-
* provider knows about the clk but it isn't provided on this system.
377+
* exist in the provider or the name can't be found in the DT node or
378+
* in a clkdev lookup. NULL when the provider knows about the clk but it
379+
* isn't provided on this system.
360380
* A valid clk_core pointer when the clk can be found in the provider.
361381
*/
362382
static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
@@ -367,17 +387,19 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
367387
struct device *dev = core->dev;
368388
const char *dev_id = dev ? dev_name(dev) : NULL;
369389
struct device_node *np = core->of_node;
390+
struct of_phandle_args clkspec;
370391

371-
if (np && (name || index >= 0))
372-
hw = of_clk_get_hw(np, index, name);
373-
374-
/*
375-
* If the DT search above couldn't find the provider or the provider
376-
* didn't know about this clk, fallback to looking up via clkdev based
377-
* clk_lookups
378-
*/
379-
if (PTR_ERR(hw) == -ENOENT && name)
392+
if (np && (name || index >= 0) &&
393+
!of_parse_clkspec(np, index, name, &clkspec)) {
394+
hw = of_clk_get_hw_from_clkspec(&clkspec);
395+
of_node_put(clkspec.np);
396+
} else if (name) {
397+
/*
398+
* If the DT search above couldn't find the provider fallback to
399+
* looking up via clkdev based clk_lookups.
400+
*/
380401
hw = clk_find_hw(dev_id, name);
402+
}
381403

382404
if (IS_ERR(hw))
383405
return ERR_CAST(hw);
@@ -401,7 +423,7 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
401423
parent = ERR_PTR(-EPROBE_DEFER);
402424
} else {
403425
parent = clk_core_get(core, index);
404-
if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT)
426+
if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT && entry->name)
405427
parent = clk_core_lookup(entry->name);
406428
}
407429

0 commit comments

Comments
 (0)