mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
firmware: arm_scmi: Use bound iterators to minimize discovered rates
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> Link: https://patch.msgid.link/20260508153300.2224715-14-cristian.marussi@arm.com Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
This commit is contained in:
parent
3065e26dac
commit
26d04d592a
|
|
@ -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_bound_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 Num_Rates:%u -> Min %llu Max %llu\n",
|
||||
clkd->info.name, clkd->tot_rates,
|
||||
clkd->info.min_rate, clkd->info.max_rate);
|
||||
}
|
||||
clkd->info.min_rate = clkd->rates[RATE_MIN];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user