[PATCH 11/11] firmware: arm_scmi: Introduce all_rates_get clock operation
Peng Fan
peng.fan at oss.nxp.com
Fri Feb 27 18:49:47 PST 2026
On Fri, Feb 27, 2026 at 03:32:25PM +0000, Cristian Marussi wrote:
>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.
>
>Signed-off-by: Cristian Marussi <cristian.marussi at arm.com>
>---
> 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 a0de10652abe..c2fd9a1c3316 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)
Not understand well "PROTOCOL_REV_MAJOR(ph->version) == 0x1", I may
get something wrong, should use ">="?
>+ sort(clkd->r.rates, clkd->r.num_rates,
>+ sizeof(clkd->r.rates[0]), rate_cmp_func, NULL);
>
Regards
Peng
More information about the linux-arm-kernel
mailing list