Thread (4 messages) 4 messages, 2 authors, 2021-11-16
STALE1709d

[PATCH v1] cpufreq: CPPC: Fix performance/frequency conversion

From: Pierre Gondois <Pierre.Gondois@arm.com>
Date: 2021-10-22 07:51:21
Also in: lkml
Subsystem: cpu frequency drivers - cppc cpufreq, cpu frequency scaling framework, the rest · Maintainers: "Rafael J. Wysocki", Viresh Kumar, Linus Torvalds

CPUfreq governors request CPU frequencies using information
on current CPU usage. The CPPC driver converts them to
performance requests. Frequency targets are computed as:
  target_freq = (util / cpu_capacity) * max_freq
target_freq is then clamped between [policy->min, policy->max].

The CPPC driver converts performance values to frequencies
(and vice-versa) using cppc_cpufreq_perf_to_khz() and
cppc_cpufreq_khz_to_perf(). These functions both use two different
factors depending on the range of the input value. For
cppc_cpufreq_khz_to_perf():
- (NOMINAL_PERF / NOMINAL_FREQ) or
- (LOWEST_PERF / LOWEST_FREQ)
and for cppc_cpufreq_perf_to_khz():
- (NOMINAL_FREQ / NOMINAL_PERF) or
- ((NOMINAL_PERF - LOWEST_FREQ) / (NOMINAL_PERF - LOWEST_PERF))

This means the functions are not inverse for some values:
(perf_to_khz(khz_to_perf(x)) != x)

This patch makes use of one single conversion factor, being
(MAX_PERF / MAX_FREQ).

As LOWEST_FREQ is not used during conversion, the LOWEST_FREQ
advertised through policy->cpuinfo.min_freq might be different
from the LOWEST_FREQ value available in the CPPC object,
but the conversion will be correct.

Suggested-by: Lukasz Luba <lukasz.luba@arm.com>
Suggested-by: Morten Rasmussen <redacted>
Signed-off-by: Pierre Gondois <Pierre.Gondois@arm.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 33 ++++++++++-----------------------
 1 file changed, 10 insertions(+), 23 deletions(-)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index d4c27022b9c9..d2ac74e7701e 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -302,13 +302,10 @@ static u64 cppc_get_dmi_max_khz(void)
 }
 
 /*
- * If CPPC lowest_freq and nominal_freq registers are exposed then we can
- * use them to convert perf to freq and vice versa
- *
- * If the perf/freq point lies between Nominal and Lowest, we can treat
- * (Low perf, Low freq) and (Nom Perf, Nom freq) as 2D co-ordinates of a line
- * and extrapolate the rest
- * For perf/freq > Nominal, we use the ratio perf:freq at Nominal for conversion
+ * The CPPC driver receives frequency requests and translates them to performance
+ * requests. Thus, frequency values are actually performance values on a frequency
+ * scale. The conversion is done as:
+ * target_freq = target_perf * (nominal_freq / nominal_perf)
  */
 static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu_data,
 					     unsigned int perf)
@@ -317,14 +314,9 @@ static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu_data,
 	static u64 max_khz;
 	u64 mul, div;
 
-	if (caps->lowest_freq && caps->nominal_freq) {
-		if (perf >= caps->nominal_perf) {
-			mul = caps->nominal_freq;
-			div = caps->nominal_perf;
-		} else {
-			mul = caps->nominal_freq - caps->lowest_freq;
-			div = caps->nominal_perf - caps->lowest_perf;
-		}
+	if (caps->nominal_freq) {
+		mul = caps->nominal_freq;
+		div = caps->nominal_perf;
 	} else {
 		if (!max_khz)
 			max_khz = cppc_get_dmi_max_khz();
@@ -341,14 +333,9 @@ static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu_data,
 	static u64 max_khz;
 	u64  mul, div;
 
-	if (caps->lowest_freq && caps->nominal_freq) {
-		if (freq >= caps->nominal_freq) {
-			mul = caps->nominal_perf;
-			div = caps->nominal_freq;
-		} else {
-			mul = caps->lowest_perf;
-			div = caps->lowest_freq;
-		}
+	if (caps->nominal_freq) {
+		mul = caps->nominal_perf;
+		div = caps->nominal_freq;
 	} else {
 		if (!max_khz)
 			max_khz = cppc_get_dmi_max_khz();
-- 
2.17.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help