Skip to content

Commit 54baf56

Browse files
Mike Tiptonbebarino
authored andcommitted
clk: Don't parent clks until the parent is fully registered
Before commit fc0c209 ("clk: Allow parents to be specified without string names") child clks couldn't find their parent until the parent clk was added to a list in __clk_core_init(). After that commit, child clks can reference their parent clks directly via a clk_hw pointer, or they can lookup that clk_hw pointer via DT if the parent clk is registered with an OF clk provider. The common clk framework treats hw->core being non-NULL as "the clk is registered" per the logic within clk_core_fill_parent_index(): parent = entry->hw->core; /* * We have a direct reference but it isn't registered yet? * Orphan it and let clk_reparent() update the orphan status * when the parent is registered. */ if (!parent) Therefore we need to be extra careful to not set hw->core until the clk is fully registered with the clk framework. Otherwise we can get into a situation where a child finds a parent clk and we move the child clk off the orphan list when the parent isn't actually registered, wrecking our enable accounting and breaking critical clks. Consider the following scenario: CPU0 CPU1 ---- ---- struct clk_hw clkBad; struct clk_hw clkA; clkA.init.parent_hws = { &clkBad }; clk_hw_register(&clkA) clk_hw_register(&clkBad) ... __clk_register() hw->core = core ... __clk_register() __clk_core_init() clk_prepare_lock() __clk_init_parent() clk_core_get_parent_by_index() clk_core_fill_parent_index() if (entry->hw) { parent = entry->hw->core; At this point, 'parent' points to clkBad even though clkBad hasn't been fully registered yet. Ouch! A similar problem can happen if a clk controller registers orphan clks that are referenced in the DT node of another clk controller. Let's fix all this by only setting the hw->core pointer underneath the clk prepare lock in __clk_core_init(). This way we know that clk_core_fill_parent_index() can't see hw->core be non-NULL until the clk is fully registered. Fixes: fc0c209 ("clk: Allow parents to be specified without string names") Signed-off-by: Mike Tipton <[email protected]> Link: https://lore.kernel.org/r/[email protected] [[email protected]: Reword commit text, update comment] Signed-off-by: Stephen Boyd <[email protected]>
1 parent 2d4fcc5 commit 54baf56

File tree

1 file changed

+12
-3
lines changed

1 file changed

+12
-3
lines changed

drivers/clk/clk.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3418,6 +3418,14 @@ static int __clk_core_init(struct clk_core *core)
34183418

34193419
clk_prepare_lock();
34203420

3421+
/*
3422+
* Set hw->core after grabbing the prepare_lock to synchronize with
3423+
* callers of clk_core_fill_parent_index() where we treat hw->core
3424+
* being NULL as the clk not being registered yet. This is crucial so
3425+
* that clks aren't parented until their parent is fully registered.
3426+
*/
3427+
core->hw->core = core;
3428+
34213429
ret = clk_pm_runtime_get(core);
34223430
if (ret)
34233431
goto unlock;
@@ -3582,8 +3590,10 @@ static int __clk_core_init(struct clk_core *core)
35823590
out:
35833591
clk_pm_runtime_put(core);
35843592
unlock:
3585-
if (ret)
3593+
if (ret) {
35863594
hlist_del_init(&core->child_node);
3595+
core->hw->core = NULL;
3596+
}
35873597

35883598
clk_prepare_unlock();
35893599

@@ -3847,7 +3857,6 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
38473857
core->num_parents = init->num_parents;
38483858
core->min_rate = 0;
38493859
core->max_rate = ULONG_MAX;
3850-
hw->core = core;
38513860

38523861
ret = clk_core_populate_parent_map(core, init);
38533862
if (ret)
@@ -3865,7 +3874,7 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw)
38653874
goto fail_create_clk;
38663875
}
38673876

3868-
clk_core_link_consumer(hw->core, hw->clk);
3877+
clk_core_link_consumer(core, hw->clk);
38693878

38703879
ret = __clk_core_init(core);
38713880
if (!ret)

0 commit comments

Comments
 (0)