Unverified Commit 2d8781ba authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

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.com


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 437c99c2 77f5032e
Loading
Loading
Loading
Loading
+10 −8
Original line number Diff line number Diff line
@@ -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;