Skip to content

Commit 6306e0c

Browse files
saschahauerbebarino
authored andcommitted
clk: scmi: Handle case where child clocks are initialized before their parents
The SCMI clock driver currently assumes that parent clocks are always initialized before their children. However, this assumption can fail if a child clock is encountered before its parent during probe. This leads to an issue during initialization of the parent_data array: sclk->parent_data[i].hw = hws[sclk->info->parents[i]]; If the parent clock's hardware structure has not been initialized yet, this assignment results in invalid data. To resolve this, allocate all struct scmi_clk instances as a contiguous array at the beginning of the probe and populate the hws[] array upfront. This ensures that any parent referenced later is already initialized, regardless of the order in which clocks are processed. Note that we can no longer free individual scmi_clk instances if scmi_clk_ops_init() fails which shouldn't be a problem if the SCMI platform has proper per-agent clock discovery. Fixes: 65a8a3d ("clk: scmi: Add support for clock {set,get}_parent") Reviewed-by: [email protected] Reviewed-by: Cristian Marussi <[email protected]> Reviewed-by: Sudeep Holla <[email protected]> Signed-off-by: Sascha Hauer <[email protected]> Link: https://lore.kernel.org/r/20250612-clk-scmi-children-parent-fix-v3-1-7de52a27593d@pengutronix.de Signed-off-by: Stephen Boyd <[email protected]>
1 parent 19272b3 commit 6306e0c

File tree

1 file changed

+10
-8
lines changed

1 file changed

+10
-8
lines changed

drivers/clk/clk-scmi.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
404404
const struct scmi_handle *handle = sdev->handle;
405405
struct scmi_protocol_handle *ph;
406406
const struct clk_ops *scmi_clk_ops_db[SCMI_MAX_CLK_OPS] = {};
407+
struct scmi_clk *sclks;
407408

408409
if (!handle)
409410
return -ENODEV;
@@ -430,18 +431,21 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
430431
transport_is_atomic = handle->is_transport_atomic(handle,
431432
&atomic_threshold_us);
432433

434+
sclks = devm_kcalloc(dev, count, sizeof(*sclks), GFP_KERNEL);
435+
if (!sclks)
436+
return -ENOMEM;
437+
438+
for (idx = 0; idx < count; idx++)
439+
hws[idx] = &sclks[idx].hw;
440+
433441
for (idx = 0; idx < count; idx++) {
434-
struct scmi_clk *sclk;
442+
struct scmi_clk *sclk = &sclks[idx];
435443
const struct clk_ops *scmi_ops;
436444

437-
sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
438-
if (!sclk)
439-
return -ENOMEM;
440-
441445
sclk->info = scmi_proto_clk_ops->info_get(ph, idx);
442446
if (!sclk->info) {
443447
dev_dbg(dev, "invalid clock info for idx %d\n", idx);
444-
devm_kfree(dev, sclk);
448+
hws[idx] = NULL;
445449
continue;
446450
}
447451

@@ -479,13 +483,11 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
479483
if (err) {
480484
dev_err(dev, "failed to register clock %d\n", idx);
481485
devm_kfree(dev, sclk->parent_data);
482-
devm_kfree(dev, sclk);
483486
hws[idx] = NULL;
484487
} else {
485488
dev_dbg(dev, "Registered clock:%s%s\n",
486489
sclk->info->name,
487490
scmi_ops->enable ? " (atomic ops)" : "");
488-
hws[idx] = &sclk->hw;
489491
}
490492
}
491493

0 commit comments

Comments
 (0)