Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b93788f authored by Mike Tipton's avatar Mike Tipton
Browse files

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: default avatarMike Tipton <mdtipton@codeaurora.org>
parent bd0cb901
Loading
Loading
Loading
Loading
+22 −67
Original line number Diff line number Diff line
@@ -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);

	/* 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;
		pr_err("Failed to get the debug mux's parent.\n");
		goto exit;
	}

	mux = to_clk_measure(parent);

	if ((clk_hw_get_flags(parent) & CLK_IS_MEASURE) && !mux->mux_sels) {
		regmap_read(mux->regmap, mux->period_offset, &regval);
		if (!regval) {
			pr_err("Error reading mccc period register, ret = %d\n",
			       ret);
			mutex_unlock(&clk_debug_lock);
			return 0;
			pr_err("Error reading mccc period register\n");
			goto exit;
		}
		*val = 1000000000000UL;
		do_div(*val, regval);
	} else {
		pr_err("Failed to set the debug mux's parent.\n");
	}
		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_SIMPLE_ATTRIBUTE(clk_read_period_fops, clk_debug_read_period,
DEFINE_DEBUGFS_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
			 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);