From 1b93788f31d2f8cc4717c4665bb474053bfcd7d6 Mon Sep 17 00:00:00 2001 From: Mike Tipton Date: Mon, 3 Aug 2020 16:11:05 -0700 Subject: [PATCH] clk: qcom: clk-debug: Fix clk_measure files not being created The clk_measure debugfs files are created in the debug_init() callback and require the debugcc provider to have probed first and to have called clk_debug_measure_register(). However, the debugcc provider itself requires all other clock providers to have probed first in order to lookup their regmaps. So they are essentially interdependent. This has worked previously since when everything is built-in, all clock providers and debugcc generally probe prior to late_init. Prior to late_init, the debug_init() callbacks aren't called, so there are no interdependencies and it's only debugcc that depends on the other clock providers. At late_init, the debug_init() callbacks are called for any clocks already registered. After late-init, the debug_init() callbacks are called when each clock is registered, which introduces the interdependencies. If the probes are delayed to after late_init, then the clk_measure nodes aren't created in debug_init() due to the missing debugcc provider. The debug_init() callback is never called again and the files are never created. We can't rely on clock controllers being probed prior to late_init. Even if built-in, they can be delayed for various reasons as has been observed after recent kernel changes. If built as DLKMs, then they are guaranteed to be loaded after late_init. Update the code to always create the clk_measure files when debug_init() is called, even if the debugcc provider hasn't probed yet. If the clk_measure files are read prior to debugcc probe, then just return an error. Change-Id: Ia05a1dba86a84d70a03c8f05533ca9e1d1e18a90 Signed-off-by: Mike Tipton --- drivers/clk/qcom/clk-debug.c | 101 ++++++++++------------------------- 1 file changed, 28 insertions(+), 73 deletions(-) diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c index b27fe0b488e1..b503728923fc 100644 --- a/drivers/clk/qcom/clk-debug.c +++ b/drivers/clk/qcom/clk-debug.c @@ -254,8 +254,11 @@ static u32 get_mux_divs(struct clk_hw *mux) static int clk_debug_measure_get(void *data, u64 *val) { + struct clk_debug_mux *mux; struct clk_hw *hw = data; + struct clk_hw *parent; int ret = 0; + u32 regval; mutex_lock(&clk_debug_lock); @@ -265,89 +268,41 @@ static int clk_debug_measure_get(void *data, u64 *val) goto exit; } - enable_debug_clks(measure); - *val = clk_debug_mux_measure_rate(measure); + parent = clk_hw_get_parent(measure); + if (!parent) { + pr_err("Failed to get the debug mux's parent.\n"); + goto exit; + } - /* recursively calculate actual freq */ - *val *= get_mux_divs(measure); - disable_debug_clks(measure); + mux = to_clk_measure(parent); + + if ((clk_hw_get_flags(parent) & CLK_IS_MEASURE) && !mux->mux_sels) { + regmap_read(mux->regmap, mux->period_offset, ®val); + if (!regval) { + pr_err("Error reading mccc period register\n"); + goto exit; + } + *val = 1000000000000UL; + do_div(*val, regval); + } else { + enable_debug_clks(measure); + *val = clk_debug_mux_measure_rate(measure); + + /* recursively calculate actual freq */ + *val *= get_mux_divs(measure); + disable_debug_clks(measure); + } exit: mutex_unlock(&clk_debug_lock); return ret; } DEFINE_DEBUGFS_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get, - NULL, "%lld\n"); - -static int clk_debug_read_period(void *data, u64 *val) -{ - struct clk_hw *hw = data; - struct clk_hw *parent; - struct clk_debug_mux *mux; - int ret = 0; - u32 regval; - - mutex_lock(&clk_debug_lock); - - ret = clk_find_and_set_parent(measure, hw); - if (!ret) { - parent = clk_hw_get_parent(measure); - if (!parent) { - mutex_unlock(&clk_debug_lock); - return -EINVAL; - } - mux = to_clk_measure(parent); - regmap_read(mux->regmap, mux->period_offset, ®val); - if (!regval) { - pr_err("Error reading mccc period register, ret = %d\n", - ret); - mutex_unlock(&clk_debug_lock); - return 0; - } - *val = 1000000000000UL; - do_div(*val, regval); - } else { - pr_err("Failed to set the debug mux's parent.\n"); - } - - mutex_unlock(&clk_debug_lock); - return ret; -} - -DEFINE_SIMPLE_ATTRIBUTE(clk_read_period_fops, clk_debug_read_period, - NULL, "%lld\n"); + NULL, "%lld\n"); void clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry) { - int ret; - struct clk_hw *parent; - struct clk_debug_mux *meas; - struct clk_debug_mux *meas_parent; - - if (IS_ERR_OR_NULL(measure)) { - pr_err_once("Please check if `measure` clk is registered.\n"); - return; - } - - meas = to_clk_measure(measure); - ret = clk_find_and_set_parent(measure, hw); - if (ret) { - pr_debug("Unable to set %s as %s's parent, ret=%d\n", - clk_hw_get_name(hw), clk_hw_get_name(measure), ret); - return; - } - - parent = clk_hw_get_parent(measure); - if (!parent) - return; - meas_parent = to_clk_measure(parent); - - if (clk_hw_get_flags(parent) & CLK_IS_MEASURE && !meas_parent->mux_sels) - debugfs_create_file("clk_measure", 0444, dentry, hw, - &clk_read_period_fops); - else - debugfs_create_file("clk_measure", 0444, dentry, hw, - &clk_measure_fops); + debugfs_create_file("clk_measure", 0444, dentry, hw, &clk_measure_fops); } EXPORT_SYMBOL(clk_debug_measure_add);