As clocks are registered their parents are resolved and the parent_map is updated to cache the clk_core objects of each existing parent. But in the event of a clock being unregistered this cache will carry dangling pointers if not invalidated, so do this for all children of the clock being unregistered. Signed-off-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx> --- This resolves the issue seen where the DSI PLL (and it's provided clocks) is being registered and unregistered multiple times due to probe deferral. Marking it RFC because I don't fully understand the life of the clock yet. drivers/clk/clk.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index c0990703ce54..8cd1ad977c50 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2423,11 +2423,14 @@ bool clk_has_parent(struct clk *clk, struct clk *parent) EXPORT_SYMBOL_GPL(clk_has_parent); static int clk_core_set_parent_nolock(struct clk_core *core, - struct clk_core *parent) + struct clk_core *parent, + bool invalidate_parent) { + struct clk_core *old_parent = core->parent; int ret = 0; int p_index = 0; unsigned long p_rate = 0; + int i; lockdep_assert_held(&prepare_lock); @@ -2481,6 +2484,14 @@ static int clk_core_set_parent_nolock(struct clk_core *core, __clk_recalc_accuracies(core); } + /* invalidate the parent cache */ + if (!parent && invalidate_parent) { + for (i = 0; i < core->num_parents; i++) { + if (core->parents[i].core == old_parent) + core->parents[i].core = NULL; + } + } + runtime_put: clk_pm_runtime_put(core); @@ -2517,7 +2528,8 @@ int clk_set_parent(struct clk *clk, struct clk *parent) clk_core_rate_unprotect(clk->core); ret = clk_core_set_parent_nolock(clk->core, - parent ? parent->core : NULL); + parent ? parent->core : NULL, + false); if (clk->exclusive_count) clk_core_rate_protect(clk->core); @@ -3772,7 +3784,7 @@ void clk_unregister(struct clk *clk) /* Reparent all children to the orphan list. */ hlist_for_each_entry_safe(child, t, &clk->core->children, child_node) - clk_core_set_parent_nolock(child, NULL); + clk_core_set_parent_nolock(child, NULL, true); } hlist_del_init(&clk->core->child_node); -- 2.18.0