Commit 2d8781ba authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'scmi-fixes-6.7' of...

Merge tag 'scmi-fixes-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes

Arm SCMI fixes for v6.7

A fix for possible truncation/overflow in the frequency computations
as both the performance value and the multiplier are 32bit values.

* tag 'scmi-fixes-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Fix possible frequency truncation when using level indexing mode
  firmware: arm_scmi: Fix frequency truncation by promoting multiplier type

Link: https://lore.kernel.org/r/20231204134724.30465-1-sudeep.holla@arm.comSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 437c99c2 77f5032e
......@@ -152,7 +152,7 @@ struct perf_dom_info {
u32 opp_count;
u32 sustained_freq_khz;
u32 sustained_perf_level;
u32 mult_factor;
unsigned long mult_factor;
struct scmi_perf_domain_info info;
struct scmi_opp opp[MAX_OPPS];
struct scmi_fc_info *fc_info;
......@@ -268,13 +268,14 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
dom_info->sustained_perf_level =
le32_to_cpu(attr->sustained_perf_level);
if (!dom_info->sustained_freq_khz ||
!dom_info->sustained_perf_level)
!dom_info->sustained_perf_level ||
dom_info->level_indexing_mode)
/* CPUFreq converts to kHz, hence default 1000 */
dom_info->mult_factor = 1000;
else
dom_info->mult_factor =
(dom_info->sustained_freq_khz * 1000) /
dom_info->sustained_perf_level;
(dom_info->sustained_freq_khz * 1000UL)
/ dom_info->sustained_perf_level;
strscpy(dom_info->info.name, attr->name,
SCMI_SHORT_NAME_MAX_SIZE);
}
......@@ -798,7 +799,7 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
if (!dom->level_indexing_mode)
freq = dom->opp[idx].perf * dom->mult_factor;
else
freq = dom->opp[idx].indicative_freq * 1000;
freq = dom->opp[idx].indicative_freq * dom->mult_factor;
data.level = dom->opp[idx].perf;
data.freq = freq;
......@@ -845,7 +846,8 @@ static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain,
} else {
struct scmi_opp *opp;
opp = LOOKUP_BY_FREQ(dom->opps_by_freq, freq / 1000);
opp = LOOKUP_BY_FREQ(dom->opps_by_freq,
freq / dom->mult_factor);
if (!opp)
return -EIO;
......@@ -879,7 +881,7 @@ static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain,
if (!opp)
return -EIO;
*freq = opp->indicative_freq * 1000;
*freq = opp->indicative_freq * dom->mult_factor;
}
return ret;
......@@ -902,7 +904,7 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
if (!dom->level_indexing_mode)
opp_freq = opp->perf * dom->mult_factor;
else
opp_freq = opp->indicative_freq * 1000;
opp_freq = opp->indicative_freq * dom->mult_factor;
if (opp_freq < *freq)
continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment