diff mbox series

[4.19,29/74] clk: qcom: regmap-mux: fix parent clock lookup

Message ID 20211213092931.784850569@linuxfoundation.org
State New
Headers show
Series None | expand

Commit Message

Greg Kroah-Hartman Dec. 13, 2021, 9:30 a.m. UTC
From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

commit 9a61f813fcc8d56d85fcf9ca6119cf2b5ac91dd5 upstream.

The function mux_get_parent() uses qcom_find_src_index() to find the
parent clock index, which is incorrect: qcom_find_src_index() uses src
enum for the lookup, while mux_get_parent() should use cfg field (which
corresponds to the register value). Add qcom_find_cfg_index() function
doing this kind of lookup and use it for mux parent lookup.

Fixes: df964016490b ("clk: qcom: add parent map for regmap mux")
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20211115233407.1046179-1-dmitry.baryshkov@linaro.org
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/clk/qcom/clk-regmap-mux.c |    2 +-
 drivers/clk/qcom/common.c         |   12 ++++++++++++
 drivers/clk/qcom/common.h         |    2 ++
 3 files changed, 15 insertions(+), 1 deletion(-)

Comments

Dmitry Baryshkov Dec. 15, 2021, 10:37 a.m. UTC | #1
On 15/12/2021 12:16, Pavel Machek wrote:
> Hi!
> 
>> The function mux_get_parent() uses qcom_find_src_index() to find the
>> parent clock index, which is incorrect: qcom_find_src_index() uses src
>> enum for the lookup, while mux_get_parent() should use cfg field (which
>> corresponds to the register value). Add qcom_find_cfg_index() function
>> doing this kind of lookup and use it for mux parent lookup.
> 
> This appears to have problems with error handling.
> 
>> +++ b/drivers/clk/qcom/clk-regmap-mux.c
>> @@ -36,7 +36,7 @@ static u8 mux_get_parent(struct clk_hw *
>>   	val &= mask;
>>   
>>   	if (mux->parent_map)
>> -		return qcom_find_src_index(hw, mux->parent_map, val);
>> +		return qcom_find_cfg_index(hw, mux->parent_map, val);
>>   
>>   	return val;
>>   }
> 
> So this returns u8.
> 
>> +int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map, u8 cfg)
>> +{
>> +	int i, num_parents = clk_hw_get_num_parents(hw);
>> +
>> +	for (i = 0; i < num_parents; i++)
>> +		if (cfg == map[i].cfg)
>> +			return i;
>> +
>> +	return -ENOENT;
>> +}
> 
> In case of error, -ENOENT will be cast to u8 in caller. I don't
> believe that is correct.

Unfortunately there is no way to return proper error code from 
clk_ops->get_parent() callback. However returning -ENOENT would 
translate to 254. Then clk_core_get_parent_by_index() would determine 
that there is no such parent and return NULL. A call to clk_set_parent 
would reparent the clock.

Returning some sensible default (e.g. 0) would be much worse, since then 
the clock subsystem would assume that the clock has correct parent. A 
call to clk_set_parent would always result in ops->set_parent() call, 
reparenting the clock correctly.

Most probably it would be correct to make ops->get_parent() return int 
instead of u8 (either an index or an -ERROR). However this was out of 
scope for this patch.
diff mbox series

Patch

--- a/drivers/clk/qcom/clk-regmap-mux.c
+++ b/drivers/clk/qcom/clk-regmap-mux.c
@@ -36,7 +36,7 @@  static u8 mux_get_parent(struct clk_hw *
 	val &= mask;
 
 	if (mux->parent_map)
-		return qcom_find_src_index(hw, mux->parent_map, val);
+		return qcom_find_cfg_index(hw, mux->parent_map, val);
 
 	return val;
 }
--- a/drivers/clk/qcom/common.c
+++ b/drivers/clk/qcom/common.c
@@ -69,6 +69,18 @@  int qcom_find_src_index(struct clk_hw *h
 }
 EXPORT_SYMBOL_GPL(qcom_find_src_index);
 
+int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map, u8 cfg)
+{
+	int i, num_parents = clk_hw_get_num_parents(hw);
+
+	for (i = 0; i < num_parents; i++)
+		if (cfg == map[i].cfg)
+			return i;
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(qcom_find_cfg_index);
+
 struct regmap *
 qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc)
 {
--- a/drivers/clk/qcom/common.h
+++ b/drivers/clk/qcom/common.h
@@ -47,6 +47,8 @@  extern void
 qcom_pll_set_fsm_mode(struct regmap *m, u32 reg, u8 bias_count, u8 lock_count);
 extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
 			       u8 src);
+extern int qcom_find_cfg_index(struct clk_hw *hw, const struct parent_map *map,
+			       u8 cfg);
 
 extern int qcom_cc_register_board_clk(struct device *dev, const char *path,
 				      const char *name, unsigned long rate);