diff mbox series

[RFC,10/10] clk: Fix the ABBA locking issue with runtime PM subcalls

Message ID 20250326-cross-lock-dep-v1-10-3199e49e8652@bootlin.com (mailing list archive)
State Under Review
Headers show
Series Fix the ABBA locking situation between clk and runtime PM | expand

Commit Message

Miquel Raynal March 26, 2025, 6:26 p.m. UTC
The clock subsystem is calling runtime PM callbacks after having
acquired its own lock, which is in general problematic, especially
because when PM callbacks enter the power domain subsystem, we have the
following scenario:
mutex_lock(prepare_lock)
mutex_lock(genpd_lock)
But on the other side, devices may enable power domains, which
themselves might require clocks, forcing the following path:
mutex_lock(genpd_lock)
mutex_lock(prepare_lock)

The clk core has been modified in order to avoid the need for "late"
runtime PM calls (ie. inside the clk prepare_lock), so what remains to
be done is to simply remove these inner runtime calls.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/clk/clk.c | 31 +++++--------------------------
 1 file changed, 5 insertions(+), 26 deletions(-)
diff mbox series

Patch

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 26af3a134fa7b9d7f4a77ff473df7e79fd465789..652551860201f2d4ed606c55079dc4fb655d9fa0 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1961,10 +1961,9 @@  static unsigned long clk_recalc(struct clk_core *core,
 {
 	unsigned long rate = parent_rate;
 
-	if (core->ops->recalc_rate && !clk_pm_runtime_get(core)) {
+	if (core->ops->recalc_rate)
 		rate = core->ops->recalc_rate(core->hw, parent_rate);
-		clk_pm_runtime_put(core);
-	}
+
 	return rate;
 }
 
@@ -2458,9 +2457,6 @@  static void clk_change_rate(struct clk_core *core)
 		best_parent_rate = core->parent->rate;
 	}
 
-	if (clk_pm_runtime_get(core))
-		return;
-
 	if (core->flags & CLK_SET_RATE_UNGATE) {
 		clk_core_prepare(core);
 		clk_core_enable_lock(core);
@@ -2523,8 +2519,6 @@  static void clk_change_rate(struct clk_core *core)
 	/* handle the new child who might not be in core->children yet */
 	if (core->new_child)
 		clk_change_rate(core->new_child);
-
-	clk_pm_runtime_put(core);
 }
 
 static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
@@ -2562,7 +2556,6 @@  static int clk_core_set_rate_nolock(struct clk_core *core,
 {
 	struct clk_core *top, *fail_clk;
 	unsigned long rate;
-	int ret;
 
 	if (!core)
 		return 0;
@@ -2582,28 +2575,21 @@  static int clk_core_set_rate_nolock(struct clk_core *core,
 	if (!top)
 		return -EINVAL;
 
-	ret = clk_pm_runtime_get(core);
-	if (ret)
-		return ret;
-
 	/* notify that we are about to change rates */
 	fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
 	if (fail_clk) {
 		pr_debug("%s: failed to set %s rate\n", __func__,
 				fail_clk->name);
 		clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
-		ret = -EBUSY;
-		goto err;
+		return -EBUSY;
 	}
 
 	/* change the rates */
 	clk_change_rate(top);
 
 	core->req_rate = req_rate;
-err:
-	clk_pm_runtime_put(core);
 
-	return ret;
+	return 0;
 }
 
 /**
@@ -2953,16 +2939,12 @@  static int clk_core_set_parent_nolock(struct clk_core *core,
 		p_rate = parent->rate;
 	}
 
-	ret = clk_pm_runtime_get(core);
-	if (ret)
-		return ret;
-
 	/* propagate PRE_RATE_CHANGE notifications */
 	ret = __clk_speculate_rates(core, p_rate);
 
 	/* abort if a driver objects */
 	if (ret & NOTIFY_STOP_MASK)
-		goto runtime_put;
+		return ret;
 
 	/* do the re-parent */
 	ret = __clk_set_parent(core, parent, p_index);
@@ -2975,9 +2957,6 @@  static int clk_core_set_parent_nolock(struct clk_core *core,
 		__clk_recalc_accuracies(core);
 	}
 
-runtime_put:
-	clk_pm_runtime_put(core);
-
 	return ret;
 }