* [PATCH v3 01/15] clk: scmi: Fix clock rate rounding
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 02/15] firmware: arm_scmi: Add clock determine_rate operation Cristian Marussi
` (14 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Michael Turquette, Stephen Boyd
While the do_div() helper used for rounding expects its divisor argument
to be a 32bits quantity, the currently provided divisor parameter is a
64bit value that, as a consequence, is silently truncated and a possible
source of bugs.
Fix by using the proper div64_ul helper.
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: linux-clk@vger.kernel.org
Fixes: 7a8655e19bdb ("clk: scmi: Fix the rounding of clock rate")
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
drivers/clk/clk-scmi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index 6b286ea6f121..b6a12f3bc123 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -10,9 +10,9 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/scmi_protocol.h>
-#include <asm/div64.h>
#define NOT_ATOMIC false
#define ATOMIC true
@@ -83,7 +83,7 @@ static int scmi_clk_determine_rate(struct clk_hw *hw,
ftmp = req->rate - fmin;
ftmp += clk->info->range.step_size - 1; /* to round up */
- do_div(ftmp, clk->info->range.step_size);
+ ftmp = div64_ul(ftmp, clk->info->range.step_size);
req->rate = ftmp * clk->info->range.step_size + fmin;
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 02/15] firmware: arm_scmi: Add clock determine_rate operation
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 01/15] clk: scmi: Fix clock rate rounding Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 03/15] clk: scmi: Use new determine_rate clock operation Cristian Marussi
` (13 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi
Add a clock operation to help determining the effective rate, closest to
the required one, that a specific clock can support.
Calculation is currently performed kernel side and the logic is taken
directly from the SCMI Clock driver: embedding the determinate rate logic
in the protocol layer enables simplifications in the SCMI Clock protocol
interface and will more easily accommodate further evolutions where such
determine_rate logic into is optionally delegated to the platform SCMI
server.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v1 --> v2
- use the fixed rounding algo using div64_ul
Spoiler alert next SCMI spec will most probably include a new
CLOCK_DETERMINE_RATE command to delegate to the platform such calculations,
so this clock proto_ops will be needed anyway sooner or later
---
drivers/firmware/arm_scmi/clock.c | 42 +++++++++++++++++++++++++++++++
include/linux/scmi_protocol.h | 6 +++++
2 files changed, 48 insertions(+)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index ab36871650a1..54b55517b759 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -5,6 +5,7 @@
* Copyright (C) 2018-2022 ARM Ltd.
*/
+#include <linux/math64.h>
#include <linux/module.h>
#include <linux/limits.h>
#include <linux/sort.h>
@@ -624,6 +625,46 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
return ret;
}
+static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
+ u32 clk_id, unsigned long *rate)
+{
+ u64 fmin, fmax, ftmp;
+ struct scmi_clock_info *clk;
+ struct clock_info *ci = ph->get_priv(ph);
+
+ if (!rate)
+ return -EINVAL;
+
+ clk = scmi_clock_domain_lookup(ci, clk_id);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ /*
+ * If we can't figure out what rate it will be, so just return the
+ * rate back to the caller.
+ */
+ if (clk->rate_discrete)
+ return 0;
+
+ fmin = clk->range.min_rate;
+ fmax = clk->range.max_rate;
+ if (*rate <= fmin) {
+ *rate = fmin;
+ return 0;
+ } else if (*rate >= fmax) {
+ *rate = fmax;
+ return 0;
+ }
+
+ ftmp = *rate - fmin;
+ ftmp += clk->range.step_size - 1; /* to round up */
+ ftmp = div64_ul(ftmp, clk->range.step_size);
+
+ *rate = ftmp * clk->range.step_size + fmin;
+
+ return 0;
+}
+
static int
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
enum clk_state state,
@@ -936,6 +977,7 @@ static const struct scmi_clk_proto_ops clk_proto_ops = {
.info_get = scmi_clock_info_get,
.rate_get = scmi_clock_rate_get,
.rate_set = scmi_clock_rate_set,
+ .determine_rate = scmi_clock_determine_rate,
.enable = scmi_clock_enable,
.disable = scmi_clock_disable,
.state_get = scmi_clock_state_get,
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index aafaac1496b0..28579c145045 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -91,6 +91,10 @@ enum scmi_clock_oem_config {
* @info_get: get the information of the specified clock
* @rate_get: request the current clock rate of a clock
* @rate_set: set the clock rate of a clock
+ * @determine_rate: determine the effective rate that can be supported by a
+ * clock calculating the closest allowed rate.
+ * Note that @rate is an input/output parameter used both to
+ * describe the requested rate and report the closest match
* @enable: enables the specified clock
* @disable: disables the specified clock
* @state_get: get the status of the specified clock
@@ -108,6 +112,8 @@ struct scmi_clk_proto_ops {
u64 *rate);
int (*rate_set)(const struct scmi_protocol_handle *ph, u32 clk_id,
u64 rate);
+ int (*determine_rate)(const struct scmi_protocol_handle *ph, u32 clk_id,
+ unsigned long *rate);
int (*enable)(const struct scmi_protocol_handle *ph, u32 clk_id,
bool atomic);
int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id,
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 03/15] clk: scmi: Use new determine_rate clock operation
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 01/15] clk: scmi: Fix clock rate rounding Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 02/15] firmware: arm_scmi: Add clock determine_rate operation Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:33 ` Brian Masney
2026-04-28 20:15 ` [PATCH v3 04/15] firmware: arm_scmi: Simplify clock rates exposed interface Cristian Marussi
` (12 subsequent siblings)
15 siblings, 1 reply; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Brian Masney, Michael Turquette, Stephen Boyd
Use the Clock protocol layer determine_rate logic to calculate the closest
rate that can be supported by a specific clock.
No functional change.
Cc: Brian Masney <bmasney@redhat.com>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: linux-clk@vger.kernel.org
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
@brian: I'd modify further this clk-scmi driver, with a patch on top of
this series, to properly use your new CLK_ROUNDING_NOOP flag once your
series AND another (already reviewed) series on clk-scmi from Peng are in.
---
drivers/clk/clk-scmi.c | 31 ++++++-------------------------
1 file changed, 6 insertions(+), 25 deletions(-)
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index b6a12f3bc123..c223e4ef1dd1 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -10,7 +10,6 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of.h>
-#include <linux/math64.h>
#include <linux/module.h>
#include <linux/scmi_protocol.h>
@@ -57,35 +56,17 @@ static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
static int scmi_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
- u64 fmin, fmax, ftmp;
+ int ret;
struct scmi_clk *clk = to_scmi_clk(hw);
/*
- * We can't figure out what rate it will be, so just return the
- * rate back to the caller. scmi_clk_recalc_rate() will be called
- * after the rate is set and we'll know what rate the clock is
+ * If we could not get a better rate scmi_clk_recalc_rate() will be
+ * called after the rate is set and we'll know what rate the clock is
* running at then.
*/
- if (clk->info->rate_discrete)
- return 0;
-
- fmin = clk->info->range.min_rate;
- fmax = clk->info->range.max_rate;
- if (req->rate <= fmin) {
- req->rate = fmin;
-
- return 0;
- } else if (req->rate >= fmax) {
- req->rate = fmax;
-
- return 0;
- }
-
- ftmp = req->rate - fmin;
- ftmp += clk->info->range.step_size - 1; /* to round up */
- ftmp = div64_ul(ftmp, clk->info->range.step_size);
-
- req->rate = ftmp * clk->info->range.step_size + fmin;
+ ret = scmi_proto_clk_ops->determine_rate(clk->ph, clk->id, &req->rate);
+ if (ret)
+ return ret;
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v3 03/15] clk: scmi: Use new determine_rate clock operation
2026-04-28 20:15 ` [PATCH v3 03/15] clk: scmi: Use new determine_rate clock operation Cristian Marussi
@ 2026-04-28 20:33 ` Brian Masney
2026-04-28 22:20 ` Cristian Marussi
0 siblings, 1 reply; 22+ messages in thread
From: Brian Masney @ 2026-04-28 20:33 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc, sudeep.holla, philip.radford, james.quinlan,
f.fainelli, vincent.guittot, etienne.carriere, peng.fan,
michal.simek, geert+renesas, kuninori.morimoto.gx,
marek.vasut+renesas, Michael Turquette, Stephen Boyd
Hi Cristian,
On Tue, Apr 28, 2026 at 09:15:10PM +0100, Cristian Marussi wrote:
> Use the Clock protocol layer determine_rate logic to calculate the closest
> rate that can be supported by a specific clock.
>
> No functional change.
>
> Cc: Brian Masney <bmasney@redhat.com>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Cc: Stephen Boyd <sboyd@kernel.org>
> Cc: linux-clk@vger.kernel.org
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> ---
> @brian: I'd modify further this clk-scmi driver, with a patch on top of
> this series, to properly use your new CLK_ROUNDING_NOOP flag once your
> series AND another (already reviewed) series on clk-scmi from Peng are in.
I don't know if Stephen is going to pick up my CLK_ROUNDING_NOOP series.
We talked about it in person at LPC in Tokyo, and he was the one that
suggested the flag rather than a new shared noop function. However he
didn't pick it up last development cycle.
I would recommend NOT basing on that series of mine to reduce
dependencies, and so that your stuff doesn't get held up by series.
Brian
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH v3 03/15] clk: scmi: Use new determine_rate clock operation
2026-04-28 20:33 ` Brian Masney
@ 2026-04-28 22:20 ` Cristian Marussi
0 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 22:20 UTC (permalink / raw)
To: Brian Masney
Cc: Cristian Marussi, linux-kernel, linux-arm-kernel, arm-scmi,
linux-clk, linux-renesas-soc, sudeep.holla, philip.radford,
james.quinlan, f.fainelli, vincent.guittot, etienne.carriere,
peng.fan, michal.simek, geert+renesas, kuninori.morimoto.gx,
marek.vasut+renesas, Michael Turquette, Stephen Boyd
On Tue, Apr 28, 2026 at 04:33:38PM -0400, Brian Masney wrote:
> Hi Cristian,
>
> On Tue, Apr 28, 2026 at 09:15:10PM +0100, Cristian Marussi wrote:
> > Use the Clock protocol layer determine_rate logic to calculate the closest
> > rate that can be supported by a specific clock.
> >
> > No functional change.
> >
> > Cc: Brian Masney <bmasney@redhat.com>
> > Cc: Michael Turquette <mturquette@baylibre.com>
> > Cc: Stephen Boyd <sboyd@kernel.org>
> > Cc: linux-clk@vger.kernel.org
> > Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
> > ---
> > @brian: I'd modify further this clk-scmi driver, with a patch on top of
> > this series, to properly use your new CLK_ROUNDING_NOOP flag once your
> > series AND another (already reviewed) series on clk-scmi from Peng are in.
Hi Brian,
>
> I don't know if Stephen is going to pick up my CLK_ROUNDING_NOOP series.
> We talked about it in person at LPC in Tokyo, and he was the one that
> suggested the flag rather than a new shared noop function. However he
> didn't pick it up last development cycle.
>
> I would recommend NOT basing on that series of mine to reduce
> dependencies, and so that your stuff doesn't get held up by series.
>
Ok, thanks for the heads up, I was indeed not able to find the _NOOP in
v7.1-rc1 and I was NOT sure...anyway a patch on top of this whenever
your series goes in should not be a problem....maybe if you can ping me
when it's merged, it would be easy NOT to miss/forget :P
Thanks,
Cristian
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 04/15] firmware: arm_scmi: Simplify clock rates exposed interface
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (2 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 03/15] clk: scmi: Use new determine_rate clock operation Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-05-05 12:17 ` Geert Uytterhoeven
2026-04-28 20:15 ` [PATCH v3 05/15] clk: scmi: Use new simplified per-clock rate properties Cristian Marussi
` (11 subsequent siblings)
15 siblings, 1 reply; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Peng Fan
Introduce a new internal struct scmi_clock_desc so as to be able to hide,
in the future, some of the needlessly public fields currently kept inside
scmi_clock_info, while keeping exposed only the two new min_rate and
max_rate fields for each clock.
No functional change.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v1 --> v2
- removed useless parenthesis
- reworded comit message
---
drivers/firmware/arm_scmi/clock.c | 145 +++++++++++++++---------------
include/linux/scmi_protocol.h | 2 +
2 files changed, 74 insertions(+), 73 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 54b55517b759..467b13a3a18f 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -157,13 +157,27 @@ struct scmi_clock_rate_notify_payld {
__le32 rate_high;
};
+struct scmi_clock_desc {
+ u32 id;
+ bool rate_discrete;
+ unsigned int num_rates;
+ u64 rates[SCMI_MAX_NUM_RATES];
+#define RATE_MIN 0
+#define RATE_MAX 1
+#define RATE_STEP 2
+ struct scmi_clock_info info;
+};
+
+#define to_desc(p) (container_of(p, struct scmi_clock_desc, info))
+
struct clock_info {
int num_clocks;
int max_async_req;
bool notify_rate_changed_cmd;
bool notify_rate_change_requested_cmd;
atomic_t cur_async_req;
- struct scmi_clock_info *clk;
+ struct scmi_clock_desc *clkds;
+#define CLOCK_INFO(c, i) (&(((c)->clkds + (i))->info))
int (*clock_config_set)(const struct scmi_protocol_handle *ph,
u32 clk_id, enum clk_state state,
enum scmi_clock_oem_config oem_type,
@@ -185,7 +199,7 @@ scmi_clock_domain_lookup(struct clock_info *ci, u32 clk_id)
if (clk_id >= ci->num_clocks)
return ERR_PTR(-EINVAL);
- return ci->clk + clk_id;
+ return CLOCK_INFO(ci, clk_id);
}
static int
@@ -226,8 +240,7 @@ scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_clk_ipriv {
struct device *dev;
- u32 clk_id;
- struct scmi_clock_info *clk;
+ struct scmi_clock_desc *clkd;
};
static void iter_clk_possible_parents_prepare_message(void *message, unsigned int desc_index,
@@ -236,7 +249,7 @@ static void iter_clk_possible_parents_prepare_message(void *message, unsigned in
struct scmi_msg_clock_possible_parents *msg = message;
const struct scmi_clk_ipriv *p = priv;
- msg->id = cpu_to_le32(p->clk_id);
+ msg->id = cpu_to_le32(p->clkd->id);
/* Set the number of OPPs to be skipped/already read */
msg->skip_parents = cpu_to_le32(desc_index);
}
@@ -246,7 +259,6 @@ static int iter_clk_possible_parents_update_state(struct scmi_iterator_state *st
{
const struct scmi_msg_resp_clock_possible_parents *r = response;
struct scmi_clk_ipriv *p = priv;
- struct device *dev = ((struct scmi_clk_ipriv *)p)->dev;
u32 flags;
flags = le32_to_cpu(r->num_parent_flags);
@@ -258,12 +270,13 @@ static int iter_clk_possible_parents_update_state(struct scmi_iterator_state *st
* assume it's returned+remaining on first call.
*/
if (!st->max_resources) {
- p->clk->num_parents = st->num_returned + st->num_remaining;
- p->clk->parents = devm_kcalloc(dev, p->clk->num_parents,
- sizeof(*p->clk->parents),
- GFP_KERNEL);
- if (!p->clk->parents) {
- p->clk->num_parents = 0;
+ p->clkd->info.num_parents = st->num_returned + st->num_remaining;
+ p->clkd->info.parents = devm_kcalloc(p->dev,
+ p->clkd->info.num_parents,
+ sizeof(*p->clkd->info.parents),
+ GFP_KERNEL);
+ if (!p->clkd->info.parents) {
+ p->clkd->info.num_parents = 0;
return -ENOMEM;
}
st->max_resources = st->num_returned + st->num_remaining;
@@ -280,29 +293,27 @@ static int iter_clk_possible_parents_process_response(const struct scmi_protocol
const struct scmi_msg_resp_clock_possible_parents *r = response;
struct scmi_clk_ipriv *p = priv;
- u32 *parent = &p->clk->parents[st->desc_index + st->loop_idx];
+ u32 *parent = &p->clkd->info.parents[st->desc_index + st->loop_idx];
*parent = le32_to_cpu(r->possible_parents[st->loop_idx]);
return 0;
}
-static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u32 clk_id,
- struct scmi_clock_info *clk)
+static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph,
+ u32 clk_id, struct clock_info *cinfo)
{
struct scmi_iterator_ops ops = {
.prepare_message = iter_clk_possible_parents_prepare_message,
.update_state = iter_clk_possible_parents_update_state,
.process_response = iter_clk_possible_parents_process_response,
};
-
+ struct scmi_clock_desc *clkd = &cinfo->clkds[clk_id];
struct scmi_clk_ipriv ppriv = {
- .clk_id = clk_id,
- .clk = clk,
+ .clkd = clkd,
.dev = ph->dev,
};
void *iter;
- int ret;
iter = ph->hops->iter_response_init(ph, &ops, 0,
CLOCK_POSSIBLE_PARENTS_GET,
@@ -311,9 +322,7 @@ static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u3
if (IS_ERR(iter))
return PTR_ERR(iter);
- ret = ph->hops->iter_response_run(iter);
-
- return ret;
+ return ph->hops->iter_response_run(iter);
}
static int
@@ -352,7 +361,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
u32 attributes;
struct scmi_xfer *t;
struct scmi_msg_resp_clock_attributes *attr;
- struct scmi_clock_info *clk = cinfo->clk + clk_id;
+ struct scmi_clock_info *clk = CLOCK_INFO(cinfo, clk_id);
ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES,
sizeof(clk_id), sizeof(*attr), &t);
@@ -394,7 +403,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
clk->rate_change_requested_notifications = true;
if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
if (SUPPORTS_PARENT_CLOCK(attributes))
- scmi_clock_possible_parents(ph, clk_id, clk);
+ scmi_clock_possible_parents(ph, clk_id, cinfo);
if (SUPPORTS_GET_PERMISSIONS(attributes))
scmi_clock_get_permissions(ph, clk_id, clk);
if (SUPPORTS_EXTENDED_CONFIG(attributes))
@@ -424,7 +433,7 @@ static void iter_clk_describe_prepare_message(void *message,
struct scmi_msg_clock_describe_rates *msg = message;
const struct scmi_clk_ipriv *p = priv;
- msg->id = cpu_to_le32(p->clk_id);
+ msg->id = cpu_to_le32(p->clkd->id);
/* Set the number of rates to be skipped/already read */
msg->rate_index = cpu_to_le32(desc_index);
}
@@ -457,14 +466,14 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
flags = le32_to_cpu(r->num_rates_flags);
st->num_remaining = NUM_REMAINING(flags);
st->num_returned = NUM_RETURNED(flags);
- p->clk->rate_discrete = RATE_DISCRETE(flags);
+ p->clkd->rate_discrete = RATE_DISCRETE(flags);
/* Warn about out of spec replies ... */
- if (!p->clk->rate_discrete &&
+ if (!p->clkd->rate_discrete &&
(st->num_returned != 3 || st->num_remaining != 0)) {
dev_warn(p->dev,
"Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
- p->clk->name, st->num_returned, st->num_remaining,
+ p->clkd->info.name, st->num_returned, st->num_remaining,
st->rx_len);
SCMI_QUIRK(clock_rates_triplet_out_of_spec,
@@ -479,38 +488,19 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
const void *response,
struct scmi_iterator_state *st, void *priv)
{
- int ret = 0;
struct scmi_clk_ipriv *p = priv;
const struct scmi_msg_resp_clock_describe_rates *r = response;
- if (!p->clk->rate_discrete) {
- switch (st->desc_index + st->loop_idx) {
- case 0:
- p->clk->range.min_rate = RATE_TO_U64(r->rate[0]);
- break;
- case 1:
- p->clk->range.max_rate = RATE_TO_U64(r->rate[1]);
- break;
- case 2:
- p->clk->range.step_size = RATE_TO_U64(r->rate[2]);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- } else {
- u64 *rate = &p->clk->list.rates[st->desc_index + st->loop_idx];
+ p->clkd->rates[st->desc_index + st->loop_idx] =
+ RATE_TO_U64(r->rate[st->loop_idx]);
+ p->clkd->num_rates++;
- *rate = RATE_TO_U64(r->rate[st->loop_idx]);
- p->clk->list.num_rates++;
- }
-
- return ret;
+ return 0;
}
static int
scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
- struct scmi_clock_info *clk)
+ struct clock_info *cinfo)
{
int ret;
void *iter;
@@ -519,9 +509,9 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
.update_state = iter_clk_describe_update_state,
.process_response = iter_clk_describe_process_response,
};
+ struct scmi_clock_desc *clkd = &cinfo->clkds[clk_id];
struct scmi_clk_ipriv cpriv = {
- .clk_id = clk_id,
- .clk = clk,
+ .clkd = clkd,
.dev = ph->dev,
};
@@ -536,16 +526,23 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
if (ret)
return ret;
- if (!clk->rate_discrete) {
+ /* empty set ? */
+ if (!clkd->num_rates)
+ return 0;
+
+ if (!clkd->rate_discrete) {
+ clkd->info.max_rate = clkd->rates[RATE_MAX];
dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",
- clk->range.min_rate, clk->range.max_rate,
- clk->range.step_size);
- } else if (clk->list.num_rates) {
- sort(clk->list.rates, clk->list.num_rates,
- sizeof(clk->list.rates[0]), rate_cmp_func, NULL);
+ clkd->rates[RATE_MIN], clkd->rates[RATE_MAX],
+ clkd->rates[RATE_STEP]);
+ } else {
+ sort(clkd->rates, clkd->num_rates,
+ sizeof(clkd->rates[0]), rate_cmp_func, NULL);
+ clkd->info.max_rate = clkd->rates[clkd->num_rates - 1];
}
+ clkd->info.min_rate = clkd->rates[RATE_MIN];
- return ret;
+ return 0;
}
static int
@@ -630,6 +627,7 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
{
u64 fmin, fmax, ftmp;
struct scmi_clock_info *clk;
+ struct scmi_clock_desc *clkd;
struct clock_info *ci = ph->get_priv(ph);
if (!rate)
@@ -639,15 +637,17 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
if (IS_ERR(clk))
return PTR_ERR(clk);
+ clkd = to_desc(clk);
+
/*
* If we can't figure out what rate it will be, so just return the
* rate back to the caller.
*/
- if (clk->rate_discrete)
+ if (clkd->rate_discrete)
return 0;
- fmin = clk->range.min_rate;
- fmax = clk->range.max_rate;
+ fmin = clk->min_rate;
+ fmax = clk->max_rate;
if (*rate <= fmin) {
*rate = fmin;
return 0;
@@ -657,10 +657,10 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
}
ftmp = *rate - fmin;
- ftmp += clk->range.step_size - 1; /* to round up */
- ftmp = div64_ul(ftmp, clk->range.step_size);
+ ftmp += clkd->rates[RATE_STEP] - 1; /* to round up */
+ ftmp = div64_ul(ftmp, clkd->rates[RATE_STEP]);
- *rate = ftmp * clk->range.step_size + fmin;
+ *rate = ftmp * clkd->rates[RATE_STEP] + fmin;
return 0;
}
@@ -1122,17 +1122,16 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
if (ret)
return ret;
- cinfo->clk = devm_kcalloc(ph->dev, cinfo->num_clocks,
- sizeof(*cinfo->clk), GFP_KERNEL);
- if (!cinfo->clk)
+ cinfo->clkds = devm_kcalloc(ph->dev, cinfo->num_clocks,
+ sizeof(*cinfo->clkds), GFP_KERNEL);
+ if (!cinfo->clkds)
return -ENOMEM;
for (clkid = 0; clkid < cinfo->num_clocks; clkid++) {
- struct scmi_clock_info *clk = cinfo->clk + clkid;
-
+ cinfo->clkds[clkid].id = clkid;
ret = scmi_clock_attributes_get(ph, clkid, cinfo);
if (!ret)
- scmi_clock_describe_rates_get(ph, clkid, clk);
+ scmi_clock_describe_rates_get(ph, clkid, cinfo);
}
if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 28579c145045..7283302b0c85 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -51,6 +51,8 @@ struct scmi_clock_info {
bool rate_ctrl_forbidden;
bool parent_ctrl_forbidden;
bool extended_config;
+ u64 min_rate;
+ u64 max_rate;
union {
struct {
int num_rates;
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v3 04/15] firmware: arm_scmi: Simplify clock rates exposed interface
2026-04-28 20:15 ` [PATCH v3 04/15] firmware: arm_scmi: Simplify clock rates exposed interface Cristian Marussi
@ 2026-05-05 12:17 ` Geert Uytterhoeven
0 siblings, 0 replies; 22+ messages in thread
From: Geert Uytterhoeven @ 2026-05-05 12:17 UTC (permalink / raw)
To: Cristian Marussi, sudeep.holla
Cc: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
kuninori.morimoto.gx, marek.vasut+renesas, Peng Fan
Hi Cristian, Sudeep,
On Tue, 28 Apr 2026 at 22:16, Cristian Marussi <cristian.marussi@arm.com> wrote:
> Introduce a new internal struct scmi_clock_desc so as to be able to hide,
> in the future, some of the needlessly public fields currently kept inside
> scmi_clock_info, while keeping exposed only the two new min_rate and
> max_rate fields for each clock.
>
> No functional change.
>
> Reviewed-by: Peng Fan <peng.fan@nxp.com>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Thanks for your patch, which is now commit 83fd9d34b6b75be5 ("firmware:
arm_scmi: Simplify clock rates exposed interface") in scmi/for-linux-next.
> --- a/drivers/firmware/arm_scmi/clock.c
> +++ b/drivers/firmware/arm_scmi/clock.c
> @@ -457,14 +466,14 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
> flags = le32_to_cpu(r->num_rates_flags);
> st->num_remaining = NUM_REMAINING(flags);
> st->num_returned = NUM_RETURNED(flags);
> - p->clk->rate_discrete = RATE_DISCRETE(flags);
This removes the last setter of scmi_clock_info.rate_discrete.
However, it is still used until the next commit cd73d1bfaa8d34bb
("clk: scmi: Use new simplified per-clock rate properties").
V2 did now have this issue, as the patches were ordered differently
in that series.
After both commits, there are no more users of
scmi_clock_info.rate_discrete, so it can be removed.
> + p->clkd->rate_discrete = RATE_DISCRETE(flags);
>
> /* Warn about out of spec replies ... */
> - if (!p->clk->rate_discrete &&
> + if (!p->clkd->rate_discrete &&
> (st->num_returned != 3 || st->num_remaining != 0)) {
> dev_warn(p->dev,
> "Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
> - p->clk->name, st->num_returned, st->num_remaining,
> + p->clkd->info.name, st->num_returned, st->num_remaining,
> st->rx_len);
>
> SCMI_QUIRK(clock_rates_triplet_out_of_spec,
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 05/15] clk: scmi: Use new simplified per-clock rate properties
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (3 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 04/15] firmware: arm_scmi: Simplify clock rates exposed interface Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 06/15] firmware: arm_scmi: Drop unused clock rate interfaces Cristian Marussi
` (10 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Michael Turquette, Stephen Boyd, Peng Fan
Use the new min_rate and max_rate unified properties that provide the
proper values without having to consider the clock type.
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: linux-clk@vger.kernel.org
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v1 --> v2
- Collected Peng Reviewed-by tag
---
drivers/clk/clk-scmi.c | 17 ++---------------
1 file changed, 2 insertions(+), 15 deletions(-)
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index c223e4ef1dd1..7c562559ad8b 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -202,7 +202,6 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
const struct clk_ops *scmi_ops)
{
int ret;
- unsigned long min_rate, max_rate;
struct clk_init_data init = {
.flags = CLK_GET_RATE_NOCACHE,
@@ -217,20 +216,8 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
if (ret)
return ret;
- if (sclk->info->rate_discrete) {
- int num_rates = sclk->info->list.num_rates;
-
- if (num_rates <= 0)
- return -EINVAL;
-
- min_rate = sclk->info->list.rates[0];
- max_rate = sclk->info->list.rates[num_rates - 1];
- } else {
- min_rate = sclk->info->range.min_rate;
- max_rate = sclk->info->range.max_rate;
- }
-
- clk_hw_set_rate_range(&sclk->hw, min_rate, max_rate);
+ clk_hw_set_rate_range(&sclk->hw, sclk->info->min_rate,
+ sclk->info->max_rate);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 06/15] firmware: arm_scmi: Drop unused clock rate interfaces
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (4 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 05/15] clk: scmi: Use new simplified per-clock rate properties Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 07/15] firmware: arm_scmi: Make clock rates allocation dynamic Cristian Marussi
` (9 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Peng Fan
Only the unified interface exposing min_rate/max_rate is now used.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v1 --> v2
- Collected Peng Reviewed-by tag
---
include/linux/scmi_protocol.h | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 7283302b0c85..d97b4e734744 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -53,17 +53,6 @@ struct scmi_clock_info {
bool extended_config;
u64 min_rate;
u64 max_rate;
- union {
- struct {
- int num_rates;
- u64 rates[SCMI_MAX_NUM_RATES];
- } list;
- struct {
- u64 min_rate;
- u64 max_rate;
- u64 step_size;
- } range;
- };
int num_parents;
u32 *parents;
};
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 07/15] firmware: arm_scmi: Make clock rates allocation dynamic
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (5 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 06/15] firmware: arm_scmi: Drop unused clock rate interfaces Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 08/15] firmware: arm_scmi: Harden clock parents discovery Cristian Marussi
` (8 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Peng Fan
Leveraging SCMI Clock protocol dynamic discovery capabilities, move away
from the static per-clock rates allocation model in favour of a dynamic
runtime allocation based on effectively discovered resources.
No functional change.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> v3
- collected Review-by tags
---
drivers/firmware/arm_scmi/clock.c | 19 ++++++++++++++++---
include/linux/scmi_protocol.h | 1 -
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 467b13a3a18f..c9b62edce4fd 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -161,7 +161,7 @@ struct scmi_clock_desc {
u32 id;
bool rate_discrete;
unsigned int num_rates;
- u64 rates[SCMI_MAX_NUM_RATES];
+ u64 *rates;
#define RATE_MIN 0
#define RATE_MAX 1
#define RATE_STEP 2
@@ -480,6 +480,18 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
QUIRK_OUT_OF_SPEC_TRIPLET);
}
+ if (!st->max_resources) {
+ int num_rates = st->num_returned + st->num_remaining;
+
+ p->clkd->rates = devm_kcalloc(p->dev, num_rates,
+ sizeof(*p->clkd->rates), GFP_KERNEL);
+ if (!p->clkd->rates)
+ return -ENOMEM;
+
+ /* max_resources is used by the iterators to control bounds */
+ st->max_resources = st->num_returned + st->num_remaining;
+ }
+
return 0;
}
@@ -493,6 +505,8 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
p->clkd->rates[st->desc_index + st->loop_idx] =
RATE_TO_U64(r->rate[st->loop_idx]);
+
+ /* Count only effectively discovered rates */
p->clkd->num_rates++;
return 0;
@@ -515,8 +529,7 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
.dev = ph->dev,
};
- iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,
- CLOCK_DESCRIBE_RATES,
+ iter = ph->hops->iter_response_init(ph, &ops, 0, CLOCK_DESCRIBE_RATES,
sizeof(struct scmi_msg_clock_describe_rates),
&cpriv);
if (IS_ERR(iter))
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index d97b4e734744..5552ac04c820 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -15,7 +15,6 @@
#define SCMI_MAX_STR_SIZE 64
#define SCMI_SHORT_NAME_MAX_SIZE 16
-#define SCMI_MAX_NUM_RATES 16
/**
* struct scmi_revision_info - version information structure
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 08/15] firmware: arm_scmi: Harden clock parents discovery
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (6 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 07/15] firmware: arm_scmi: Make clock rates allocation dynamic Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 09/15] firmware: arm_scmi: Refactor iterators internal allocation Cristian Marussi
` (7 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Peng Fan
Fix clock parents enumeration to account only for effectively discovered
parents during enumeration, avoiding to trust the total number of parents
declared upfront by the platform.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> v3
- collected Reviewed-by tags
---
drivers/firmware/arm_scmi/clock.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index c9b62edce4fd..d07cfef243fd 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -270,15 +270,15 @@ static int iter_clk_possible_parents_update_state(struct scmi_iterator_state *st
* assume it's returned+remaining on first call.
*/
if (!st->max_resources) {
- p->clkd->info.num_parents = st->num_returned + st->num_remaining;
- p->clkd->info.parents = devm_kcalloc(p->dev,
- p->clkd->info.num_parents,
+ int num_parents = st->num_returned + st->num_remaining;
+
+ p->clkd->info.parents = devm_kcalloc(p->dev, num_parents,
sizeof(*p->clkd->info.parents),
GFP_KERNEL);
- if (!p->clkd->info.parents) {
- p->clkd->info.num_parents = 0;
+ if (!p->clkd->info.parents)
return -ENOMEM;
- }
+
+ /* max_resources is used by the iterators to control bounds */
st->max_resources = st->num_returned + st->num_remaining;
}
@@ -293,9 +293,11 @@ static int iter_clk_possible_parents_process_response(const struct scmi_protocol
const struct scmi_msg_resp_clock_possible_parents *r = response;
struct scmi_clk_ipriv *p = priv;
- u32 *parent = &p->clkd->info.parents[st->desc_index + st->loop_idx];
+ p->clkd->info.parents[st->desc_index + st->loop_idx] =
+ le32_to_cpu(r->possible_parents[st->loop_idx]);
- *parent = le32_to_cpu(r->possible_parents[st->loop_idx]);
+ /* Count only effectively discovered parents */
+ p->clkd->info.num_parents++;
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 09/15] firmware: arm_scmi: Refactor iterators internal allocation
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (7 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 08/15] firmware: arm_scmi: Harden clock parents discovery Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 10/15] firmware: arm_scmi: Add bound iterators support Cristian Marussi
` (6 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Peng Fan
Use cleanup handlers to manage iterator data structures.
No functional change.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> v3
- collected Reviewed tags
---
drivers/firmware/arm_scmi/driver.c | 35 +++++++++++++++---------------
1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index f167194f7cf6..66cb64c8ed3d 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -17,6 +17,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitmap.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/export.h>
@@ -1789,39 +1790,41 @@ static void *scmi_iterator_init(const struct scmi_protocol_handle *ph,
size_t tx_size, void *priv)
{
int ret;
- struct scmi_iterator *i;
- i = devm_kzalloc(ph->dev, sizeof(*i), GFP_KERNEL);
+ struct scmi_iterator *i __free(kfree) = kzalloc(sizeof(*i), GFP_KERNEL);
if (!i)
return ERR_PTR(-ENOMEM);
+ if (!ops || !ph)
+ return ERR_PTR(-EINVAL);
+
i->ph = ph;
i->ops = ops;
i->priv = priv;
ret = ph->xops->xfer_get_init(ph, msg_id, tx_size, 0, &i->t);
- if (ret) {
- devm_kfree(ph->dev, i);
+ if (ret)
return ERR_PTR(ret);
- }
i->state.max_resources = max_resources;
i->msg = i->t->tx.buf;
i->resp = i->t->rx.buf;
- return i;
+ return no_free_ptr(i);
}
static int scmi_iterator_run(void *iter)
{
- int ret = -EINVAL;
+ int ret;
struct scmi_iterator_ops *iops;
const struct scmi_protocol_handle *ph;
struct scmi_iterator_state *st;
- struct scmi_iterator *i = iter;
- if (!i || !i->ops || !i->ph)
- return ret;
+ if (!iter)
+ return -EINVAL;
+
+ /* Take ownership of the iterator */
+ struct scmi_iterator *i __free(kfree) = iter;
iops = i->ops;
ph = i->ph;
@@ -1846,12 +1849,12 @@ static int scmi_iterator_run(void *iter)
break;
}
- for (st->loop_idx = 0; st->loop_idx < st->num_returned;
- st->loop_idx++) {
+ for (st->loop_idx = 0; !ret && st->loop_idx < st->num_returned;
+ st->loop_idx++)
ret = iops->process_response(ph, i->resp, st, i->priv);
- if (ret)
- goto out;
- }
+
+ if (ret)
+ break;
st->desc_index += st->num_returned;
ph->xops->reset_rx_to_maxsz(ph, i->t);
@@ -1861,10 +1864,8 @@ static int scmi_iterator_run(void *iter)
*/
} while (st->num_returned && st->num_remaining);
-out:
/* Finalize and destroy iterator */
ph->xops->xfer_put(ph, i->t);
- devm_kfree(ph->dev, i);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 10/15] firmware: arm_scmi: Add bound iterators support
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (8 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 09/15] firmware: arm_scmi: Refactor iterators internal allocation Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 11/15] firmware: arm_scmi: Fix bound iterators returning too many items Cristian Marussi
` (5 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi
SCMI core stack provides some common helpers to handle in a unified way
multipart message replies: such iterator-helpers, when run, currently
process by default the whole set of discovered resources.
Introduce an alternative way to run the initialized iterator on a limited
range of resources.
Note that the subset of resources that can be chosen is anyway limited by
the SCMI protocol specification, since you are only allowed to choose the
start-index on a multi-part enumeration NOT the end-index, so that the
effective number of returned items by a bound iterators depends really
on platform side decisions.
Suggested-by: Etienne Carriere <etienne.carriere@foss.st.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> v3
- fixed typos in commit message
---
drivers/firmware/arm_scmi/clock.c | 3 +-
drivers/firmware/arm_scmi/driver.c | 58 +++++++++++++++++++--------
drivers/firmware/arm_scmi/protocols.h | 13 +++++-
3 files changed, 55 insertions(+), 19 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index d07cfef243fd..8ce889dfc87b 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -505,8 +505,7 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
struct scmi_clk_ipriv *p = priv;
const struct scmi_msg_resp_clock_describe_rates *r = response;
- p->clkd->rates[st->desc_index + st->loop_idx] =
- RATE_TO_U64(r->rate[st->loop_idx]);
+ p->clkd->rates[p->clkd->num_rates] = RATE_TO_U64(r->rate[st->loop_idx]);
/* Count only effectively discovered rates */
p->clkd->num_rates++;
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 66cb64c8ed3d..cb4865fd8af2 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1813,48 +1813,50 @@ static void *scmi_iterator_init(const struct scmi_protocol_handle *ph,
return no_free_ptr(i);
}
-static int scmi_iterator_run(void *iter)
+static int __scmi_iterator_run(void *iter, unsigned int *start, unsigned int *end)
{
int ret;
struct scmi_iterator_ops *iops;
const struct scmi_protocol_handle *ph;
struct scmi_iterator_state *st;
+ struct scmi_iterator *i;
if (!iter)
return -EINVAL;
- /* Take ownership of the iterator */
- struct scmi_iterator *i __free(kfree) = iter;
-
+ i = iter;
iops = i->ops;
ph = i->ph;
st = &i->state;
+ /* Reinitialize state for next run */
+ st->num_returned = 0;
+ st->num_remaining = 0;
+ st->desc_index = start ? *start : 0;
+
do {
iops->prepare_message(i->msg, st->desc_index, i->priv);
ret = ph->xops->do_xfer(ph, i->t);
if (ret)
- break;
+ return ret;
st->rx_len = i->t->rx.len;
ret = iops->update_state(st, i->resp, i->priv);
if (ret)
- break;
+ return ret;
if (st->num_returned > st->max_resources - st->desc_index) {
dev_err(ph->dev,
"No. of resources can't exceed %d\n",
st->max_resources);
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- for (st->loop_idx = 0; !ret && st->loop_idx < st->num_returned;
- st->loop_idx++)
+ for (st->loop_idx = 0; st->loop_idx < st->num_returned; st->loop_idx++) {
ret = iops->process_response(ph, i->resp, st, i->priv);
-
- if (ret)
- break;
+ if (ret)
+ return ret;
+ }
st->desc_index += st->num_returned;
ph->xops->reset_rx_to_maxsz(ph, i->t);
@@ -1862,14 +1864,36 @@ static int scmi_iterator_run(void *iter)
* check for both returned and remaining to avoid infinite
* loop due to buggy firmware
*/
- } while (st->num_returned && st->num_remaining);
+ } while (st->num_returned && st->num_remaining &&
+ (!end || (st->desc_index <= min(*end, st->max_resources - 1))));
- /* Finalize and destroy iterator */
- ph->xops->xfer_put(ph, i->t);
+ return 0;
+}
+
+static void scmi_iterator_cleanup(void *iter)
+{
+ struct scmi_iterator *i = iter;
+
+ i->ph->xops->xfer_put(i->ph, i->t);
+ kfree(i);
+}
+
+static int scmi_iterator_run(void *iter)
+{
+ int ret;
+
+ ret = __scmi_iterator_run(iter, NULL, NULL);
+ scmi_iterator_cleanup(iter);
return ret;
}
+static int scmi_iterator_run_bound(void *iter, unsigned int *start,
+ unsigned int *end)
+{
+ return __scmi_iterator_run(iter, start, end);
+}
+
struct scmi_msg_get_fc_info {
__le32 domain;
__le32 message_id;
@@ -2048,6 +2072,8 @@ static const struct scmi_proto_helpers_ops helpers_ops = {
.get_max_msg_size = scmi_common_get_max_msg_size,
.iter_response_init = scmi_iterator_init,
.iter_response_run = scmi_iterator_run,
+ .iter_response_run_bound = scmi_iterator_run_bound,
+ .iter_response_cleanup = scmi_iterator_cleanup,
.protocol_msg_check = scmi_protocol_msg_check,
.fastchannel_init = scmi_common_fastchannel_init,
.fastchannel_db_ring = scmi_common_fastchannel_db_ring,
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index f51245aca259..e2ef604c16ef 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -259,7 +259,15 @@ struct scmi_fc_info {
* multi-part responses using the custom operations
* provided in @ops.
* @iter_response_run: A common helper to trigger the run of a previously
- * initialized iterator.
+ * initialized iterator. Note that unbound iterators are
+ * automatically cleaned up.
+ * @iter_response_run_bound: A common helper to trigger the run of a previously
+ * initialized iterator, but only within the
+ * specified, optional, @start and @end resource
+ * indexes. Note that these bound-iterators need
+ * explicit cleanup via @iter_response_bound_cleanup.
+ * @iter_response_bound_cleanup: A common helper to finally release the iterator
+ * for bound iterators.
* @protocol_msg_check: A common helper to check is a specific protocol message
* is supported.
* @fastchannel_init: A common helper used to initialize FC descriptors by
@@ -276,6 +284,9 @@ struct scmi_proto_helpers_ops {
unsigned int max_resources, u8 msg_id,
size_t tx_size, void *priv);
int (*iter_response_run)(void *iter);
+ int (*iter_response_run_bound)(void *iter,
+ unsigned int *start, unsigned int *end);
+ void (*iter_response_cleanup)(void *iter);
int (*protocol_msg_check)(const struct scmi_protocol_handle *ph,
u32 message_id, u32 *attributes);
void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 11/15] firmware: arm_scmi: Fix bound iterators returning too many items
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (9 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 10/15] firmware: arm_scmi: Add bound iterators support Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 12/15] firmware: arm_scmi: Use proper iter_response_bound_cleanup() name Cristian Marussi
` (4 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi
From: Geert Uytterhoeven <geert+renesas@glider.be>
When using a bound-iterator with an upper bound, commands are sent, and
responses are received, until the upper bound is reached. However, it
is up to the SCMI provider implementation to decide how many rates are
returned in response to a single CLOCK_DESCRIBE_RATES command. If the
last response contains rates beyond the specified upper bound, they are
still passed up for further processing. This may lead to buffer
overflows in unprepared callsites.
While the imprecise bound handling may have been intentional (it was
mentioned in the commit message introducing the code), it is still
confusing for users, and may cause hard to debug crashes. Fix this by
strictly enforcing the upper bound.
Note that this may cause an increase in the number of
CLOCK_DESCRIBE_RATES commands issued, as retrieving the last rate may no
longer be done inadvertentently, but require its own command.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[Cristian: removed Fixed tag referring the same series]
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
drivers/firmware/arm_scmi/driver.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index cb4865fd8af2..fd031a8d40df 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1820,6 +1820,7 @@ static int __scmi_iterator_run(void *iter, unsigned int *start, unsigned int *en
const struct scmi_protocol_handle *ph;
struct scmi_iterator_state *st;
struct scmi_iterator *i;
+ unsigned int n;
if (!iter)
return -EINVAL;
@@ -1852,13 +1853,17 @@ static int __scmi_iterator_run(void *iter, unsigned int *start, unsigned int *en
return -EINVAL;
}
- for (st->loop_idx = 0; st->loop_idx < st->num_returned; st->loop_idx++) {
+ if (end)
+ n = min(st->num_returned, *end - st->desc_index + 1);
+ else
+ n = st->num_returned;
+ for (st->loop_idx = 0; st->loop_idx < n; st->loop_idx++) {
ret = iops->process_response(ph, i->resp, st, i->priv);
if (ret)
return ret;
}
- st->desc_index += st->num_returned;
+ st->desc_index += n;
ph->xops->reset_rx_to_maxsz(ph, i->t);
/*
* check for both returned and remaining to avoid infinite
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 12/15] firmware: arm_scmi: Use proper iter_response_bound_cleanup() name
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (10 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 11/15] firmware: arm_scmi: Fix bound iterators returning too many items Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 13/15] firmware: arm_scmi: Use bound iterators to minimize discovered rates Cristian Marussi
` (3 subsequent siblings)
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi
From: Geert Uytterhoeven <geert+renesas@glider.be>
The documentation speaks of the "iter_response_bound_cleanup()" protocol
helper, while the actual helper is called "iter_response_cleanup()".
Settle on the former name, because the helper is only needed when using
bound-iterators.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[Cristian: removed Fixed tag referring the same series]
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
drivers/firmware/arm_scmi/driver.c | 6 +++---
drivers/firmware/arm_scmi/protocols.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index fd031a8d40df..57785c0c0424 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1875,7 +1875,7 @@ static int __scmi_iterator_run(void *iter, unsigned int *start, unsigned int *en
return 0;
}
-static void scmi_iterator_cleanup(void *iter)
+static void scmi_iterator_bound_cleanup(void *iter)
{
struct scmi_iterator *i = iter;
@@ -1888,7 +1888,7 @@ static int scmi_iterator_run(void *iter)
int ret;
ret = __scmi_iterator_run(iter, NULL, NULL);
- scmi_iterator_cleanup(iter);
+ scmi_iterator_bound_cleanup(iter);
return ret;
}
@@ -2078,7 +2078,7 @@ static const struct scmi_proto_helpers_ops helpers_ops = {
.iter_response_init = scmi_iterator_init,
.iter_response_run = scmi_iterator_run,
.iter_response_run_bound = scmi_iterator_run_bound,
- .iter_response_cleanup = scmi_iterator_cleanup,
+ .iter_response_bound_cleanup = scmi_iterator_bound_cleanup,
.protocol_msg_check = scmi_protocol_msg_check,
.fastchannel_init = scmi_common_fastchannel_init,
.fastchannel_db_ring = scmi_common_fastchannel_db_ring,
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index e2ef604c16ef..15ad5162e37a 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -286,7 +286,7 @@ struct scmi_proto_helpers_ops {
int (*iter_response_run)(void *iter);
int (*iter_response_run_bound)(void *iter,
unsigned int *start, unsigned int *end);
- void (*iter_response_cleanup)(void *iter);
+ void (*iter_response_bound_cleanup)(void *iter);
int (*protocol_msg_check)(const struct scmi_protocol_handle *ph,
u32 message_id, u32 *attributes);
void (*fastchannel_init)(const struct scmi_protocol_handle *ph,
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 13/15] firmware: arm_scmi: Use bound iterators to minimize discovered rates
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (11 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 12/15] firmware: arm_scmi: Use proper iter_response_bound_cleanup() name Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-05-05 9:59 ` Geert Uytterhoeven
2026-04-28 20:15 ` [PATCH v3 14/15] firmware: arm_scmi: Fix OOB in scmi_clock_describe_rates_get_lazy() Cristian Marussi
` (2 subsequent siblings)
15 siblings, 1 reply; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi
Clock rates are guaranteed to be returned in ascending order for SCMI clock
protocol versions greater than 1.0: in such a case, use bounded iterators
to minimize the number of message exchanges needed to discover min and max
rate.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v1 --> v2
- fixed final ret value in scmi_clock_describe_get
---
drivers/firmware/arm_scmi/clock.c | 90 +++++++++++++++++++++++++++----
1 file changed, 81 insertions(+), 9 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 8ce889dfc87b..15a963b1edb9 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -160,6 +160,7 @@ struct scmi_clock_rate_notify_payld {
struct scmi_clock_desc {
u32 id;
bool rate_discrete;
+ unsigned int tot_rates;
unsigned int num_rates;
u64 *rates;
#define RATE_MIN 0
@@ -483,15 +484,16 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
}
if (!st->max_resources) {
- int num_rates = st->num_returned + st->num_remaining;
+ unsigned int tot_rates = st->num_returned + st->num_remaining;
- p->clkd->rates = devm_kcalloc(p->dev, num_rates,
+ p->clkd->rates = devm_kcalloc(p->dev, tot_rates,
sizeof(*p->clkd->rates), GFP_KERNEL);
if (!p->clkd->rates)
return -ENOMEM;
/* max_resources is used by the iterators to control bounds */
- st->max_resources = st->num_returned + st->num_remaining;
+ p->clkd->tot_rates = tot_rates;
+ st->max_resources = tot_rates;
}
return 0;
@@ -514,8 +516,8 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
}
static int
-scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
- struct clock_info *cinfo)
+scmi_clock_describe_rates_get_full(const struct scmi_protocol_handle *ph,
+ struct scmi_clock_desc *clkd)
{
int ret;
void *iter;
@@ -524,7 +526,6 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
.update_state = iter_clk_describe_update_state,
.process_response = iter_clk_describe_process_response,
};
- struct scmi_clock_desc *clkd = &cinfo->clkds[clk_id];
struct scmi_clk_ipriv cpriv = {
.clkd = clkd,
.dev = ph->dev,
@@ -544,17 +545,88 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
if (!clkd->num_rates)
return 0;
+ if (clkd->rate_discrete)
+ sort(clkd->rates, clkd->num_rates,
+ sizeof(clkd->rates[0]), rate_cmp_func, NULL);
+
+ return 0;
+}
+
+static int
+scmi_clock_describe_rates_get_lazy(const struct scmi_protocol_handle *ph,
+ struct scmi_clock_desc *clkd)
+{
+ struct scmi_iterator_ops ops = {
+ .prepare_message = iter_clk_describe_prepare_message,
+ .update_state = iter_clk_describe_update_state,
+ .process_response = iter_clk_describe_process_response,
+ };
+ struct scmi_clk_ipriv cpriv = {
+ .clkd = clkd,
+ .dev = ph->dev,
+ };
+ unsigned int first, last;
+ void *iter;
+ int ret;
+
+ iter = ph->hops->iter_response_init(ph, &ops, 0, CLOCK_DESCRIBE_RATES,
+ sizeof(struct scmi_msg_clock_describe_rates),
+ &cpriv);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
+
+ /* Try to grab a triplet, so that in case is NON-discrete we are done */
+ first = 0;
+ last = 2;
+ ret = ph->hops->iter_response_run_bound(iter, &first, &last);
+ if (ret)
+ goto out;
+
+ /* If discrete grab the last value, which should be the max */
+ if (clkd->rate_discrete && clkd->tot_rates > 3) {
+ first = clkd->tot_rates - 1;
+ last = clkd->tot_rates - 1;
+ ret = ph->hops->iter_response_run_bound(iter, &first, &last);
+ }
+
+out:
+ ph->hops->iter_response_cleanup(iter);
+
+ return ret;
+}
+
+static int
+scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph,
+ u32 clk_id, struct clock_info *cinfo)
+{
+ struct scmi_clock_desc *clkd = &cinfo->clkds[clk_id];
+ int ret;
+
+ /*
+ * Since only after SCMI Clock v1.0 the returned rates are guaranteed to
+ * be discovered in ascending order, lazy enumeration cannot be use for
+ * SCMI Clock v1.0 protocol.
+ */
+ if (PROTOCOL_REV_MAJOR(ph->version) > 0x1)
+ ret = scmi_clock_describe_rates_get_lazy(ph, clkd);
+ else
+ ret = scmi_clock_describe_rates_get_full(ph, clkd);
+
+ if (ret)
+ return ret;
+
+ clkd->info.min_rate = clkd->rates[RATE_MIN];
if (!clkd->rate_discrete) {
clkd->info.max_rate = clkd->rates[RATE_MAX];
dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",
clkd->rates[RATE_MIN], clkd->rates[RATE_MAX],
clkd->rates[RATE_STEP]);
} else {
- sort(clkd->rates, clkd->num_rates,
- sizeof(clkd->rates[0]), rate_cmp_func, NULL);
clkd->info.max_rate = clkd->rates[clkd->num_rates - 1];
+ dev_dbg(ph->dev, "Clock:%s DISCRETE:%d -> Min %llu Max %llu\n",
+ clkd->info.name, clkd->rate_discrete,
+ clkd->info.min_rate, clkd->info.max_rate);
}
- clkd->info.min_rate = clkd->rates[RATE_MIN];
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v3 13/15] firmware: arm_scmi: Use bound iterators to minimize discovered rates
2026-04-28 20:15 ` [PATCH v3 13/15] firmware: arm_scmi: Use bound iterators to minimize discovered rates Cristian Marussi
@ 2026-05-05 9:59 ` Geert Uytterhoeven
2026-05-05 11:57 ` Geert Uytterhoeven
0 siblings, 1 reply; 22+ messages in thread
From: Geert Uytterhoeven @ 2026-05-05 9:59 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc, sudeep.holla, philip.radford, james.quinlan,
f.fainelli, vincent.guittot, etienne.carriere, peng.fan,
michal.simek, kuninori.morimoto.gx, marek.vasut+renesas
Hi Cristian,
On Tue, 28 Apr 2026 at 22:17, Cristian Marussi <cristian.marussi@arm.com> wrote:
> Clock rates are guaranteed to be returned in ascending order for SCMI clock
> protocol versions greater than 1.0: in such a case, use bounded iterators
> to minimize the number of message exchanges needed to discover min and max
> rate.
>
> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Thanks for your patch!
> +static int
> +scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph,
> + u32 clk_id, struct clock_info *cinfo)
> +{
> + struct scmi_clock_desc *clkd = &cinfo->clkds[clk_id];
> + int ret;
> +
> + /*
> + * Since only after SCMI Clock v1.0 the returned rates are guaranteed to
> + * be discovered in ascending order, lazy enumeration cannot be use for
> + * SCMI Clock v1.0 protocol.
> + */
> + if (PROTOCOL_REV_MAJOR(ph->version) > 0x1)
> + ret = scmi_clock_describe_rates_get_lazy(ph, clkd);
> + else
> + ret = scmi_clock_describe_rates_get_full(ph, clkd);
> +
> + if (ret)
> + return ret;
> +
> + clkd->info.min_rate = clkd->rates[RATE_MIN];
> if (!clkd->rate_discrete) {
> clkd->info.max_rate = clkd->rates[RATE_MAX];
> dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",
> clkd->rates[RATE_MIN], clkd->rates[RATE_MAX],
> clkd->rates[RATE_STEP]);
> } else {
> - sort(clkd->rates, clkd->num_rates,
> - sizeof(clkd->rates[0]), rate_cmp_func, NULL);
> clkd->info.max_rate = clkd->rates[clkd->num_rates - 1];
> + dev_dbg(ph->dev, "Clock:%s DISCRETE:%d -> Min %llu Max %llu\n",
> + clkd->info.name, clkd->rate_discrete,
> + clkd->info.min_rate, clkd->info.max_rate);
Printing clkd->rate_discrete is futile, as it is always 1.
It would be more useful to print clkd->r.num_rates instead, although
that may still be lower than the actual value, due to lazy handling.
> }
> - clkd->info.min_rate = clkd->rates[RATE_MIN];
>
> return 0;
> }
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 22+ messages in thread* Re: [PATCH v3 13/15] firmware: arm_scmi: Use bound iterators to minimize discovered rates
2026-05-05 9:59 ` Geert Uytterhoeven
@ 2026-05-05 11:57 ` Geert Uytterhoeven
0 siblings, 0 replies; 22+ messages in thread
From: Geert Uytterhoeven @ 2026-05-05 11:57 UTC (permalink / raw)
To: Cristian Marussi
Cc: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc, sudeep.holla, philip.radford, james.quinlan,
f.fainelli, vincent.guittot, etienne.carriere, peng.fan,
michal.simek, kuninori.morimoto.gx, marek.vasut+renesas
On Tue, 5 May 2026 at 11:59, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Tue, 28 Apr 2026 at 22:17, Cristian Marussi <cristian.marussi@arm.com> wrote:
> > Clock rates are guaranteed to be returned in ascending order for SCMI clock
> > protocol versions greater than 1.0: in such a case, use bounded iterators
> > to minimize the number of message exchanges needed to discover min and max
> > rate.
> >
> > Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
>
> Thanks for your patch!
>
> > +static int
> > +scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph,
> > + u32 clk_id, struct clock_info *cinfo)
> > +{
> > + struct scmi_clock_desc *clkd = &cinfo->clkds[clk_id];
> > + int ret;
> > +
> > + /*
> > + * Since only after SCMI Clock v1.0 the returned rates are guaranteed to
> > + * be discovered in ascending order, lazy enumeration cannot be use for
> > + * SCMI Clock v1.0 protocol.
> > + */
> > + if (PROTOCOL_REV_MAJOR(ph->version) > 0x1)
> > + ret = scmi_clock_describe_rates_get_lazy(ph, clkd);
> > + else
> > + ret = scmi_clock_describe_rates_get_full(ph, clkd);
> > +
> > + if (ret)
> > + return ret;
> > +
> > + clkd->info.min_rate = clkd->rates[RATE_MIN];
> > if (!clkd->rate_discrete) {
> > clkd->info.max_rate = clkd->rates[RATE_MAX];
> > dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",
> > clkd->rates[RATE_MIN], clkd->rates[RATE_MAX],
> > clkd->rates[RATE_STEP]);
> > } else {
> > - sort(clkd->rates, clkd->num_rates,
> > - sizeof(clkd->rates[0]), rate_cmp_func, NULL);
> > clkd->info.max_rate = clkd->rates[clkd->num_rates - 1];
> > + dev_dbg(ph->dev, "Clock:%s DISCRETE:%d -> Min %llu Max %llu\n",
> > + clkd->info.name, clkd->rate_discrete,
> > + clkd->info.min_rate, clkd->info.max_rate);
>
> Printing clkd->rate_discrete is futile, as it is always 1.
> It would be more useful to print clkd->r.num_rates instead, although
clkd->tot_rates (sorry, my local tree still had your v2)
> that may still be lower than the actual value, due to lazy handling.
clkd->tot_rates is the actual value, so there is no such issue.
>
> > }
> > - clkd->info.min_rate = clkd->rates[RATE_MIN];
> >
> > return 0;
> > }
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH v3 14/15] firmware: arm_scmi: Fix OOB in scmi_clock_describe_rates_get_lazy()
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (12 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 13/15] firmware: arm_scmi: Use bound iterators to minimize discovered rates Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-28 20:15 ` [PATCH v3 15/15] firmware: arm_scmi: Introduce all_rates_get clock operation Cristian Marussi
2026-04-29 15:39 ` [PATCH v3 00/15] SCMI Clock rates discovery rework Florian Fainelli
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi
From: Geert Uytterhoeven <geert+renesas@glider.be>
Lazy discovery of discrete rates works as follows:
A. Grab the first three rates,
B. Grab the last rate, if there are more than three rates.
It is up to the SCMI provider implementation to decide how many rates
are returned in response to a single CLOCK_DESCRIBE_RATES command. Each
rate received is stored in the scmi_clock_rates.rates[] array, and
.num_rates is updated accordingly.
When more than 3 rates have been received after step A, the last rate
may have been received already, and stored in scmi_clock_rates.rates[]
(which has space for scmi_clock_desc.tot_rates entries). Hence grabbing
the last rate again will store it a second time, beyond the end of the
array.
Fix this by only grabbing the last rate when we don't already have it.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
[Cristian: removed Fixed tag referring the same series]
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
drivers/firmware/arm_scmi/clock.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 15a963b1edb9..ba25a9c6d3ae 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -582,15 +582,18 @@ scmi_clock_describe_rates_get_lazy(const struct scmi_protocol_handle *ph,
if (ret)
goto out;
- /* If discrete grab the last value, which should be the max */
- if (clkd->rate_discrete && clkd->tot_rates > 3) {
+ /*
+ * If discrete and we don't already have it, grab the last value, which
+ * should be the max
+ */
+ if (clkd->rate_discrete && clkd->tot_rates > clkd->num_rates) {
first = clkd->tot_rates - 1;
last = clkd->tot_rates - 1;
ret = ph->hops->iter_response_run_bound(iter, &first, &last);
}
out:
- ph->hops->iter_response_cleanup(iter);
+ ph->hops->iter_response_bound_cleanup(iter);
return ret;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* [PATCH v3 15/15] firmware: arm_scmi: Introduce all_rates_get clock operation
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (13 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 14/15] firmware: arm_scmi: Fix OOB in scmi_clock_describe_rates_get_lazy() Cristian Marussi
@ 2026-04-28 20:15 ` Cristian Marussi
2026-04-29 15:39 ` [PATCH v3 00/15] SCMI Clock rates discovery rework Florian Fainelli
15 siblings, 0 replies; 22+ messages in thread
From: Cristian Marussi @ 2026-04-28 20:15 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel, arm-scmi, linux-clk,
linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, f.fainelli,
vincent.guittot, etienne.carriere, peng.fan, michal.simek,
geert+renesas, kuninori.morimoto.gx, marek.vasut+renesas,
Cristian Marussi, Peng Fan
Add a clock operation to get the whole set of rates available to a specific
clock: when needed this request could transparently trigger a full rate
discovery enumeration if this specific clock-rates were previously only
lazily enumerated.
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
v2 --> v3
- collected Reviewed tags
---
drivers/firmware/arm_scmi/clock.c | 85 +++++++++++++++++++++----------
include/linux/scmi_protocol.h | 9 ++++
2 files changed, 67 insertions(+), 27 deletions(-)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index ba25a9c6d3ae..316d3cd90c81 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -159,10 +159,8 @@ struct scmi_clock_rate_notify_payld {
struct scmi_clock_desc {
u32 id;
- bool rate_discrete;
unsigned int tot_rates;
- unsigned int num_rates;
- u64 *rates;
+ struct scmi_clock_rates r;
#define RATE_MIN 0
#define RATE_MAX 1
#define RATE_STEP 2
@@ -469,10 +467,10 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
flags = le32_to_cpu(r->num_rates_flags);
st->num_remaining = NUM_REMAINING(flags);
st->num_returned = NUM_RETURNED(flags);
- p->clkd->rate_discrete = RATE_DISCRETE(flags);
+ p->clkd->r.rate_discrete = RATE_DISCRETE(flags);
/* Warn about out of spec replies ... */
- if (!p->clkd->rate_discrete &&
+ if (!p->clkd->r.rate_discrete &&
(st->num_returned != 3 || st->num_remaining != 0)) {
dev_warn(p->dev,
"Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
@@ -486,9 +484,9 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
if (!st->max_resources) {
unsigned int tot_rates = st->num_returned + st->num_remaining;
- p->clkd->rates = devm_kcalloc(p->dev, tot_rates,
- sizeof(*p->clkd->rates), GFP_KERNEL);
- if (!p->clkd->rates)
+ p->clkd->r.rates = devm_kcalloc(p->dev, tot_rates,
+ sizeof(*p->clkd->r.rates), GFP_KERNEL);
+ if (!p->clkd->r.rates)
return -ENOMEM;
/* max_resources is used by the iterators to control bounds */
@@ -507,10 +505,10 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
struct scmi_clk_ipriv *p = priv;
const struct scmi_msg_resp_clock_describe_rates *r = response;
- p->clkd->rates[p->clkd->num_rates] = RATE_TO_U64(r->rate[st->loop_idx]);
+ p->clkd->r.rates[p->clkd->r.num_rates] = RATE_TO_U64(r->rate[st->loop_idx]);
/* Count only effectively discovered rates */
- p->clkd->num_rates++;
+ p->clkd->r.num_rates++;
return 0;
}
@@ -531,7 +529,13 @@ scmi_clock_describe_rates_get_full(const struct scmi_protocol_handle *ph,
.dev = ph->dev,
};
- iter = ph->hops->iter_response_init(ph, &ops, 0, CLOCK_DESCRIBE_RATES,
+ /*
+ * Using tot_rates as max_resources parameter here so as to trigger
+ * the dynamic allocation only when strictly needed: when trying a
+ * full enumeration after a lazy one tot_rates will be non-zero.
+ */
+ iter = ph->hops->iter_response_init(ph, &ops, clkd->tot_rates,
+ CLOCK_DESCRIBE_RATES,
sizeof(struct scmi_msg_clock_describe_rates),
&cpriv);
if (IS_ERR(iter))
@@ -542,12 +546,12 @@ scmi_clock_describe_rates_get_full(const struct scmi_protocol_handle *ph,
return ret;
/* empty set ? */
- if (!clkd->num_rates)
+ if (!clkd->r.num_rates)
return 0;
- if (clkd->rate_discrete)
- sort(clkd->rates, clkd->num_rates,
- sizeof(clkd->rates[0]), rate_cmp_func, NULL);
+ if (clkd->r.rate_discrete && PROTOCOL_REV_MAJOR(ph->version) == 0x1)
+ sort(clkd->r.rates, clkd->r.num_rates,
+ sizeof(clkd->r.rates[0]), rate_cmp_func, NULL);
return 0;
}
@@ -586,7 +590,7 @@ scmi_clock_describe_rates_get_lazy(const struct scmi_protocol_handle *ph,
* If discrete and we don't already have it, grab the last value, which
* should be the max
*/
- if (clkd->rate_discrete && clkd->tot_rates > clkd->num_rates) {
+ if (clkd->r.rate_discrete && clkd->tot_rates > clkd->r.num_rates) {
first = clkd->tot_rates - 1;
last = clkd->tot_rates - 1;
ret = ph->hops->iter_response_run_bound(iter, &first, &last);
@@ -618,16 +622,16 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph,
if (ret)
return ret;
- clkd->info.min_rate = clkd->rates[RATE_MIN];
- if (!clkd->rate_discrete) {
- clkd->info.max_rate = clkd->rates[RATE_MAX];
+ clkd->info.min_rate = clkd->r.rates[RATE_MIN];
+ if (!clkd->r.rate_discrete) {
+ clkd->info.max_rate = clkd->r.rates[RATE_MAX];
dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",
- clkd->rates[RATE_MIN], clkd->rates[RATE_MAX],
- clkd->rates[RATE_STEP]);
+ clkd->r.rates[RATE_MIN], clkd->r.rates[RATE_MAX],
+ clkd->r.rates[RATE_STEP]);
} else {
- clkd->info.max_rate = clkd->rates[clkd->num_rates - 1];
+ clkd->info.max_rate = clkd->r.rates[clkd->r.num_rates - 1];
dev_dbg(ph->dev, "Clock:%s DISCRETE:%d -> Min %llu Max %llu\n",
- clkd->info.name, clkd->rate_discrete,
+ clkd->info.name, clkd->r.rate_discrete,
clkd->info.min_rate, clkd->info.max_rate);
}
@@ -732,7 +736,7 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
* If we can't figure out what rate it will be, so just return the
* rate back to the caller.
*/
- if (clkd->rate_discrete)
+ if (clkd->r.rate_discrete)
return 0;
fmin = clk->min_rate;
@@ -746,14 +750,40 @@ static int scmi_clock_determine_rate(const struct scmi_protocol_handle *ph,
}
ftmp = *rate - fmin;
- ftmp += clkd->rates[RATE_STEP] - 1; /* to round up */
- ftmp = div64_ul(ftmp, clkd->rates[RATE_STEP]);
+ ftmp += clkd->r.rates[RATE_STEP] - 1; /* to round up */
+ ftmp = div64_ul(ftmp, clkd->r.rates[RATE_STEP]);
- *rate = ftmp * clkd->rates[RATE_STEP] + fmin;
+ *rate = ftmp * clkd->r.rates[RATE_STEP] + fmin;
return 0;
}
+static const struct scmi_clock_rates *
+scmi_clock_all_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id)
+{
+ struct clock_info *ci = ph->get_priv(ph);
+ struct scmi_clock_desc *clkd;
+ struct scmi_clock_info *clk;
+
+ clk = scmi_clock_domain_lookup(ci, clk_id);
+ if (IS_ERR(clk) || !clk->name[0])
+ return NULL;
+
+ clkd = to_desc(clk);
+ /* Needs full enumeration ? */
+ if (clkd->r.rate_discrete && clkd->tot_rates != clkd->r.num_rates) {
+ int ret;
+
+ /* rates[] is already allocated BUT we need to re-enumerate */
+ clkd->r.num_rates = 0;
+ ret = scmi_clock_describe_rates_get_full(ph, clkd);
+ if (ret)
+ return NULL;
+ }
+
+ return &clkd->r;
+}
+
static int
scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,
enum clk_state state,
@@ -1067,6 +1097,7 @@ static const struct scmi_clk_proto_ops clk_proto_ops = {
.rate_get = scmi_clock_rate_get,
.rate_set = scmi_clock_rate_set,
.determine_rate = scmi_clock_determine_rate,
+ .all_rates_get = scmi_clock_all_rates_get,
.enable = scmi_clock_enable,
.disable = scmi_clock_disable,
.state_get = scmi_clock_state_get,
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 5552ac04c820..c710107c2120 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -40,6 +40,12 @@ struct scmi_revision_info {
char sub_vendor_id[SCMI_SHORT_NAME_MAX_SIZE];
};
+struct scmi_clock_rates {
+ bool rate_discrete;
+ unsigned int num_rates;
+ u64 *rates;
+};
+
struct scmi_clock_info {
char name[SCMI_MAX_STR_SIZE];
unsigned int enable_latency;
@@ -85,6 +91,7 @@ enum scmi_clock_oem_config {
* clock calculating the closest allowed rate.
* Note that @rate is an input/output parameter used both to
* describe the requested rate and report the closest match
+ * @all_rates_get: get the list of all available rates for the specified clock.
* @enable: enables the specified clock
* @disable: disables the specified clock
* @state_get: get the status of the specified clock
@@ -104,6 +111,8 @@ struct scmi_clk_proto_ops {
u64 rate);
int (*determine_rate)(const struct scmi_protocol_handle *ph, u32 clk_id,
unsigned long *rate);
+ const struct scmi_clock_rates __must_check *(*all_rates_get)
+ (const struct scmi_protocol_handle *ph, u32 clk_id);
int (*enable)(const struct scmi_protocol_handle *ph, u32 clk_id,
bool atomic);
int (*disable)(const struct scmi_protocol_handle *ph, u32 clk_id,
--
2.53.0
^ permalink raw reply related [flat|nested] 22+ messages in thread* Re: [PATCH v3 00/15] SCMI Clock rates discovery rework
2026-04-28 20:15 [PATCH v3 00/15] SCMI Clock rates discovery rework Cristian Marussi
` (14 preceding siblings ...)
2026-04-28 20:15 ` [PATCH v3 15/15] firmware: arm_scmi: Introduce all_rates_get clock operation Cristian Marussi
@ 2026-04-29 15:39 ` Florian Fainelli
15 siblings, 0 replies; 22+ messages in thread
From: Florian Fainelli @ 2026-04-29 15:39 UTC (permalink / raw)
To: Cristian Marussi, linux-kernel, linux-arm-kernel, arm-scmi,
linux-clk, linux-renesas-soc
Cc: sudeep.holla, philip.radford, james.quinlan, vincent.guittot,
etienne.carriere, peng.fan, michal.simek, geert+renesas,
kuninori.morimoto.gx, marek.vasut+renesas
On 4/28/2026 1:15 PM, Cristian Marussi wrote:
> Hi,
>
> it was a known limitation, in the SCMI Clock protocol support, the lack of
> dynamic allocation around per-clock rates discovery: fixed size statically
> per-clock rates arrays did not scale and was increasingly a waste of memory
> (see [1]).
>
> This series aim at solving this in successive steps:
>
> - simplify and reduce to the minimum possible the rates data info exposed
> to the SCMI driver by scmi_clock_info
> - move away from static fixed allocation of per-clock rates arrays in
> favour of a completely dynamic runtime allocation: just allocate what
> is needed based on the effectively discovered
>
> This is done in patches 2-6.
>
> A further bigger optimization suggested in a past series [2] by Etienne
> would be, whenever allowed by the spec, to limit upfront the number of
> queries in order to simply retrieve min and max rate, that are indeed the
> only rates needed by the CLK SCMI driver.
>
> The approach proposed in [1] was open coding and duplicating some of the
> functionalities already provided by SCMI iterators, though.
>
> Patch 7-14 implement such optimization instead by:
>
> - reworking core SCMI iterators to support bound enumerations
> - use such new bound iterators to perform the minimum number of queries
> in order to only retrieve min an max rate
>
> As a final result now the rates enumeration triggered by the CLK SCMI
> driver, while still allocating for all the existent rates, miminize the
> number of SCMI CLK_DESCRIBE_RATE messages needed to obtain min and max.
>
> Finally, patch 15 introduces a new clock protocol operation to be able to
> trigger anytime on demand a full enumeration and obtain the full list of
> rates when needed, not only min/max: this latter method is really only used
> currently by some dowstream SCMI Test driver of mine.
>
> Most notably in this V3 I had:
>
> - picked up Geert fixes on V2: these could have been squashed in the
> original series while maintaining proper Geert's authorship but as of
> now I have simply picked them up and changed their order to be near the
> commit they fix
>
> - dropped the "Harden Clock protocol initialization" patch that caused a
> number of out-of-spec vendor FW to break
>
> Based on v7.1-rc1.
> Tested on ARM/JUNO, RADXA/ROCK5B and an emulated environment.
Tested-by: Florian Fainelli <florian.fainelli@broadcom.com>
--
Florian
^ permalink raw reply [flat|nested] 22+ messages in thread