From d1011cba02f2f931f0a95ea093cb25bc7738ff4d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Apr 2019 11:31:43 -0700 Subject: clkdev: Move clk creation outside of 'clocks_mutex' We don't need to hold the 'clocks_mutex' here when we're creating a clk pointer from a clk_lookup structure. Instead, we just need to make sure that the lookup doesn't go away while we dereference the lookup pointer to extract the clk_hw pointer out of it. Let's move things around slightly so that we have a new function to get the clk_hw out of the lookup with the right locking and then chain the two together for what used to be __clk_get_sys(). Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Tested-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/clkdev.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 6e787cc9e5b9..6f65bde696da 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -72,25 +72,26 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) return cl; } -static struct clk *__clk_get_sys(struct device *dev, const char *dev_id, - const char *con_id) +static struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id) { struct clk_lookup *cl; - struct clk *clk = NULL; + struct clk_hw *hw = ERR_PTR(-ENOENT); mutex_lock(&clocks_mutex); - cl = clk_find(dev_id, con_id); - if (!cl) - goto out; - - clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id); - if (IS_ERR(clk)) - cl = NULL; -out: + if (cl) + hw = cl->clk_hw; mutex_unlock(&clocks_mutex); - return cl ? clk : ERR_PTR(-ENOENT); + return hw; +} + +static struct clk *__clk_get_sys(struct device *dev, const char *dev_id, + const char *con_id) +{ + struct clk_hw *hw = clk_find_hw(dev_id, con_id); + + return clk_hw_create_clk(dev, hw, dev_id, con_id); } struct clk *clk_get_sys(const char *dev_id, const char *con_id) -- cgit v1.2.3 From fceaa7d8004339820a0026d163b20becc796d1af Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Apr 2019 11:31:44 -0700 Subject: clk: Prepare for clk registration API that uses DT nodes Split out the body of the clk_register() function so it can be shared between the different types of registration APIs (DT, device). Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Cc: Rob Herring Tested-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 96053a96fe2f..d27775a73e67 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3313,18 +3313,7 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, return clk; } -/** - * clk_register - allocate a new clock, register it and return an opaque cookie - * @dev: device that is registering this clock - * @hw: link to hardware-specific clock data - * - * clk_register is the primary interface for populating the clock tree with new - * clock nodes. It returns a pointer to the newly allocated struct clk which - * cannot be dereferenced by driver code but may be used in conjunction with the - * rest of the clock API. In the event of an error clk_register will return an - * error code; drivers must test for an error code after calling clk_register. - */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw) +static struct clk *__clk_register(struct device *dev, struct clk_hw *hw) { int i, ret; struct clk_core *core; @@ -3426,6 +3415,22 @@ fail_name: fail_out: return ERR_PTR(ret); } + +/** + * clk_register - allocate a new clock, register it and return an opaque cookie + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * clk_register is the primary interface for populating the clock tree with new + * clock nodes. It returns a pointer to the newly allocated struct clk which + * cannot be dereferenced by driver code but may be used in conjunction with the + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. + */ +struct clk *clk_register(struct device *dev, struct clk_hw *hw) +{ + return __clk_register(dev, hw); +} EXPORT_SYMBOL_GPL(clk_register); /** @@ -3440,7 +3445,7 @@ EXPORT_SYMBOL_GPL(clk_register); */ int clk_hw_register(struct device *dev, struct clk_hw *hw) { - return PTR_ERR_OR_ZERO(clk_register(dev, hw)); + return PTR_ERR_OR_ZERO(__clk_register(dev, hw)); } EXPORT_SYMBOL_GPL(clk_hw_register); -- cgit v1.2.3 From 89a5ddcc799d5d7dbcf6197b79dafc1dc9f997f5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Apr 2019 11:31:46 -0700 Subject: clk: Add of_clk_hw_register() API for early clk drivers In some circumstances drivers register clks early and don't have access to a struct device because the device model isn't initialized yet. Add an API to let drivers register clks associated with a struct device_node so that these drivers can participate in getting parent clks through DT. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Cc: Rob Herring Tested-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index d27775a73e67..ffa63ddcd408 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -45,6 +45,7 @@ struct clk_core { struct clk_hw *hw; struct module *owner; struct device *dev; + struct device_node *of_node; struct clk_core *parent; const char **parent_names; struct clk_core **parents; @@ -3313,7 +3314,8 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, return clk; } -static struct clk *__clk_register(struct device *dev, struct clk_hw *hw) +static struct clk * +__clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) { int i, ret; struct clk_core *core; @@ -3339,6 +3341,7 @@ static struct clk *__clk_register(struct device *dev, struct clk_hw *hw) if (dev && pm_runtime_enabled(dev)) core->rpm_enabled = true; core->dev = dev; + core->of_node = np; if (dev && dev->driver) core->owner = dev->driver->owner; core->hw = hw; @@ -3429,7 +3432,7 @@ fail_out: */ struct clk *clk_register(struct device *dev, struct clk_hw *hw) { - return __clk_register(dev, hw); + return __clk_register(dev, dev_of_node(dev), hw); } EXPORT_SYMBOL_GPL(clk_register); @@ -3445,10 +3448,27 @@ EXPORT_SYMBOL_GPL(clk_register); */ int clk_hw_register(struct device *dev, struct clk_hw *hw) { - return PTR_ERR_OR_ZERO(__clk_register(dev, hw)); + return PTR_ERR_OR_ZERO(__clk_register(dev, dev_of_node(dev), hw)); } EXPORT_SYMBOL_GPL(clk_hw_register); +/* + * of_clk_hw_register - register a clk_hw and return an error code + * @node: device_node of device that is registering this clock + * @hw: link to hardware-specific clock data + * + * of_clk_hw_register() is the primary interface for populating the clock tree + * with new clock nodes when a struct device is not available, but a struct + * device_node is. It returns an integer equal to zero indicating success or + * less than zero indicating failure. Drivers must test for an error code after + * calling of_clk_hw_register(). + */ +int of_clk_hw_register(struct device_node *node, struct clk_hw *hw) +{ + return PTR_ERR_OR_ZERO(__clk_register(NULL, node, hw)); +} +EXPORT_SYMBOL_GPL(of_clk_hw_register); + /* Free memory allocated for a clock. */ static void __clk_release(struct kref *ref) { -- cgit v1.2.3 From fc0c209c147f35ed2648adda09db39fcad89e334 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Apr 2019 11:31:47 -0700 Subject: clk: Allow parents to be specified without string names The common clk framework is lacking in ability to describe the clk topology without specifying strings for every possible parent-child link. There are a few drawbacks to the current approach: 1) String comparisons are used for everything, including describing topologies that are 'local' to a single clock controller. 2) clk providers (e.g. i2c clk drivers) need to create globally unique clk names to avoid collisions in the clk namespace, leading to awkward name generation code in various clk drivers. 3) DT bindings may not fully describe the clk topology and linkages between clk controllers because drivers can easily rely on globally unique strings to describe connections between clks. This leads to confusing DT bindings, complicated clk name generation code, and inefficient string comparisons during clk registration just so that the clk framework can detect the topology of the clk tree. Furthermore, some drivers call clk_get() and then __clk_get_name() to extract the globally unique clk name just so they can specify the parent of the clk they're registering. We have of_clk_parent_fill() but that mostly only works for single clks registered from a DT node, which isn't the norm. Let's simplify this all by introducing two new ways of specifying clk parents. The first method is an array of pointers to clk_hw structures corresponding to the parents at that index. This works for clks that are registered when we have access to all the clk_hw pointers for the parents. The second method is a mix of clk_hw pointers and strings of local and global parent clk names. If the .fw_name member of the map is set we'll look for that clk by performing a DT based lookup of the device the clk is registered with and the .name specified in the map. If that fails, we'll fallback to the .name member and perform a global clk name lookup like we've always done before. Using either one of these new methods is entirely optional. Existing drivers will continue to work, and they can migrate to this new approach as they see fit. Eventually, we'll want to get rid of the 'parent_names' array in struct clk_init_data and use one of these new methods instead. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Cc: Rob Herring Tested-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 262 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 200 insertions(+), 62 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ffa63ddcd408..ffd33b63c37e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -39,6 +39,13 @@ static LIST_HEAD(clk_notifier_list); /*** private data structures ***/ +struct clk_parent_map { + const struct clk_hw *hw; + struct clk_core *core; + const char *fw_name; + const char *name; +}; + struct clk_core { const char *name; const struct clk_ops *ops; @@ -47,8 +54,7 @@ struct clk_core { struct device *dev; struct device_node *of_node; struct clk_core *parent; - const char **parent_names; - struct clk_core **parents; + struct clk_parent_map *parents; u8 num_parents; u8 new_parent_index; unsigned long rate; @@ -317,17 +323,92 @@ static struct clk_core *clk_core_lookup(const char *name) return NULL; } +/** + * clk_core_get - Find the parent of a clk using a clock specifier in DT + * @core: clk to find parent of + * @name: name to search for in 'clock-names' of device providing clk + * + * 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 + * array is indexed and treated as a local name matching a string in the device + * node's 'clock-names' property. This allows clk providers to use their own + * namespace instead of looking for a globally unique parent string. + * + * For example the following DT snippet would allow a clock registered by the + * clock-controller@c001 that has a clk_init_data::parent_data array + * with 'xtal' in the 'name' member to find the clock provided by the + * clock-controller@f00abcd without needing to get the globally unique name of + * the xtal clk. + * + * parent: clock-controller@f00abcd { + * reg = <0xf00abcd 0xabcd>; + * #clock-cells = <0>; + * }; + * + * clock-controller@c001 { + * reg = <0xc001 0xf00d>; + * clocks = <&parent>; + * clock-names = "xtal"; + * #clock-cells = <1>; + * }; + * + * Returns: -ENOENT when the provider can't be found or the clk doesn't + * exist in the provider. -EINVAL when the name can't be found. NULL when the + * 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) +{ + struct clk_hw *hw; + struct device_node *np = core->of_node; + + if (!np) + return ERR_PTR(-ENOENT); + + /* TODO: Support clkdev clk_lookups */ + hw = of_clk_get_hw(np, -1, name); + if (IS_ERR_OR_NULL(hw)) + return ERR_CAST(hw); + + return hw->core; +} + +static void clk_core_fill_parent_index(struct clk_core *core, u8 index) +{ + struct clk_parent_map *entry = &core->parents[index]; + struct clk_core *parent = ERR_PTR(-ENOENT); + + if (entry->hw) { + parent = entry->hw->core; + /* + * We have a direct reference but it isn't registered yet? + * Orphan it and let clk_reparent() update the orphan status + * when the parent is registered. + */ + if (!parent) + parent = ERR_PTR(-EPROBE_DEFER); + } else { + if (entry->fw_name) + parent = clk_core_get(core, entry->fw_name); + if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT) + parent = clk_core_lookup(entry->name); + } + + /* Only cache it if it's not an error */ + if (!IS_ERR(parent)) + entry->core = parent; +} + static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core, u8 index) { - if (!core || index >= core->num_parents) + if (!core || index >= core->num_parents || !core->parents) return NULL; - if (!core->parents[index]) - core->parents[index] = - clk_core_lookup(core->parent_names[index]); + if (!core->parents[index].core) + clk_core_fill_parent_index(core, index); - return core->parents[index]; + return core->parents[index].core; } struct clk_hw * @@ -1520,15 +1601,15 @@ static int clk_fetch_parent_index(struct clk_core *core, return -EINVAL; for (i = 0; i < core->num_parents; i++) { - if (core->parents[i] == parent) + if (core->parents[i].core == parent) return i; - if (core->parents[i]) + if (core->parents[i].core) continue; /* Fallback to comparing globally unique names */ - if (!strcmp(parent->name, core->parent_names[i])) { - core->parents[i] = parent; + if (!strcmp(parent->name, core->parents[i].name)) { + core->parents[i].core = parent; return i; } } @@ -2294,6 +2375,7 @@ void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent) bool clk_has_parent(struct clk *clk, struct clk *parent) { struct clk_core *core, *parent_core; + int i; /* NULL clocks should be nops, so return success if either is NULL. */ if (!clk || !parent) @@ -2306,8 +2388,11 @@ bool clk_has_parent(struct clk *clk, struct clk *parent) if (core->parent == parent_core) return true; - return match_string(core->parent_names, core->num_parents, - parent_core->name) >= 0; + for (i = 0; i < core->num_parents; i++) + if (!strcmp(core->parents[i].name, parent_core->name)) + return true; + + return false; } EXPORT_SYMBOL_GPL(clk_has_parent); @@ -2890,9 +2975,9 @@ static int possible_parents_show(struct seq_file *s, void *data) int i; for (i = 0; i < core->num_parents - 1; i++) - seq_printf(s, "%s ", core->parent_names[i]); + seq_printf(s, "%s ", core->parents[i].name); - seq_printf(s, "%s\n", core->parent_names[i]); + seq_printf(s, "%s\n", core->parents[i].name); return 0; } @@ -3026,7 +3111,7 @@ static inline void clk_debug_unregister(struct clk_core *core) */ static int __clk_core_init(struct clk_core *core) { - int i, ret; + int ret; struct clk_core *orphan; struct hlist_node *tmp2; unsigned long rate; @@ -3080,12 +3165,6 @@ static int __clk_core_init(struct clk_core *core) goto out; } - /* throw a WARN if any entries in parent_names are NULL */ - for (i = 0; i < core->num_parents; i++) - WARN(!core->parent_names[i], - "%s: invalid NULL in %s's .parent_names\n", - __func__, core->name); - core->parent = __clk_init_parent(core); /* @@ -3314,10 +3393,102 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, return clk; } +static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist) +{ + const char *dst; + + if (!src) { + if (must_exist) + return -EINVAL; + return 0; + } + + *dst_p = dst = kstrdup_const(src, GFP_KERNEL); + if (!dst) + return -ENOMEM; + + return 0; +} + +static int clk_core_populate_parent_map(struct clk_core *core) +{ + const struct clk_init_data *init = core->hw->init; + u8 num_parents = init->num_parents; + const char * const *parent_names = init->parent_names; + const struct clk_hw **parent_hws = init->parent_hws; + const struct clk_parent_data *parent_data = init->parent_data; + int i, ret = 0; + struct clk_parent_map *parents, *parent; + + if (!num_parents) + return 0; + + /* + * Avoid unnecessary string look-ups of clk_core's possible parents by + * having a cache of names/clk_hw pointers to clk_core pointers. + */ + parents = kcalloc(num_parents, sizeof(*parents), GFP_KERNEL); + core->parents = parents; + if (!parents) + return -ENOMEM; + + /* Copy everything over because it might be __initdata */ + for (i = 0, parent = parents; i < num_parents; i++, parent++) { + if (parent_names) { + /* throw a WARN if any entries are NULL */ + WARN(!parent_names[i], + "%s: invalid NULL in %s's .parent_names\n", + __func__, core->name); + ret = clk_cpy_name(&parent->name, parent_names[i], + true); + } else if (parent_data) { + parent->hw = parent_data[i].hw; + ret = clk_cpy_name(&parent->fw_name, + parent_data[i].fw_name, false); + if (!ret) + ret = clk_cpy_name(&parent->name, + parent_data[i].name, + false); + } else if (parent_hws) { + parent->hw = parent_hws[i]; + } else { + ret = -EINVAL; + WARN(1, "Must specify parents if num_parents > 0\n"); + } + + if (ret) { + do { + kfree_const(parents[i].name); + kfree_const(parents[i].fw_name); + } while (--i >= 0); + kfree(parents); + + return ret; + } + } + + return 0; +} + +static void clk_core_free_parent_map(struct clk_core *core) +{ + int i = core->num_parents; + + if (!core->num_parents) + return; + + while (--i >= 0) { + kfree_const(core->parents[i].name); + kfree_const(core->parents[i].fw_name); + } + + kfree(core->parents); +} + static struct clk * __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) { - int i, ret; + int ret; struct clk_core *core; core = kzalloc(sizeof(*core), GFP_KERNEL); @@ -3351,33 +3522,9 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) core->max_rate = ULONG_MAX; hw->core = core; - /* allocate local copy in case parent_names is __initdata */ - core->parent_names = kcalloc(core->num_parents, sizeof(char *), - GFP_KERNEL); - - if (!core->parent_names) { - ret = -ENOMEM; - goto fail_parent_names; - } - - - /* copy each string name in case parent_names is __initdata */ - for (i = 0; i < core->num_parents; i++) { - core->parent_names[i] = kstrdup_const(hw->init->parent_names[i], - GFP_KERNEL); - if (!core->parent_names[i]) { - ret = -ENOMEM; - goto fail_parent_names_copy; - } - } - - /* avoid unnecessary string look-ups of clk_core's possible parents. */ - core->parents = kcalloc(core->num_parents, sizeof(*core->parents), - GFP_KERNEL); - if (!core->parents) { - ret = -ENOMEM; + ret = clk_core_populate_parent_map(core); + if (ret) goto fail_parents; - }; INIT_HLIST_HEAD(&core->clks); @@ -3388,7 +3535,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) hw->clk = alloc_clk(core, NULL, NULL); if (IS_ERR(hw->clk)) { ret = PTR_ERR(hw->clk); - goto fail_parents; + goto fail_create_clk; } clk_core_link_consumer(hw->core, hw->clk); @@ -3404,13 +3551,9 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) free_clk(hw->clk); hw->clk = NULL; +fail_create_clk: + clk_core_free_parent_map(core); fail_parents: - kfree(core->parents); -fail_parent_names_copy: - while (--i >= 0) - kfree_const(core->parent_names[i]); - kfree(core->parent_names); -fail_parent_names: fail_ops: kfree_const(core->name); fail_name: @@ -3473,15 +3616,10 @@ EXPORT_SYMBOL_GPL(of_clk_hw_register); static void __clk_release(struct kref *ref) { struct clk_core *core = container_of(ref, struct clk_core, ref); - int i = core->num_parents; lockdep_assert_held(&prepare_lock); - kfree(core->parents); - while (--i >= 0) - kfree_const(core->parent_names[i]); - - kfree(core->parent_names); + clk_core_free_parent_map(core); kfree_const(core->name); kfree(core); } -- cgit v1.2.3 From dde4eff47c82c52a72af333d9e55370eee6d95d6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Apr 2019 11:31:48 -0700 Subject: clk: Look for parents with clkdev based clk_lookups In addition to looking for DT based parents, support clkdev based clk_lookups. This should allow non-DT based clk drivers to participate in the parent lookup process. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Tested-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 27 ++++++++++++++++++--------- drivers/clk/clk.h | 2 ++ drivers/clk/clkdev.c | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ffd33b63c37e..50f5c73de688 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -324,14 +324,15 @@ static struct clk_core *clk_core_lookup(const char *name) } /** - * clk_core_get - Find the parent of a clk using a clock specifier in DT + * clk_core_get - Find the clk_core parent of a clk * @core: clk to find parent of - * @name: name to search for in 'clock-names' of device providing clk + * @name: name 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 * array is indexed and treated as a local name matching a string in the device - * node's 'clock-names' property. This allows clk providers to use their own + * node's 'clock-names' property or as the 'con_id' matching the device's + * dev_name() in a clk_lookup. This allows clk providers to use their own * namespace instead of looking for a globally unique parent string. * * For example the following DT snippet would allow a clock registered by the @@ -359,15 +360,23 @@ static struct clk_core *clk_core_lookup(const char *name) */ static struct clk_core *clk_core_get(struct clk_core *core, const char *name) { - struct clk_hw *hw; + struct clk_hw *hw = ERR_PTR(-ENOENT); + struct device *dev = core->dev; + const char *dev_id = dev ? dev_name(dev) : NULL; struct device_node *np = core->of_node; - if (!np) - return ERR_PTR(-ENOENT); + if (np) + hw = of_clk_get_hw(np, -1, name); - /* TODO: Support clkdev clk_lookups */ - hw = of_clk_get_hw(np, -1, name); - if (IS_ERR_OR_NULL(hw)) + /* + * If the DT search above couldn't find the provider or the provider + * didn't know about this clk, fallback to looking up via clkdev based + * clk_lookups + */ + if (PTR_ERR(hw) == -ENOENT) + hw = clk_find_hw(dev_id, name); + + if (IS_ERR(hw)) return ERR_CAST(hw); return hw->core; diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 553f531cc232..d8400d623b34 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -19,6 +19,8 @@ static inline struct clk_hw *of_clk_get_hw(struct device_node *np, } #endif +struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id); + #ifdef CONFIG_COMMON_CLK struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id, const char *con_id); diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 6f65bde696da..2afc8df8acff 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -72,7 +72,7 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) return cl; } -static struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id) +struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id) { struct clk_lookup *cl; struct clk_hw *hw = ERR_PTR(-ENOENT); -- cgit v1.2.3 From 601b6e93304a65f8f7c37168763ab9ba5b195ce5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Apr 2019 11:31:49 -0700 Subject: clk: Allow parents to be specified via clkspec index Some clk providers are simple DT nodes that only have a 'clocks' property without having an associated 'clock-names' property. In these cases, we want to let these clk providers point to their parent clks without having to dereference the 'clocks' property at probe time to figure out the parent's globally unique clk name. Let's add an 'index' property to the parent_data structure so that clk providers can indicate that their parent is a particular index in the 'clocks' DT property. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Tested-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 50f5c73de688..dc05cb339761 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -44,6 +44,7 @@ struct clk_parent_map { struct clk_core *core; const char *fw_name; const char *name; + int index; }; struct clk_core { @@ -326,7 +327,8 @@ 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 + * @name: name to search for (if string based) + * @index: index to use for search (if DT index based) * * 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 @@ -358,22 +360,23 @@ 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) +static struct clk_core *clk_core_get(struct clk_core *core, const char *name, + int index) { struct clk_hw *hw = ERR_PTR(-ENOENT); struct device *dev = core->dev; const char *dev_id = dev ? dev_name(dev) : NULL; struct device_node *np = core->of_node; - if (np) - hw = of_clk_get_hw(np, -1, name); + if (np && index >= 0) + hw = of_clk_get_hw(np, index, name); /* * If the DT search above couldn't find the provider or the provider * didn't know about this clk, fallback to looking up via clkdev based * clk_lookups */ - if (PTR_ERR(hw) == -ENOENT) + if (PTR_ERR(hw) == -ENOENT && name) hw = clk_find_hw(dev_id, name); if (IS_ERR(hw)) @@ -397,8 +400,7 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index) if (!parent) parent = ERR_PTR(-EPROBE_DEFER); } else { - if (entry->fw_name) - parent = clk_core_get(core, entry->fw_name); + parent = clk_core_get(core, entry->fw_name, entry->index); if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT) parent = clk_core_lookup(entry->name); } @@ -3443,6 +3445,7 @@ static int clk_core_populate_parent_map(struct clk_core *core) /* Copy everything over because it might be __initdata */ for (i = 0, parent = parents; i < num_parents; i++, parent++) { + parent->index = -1; if (parent_names) { /* throw a WARN if any entries are NULL */ WARN(!parent_names[i], @@ -3452,6 +3455,7 @@ static int clk_core_populate_parent_map(struct clk_core *core) true); } else if (parent_data) { parent->hw = parent_data[i].hw; + parent->index = parent_data[i].index; ret = clk_cpy_name(&parent->fw_name, parent_data[i].fw_name, false); if (!ret) -- cgit v1.2.3 From ecbf3f1795fda56122632c1d024cfd0d3f4fe353 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 12 Apr 2019 11:31:50 -0700 Subject: clk: fixed-factor: Let clk framework find parent Convert this driver to a more modern way of specifying parents now that we have a way to specify clk parents by DT index. This lets us nicely avoid a problem where a parent clk name isn't know because the parent clk hasn't been registered yet. Cc: Miquel Raynal Cc: Jerome Brunet Cc: Russell King Cc: Michael Turquette Cc: Jeffrey Hugo Cc: Chen-Yu Tsai Tested-by: Jeffrey Hugo Signed-off-by: Stephen Boyd --- drivers/clk/clk-fixed-factor.c | 53 ++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 241b3f8c61a9..5b09f2cdb7de 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -64,12 +64,14 @@ const struct clk_ops clk_fixed_factor_ops = { }; EXPORT_SYMBOL_GPL(clk_fixed_factor_ops); -struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - unsigned int mult, unsigned int div) +static struct clk_hw * +__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, + const char *name, const char *parent_name, int index, + unsigned long flags, unsigned int mult, unsigned int div) { struct clk_fixed_factor *fix; struct clk_init_data init; + struct clk_parent_data pdata = { .index = index }; struct clk_hw *hw; int ret; @@ -85,11 +87,17 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, init.name = name; init.ops = &clk_fixed_factor_ops; init.flags = flags | CLK_IS_BASIC; - init.parent_names = &parent_name; + if (parent_name) + init.parent_names = &parent_name; + else + init.parent_data = &pdata; init.num_parents = 1; hw = &fix->hw; - ret = clk_hw_register(dev, hw); + if (dev) + ret = clk_hw_register(dev, hw); + else + ret = of_clk_hw_register(np, hw); if (ret) { kfree(fix); hw = ERR_PTR(ret); @@ -97,6 +105,14 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, return hw; } + +struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, + const char *name, const char *parent_name, unsigned long flags, + unsigned int mult, unsigned int div) +{ + return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, -1, + flags, mult, div); +} EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor); struct clk *clk_register_fixed_factor(struct device *dev, const char *name, @@ -143,11 +159,10 @@ static const struct of_device_id set_rate_parent_matches[] = { { /* Sentinel */ }, }; -static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) +static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node) { - struct clk *clk; + struct clk_hw *hw; const char *clk_name = node->name; - const char *parent_name; unsigned long flags = 0; u32 div, mult; int ret; @@ -165,30 +180,28 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node) } of_property_read_string(node, "clock-output-names", &clk_name); - parent_name = of_clk_get_parent_name(node, 0); if (of_match_node(set_rate_parent_matches, node)) flags |= CLK_SET_RATE_PARENT; - clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags, - mult, div); - if (IS_ERR(clk)) { + hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, 0, + flags, mult, div); + if (IS_ERR(hw)) { /* - * If parent clock is not registered, registration would fail. * Clear OF_POPULATED flag so that clock registration can be * attempted again from probe function. */ of_node_clear_flag(node, OF_POPULATED); - return clk; + return ERR_CAST(hw); } - ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); + ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw); if (ret) { - clk_unregister(clk); + clk_hw_unregister_fixed_factor(hw); return ERR_PTR(ret); } - return clk; + return hw; } /** @@ -203,17 +216,17 @@ CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock", static int of_fixed_factor_clk_remove(struct platform_device *pdev) { - struct clk *clk = platform_get_drvdata(pdev); + struct clk_hw *clk = platform_get_drvdata(pdev); of_clk_del_provider(pdev->dev.of_node); - clk_unregister_fixed_factor(clk); + clk_hw_unregister_fixed_factor(clk); return 0; } static int of_fixed_factor_clk_probe(struct platform_device *pdev) { - struct clk *clk; + struct clk_hw *clk; /* * This function is not executed when of_fixed_factor_clk_setup -- cgit v1.2.3 From e4818d615b58f145ace70fefa43aeae8611b55a1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 23 Apr 2019 10:46:51 -0700 Subject: clk: fixed-factor: Initialize clk_init_data on stack This structure can be full of junk from the stack if we don't initialize it. The clk framework tests clk_init_data::parent_names for non-NULL and then considers that as the parent name pointer, but if it's full of junk then we'll try to deref a bad pointer and oops the system. Let's initialize the structure so that only clk_init_data::parent_names or clk_init_data::parent_data is set, and not both. Reported-by: "kernelci.org bot" Tested-by: Geert Uytterhoeven Tested-by: Tony Lindgren Fixes: ecbf3f1795fd ("clk: fixed-factor: Let clk framework find parent") Signed-off-by: Stephen Boyd --- drivers/clk/clk-fixed-factor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 5b09f2cdb7de..2d988a7585d5 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -70,7 +70,7 @@ __clk_hw_register_fixed_factor(struct device *dev, struct device_node *np, unsigned long flags, unsigned int mult, unsigned int div) { struct clk_fixed_factor *fix; - struct clk_init_data init; + struct clk_init_data init = { }; struct clk_parent_data pdata = { .index = index }; struct clk_hw *hw; int ret; -- cgit v1.2.3 From 1a079560b1450b72ff4e944bb9185e77633d74c4 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 30 Apr 2019 10:22:30 -0700 Subject: 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 Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers/clk') 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; } /* -- cgit v1.2.3