aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/intel_pstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpufreq/intel_pstate.c')
-rw-r--r--drivers/cpufreq/intel_pstate.c65
1 files changed, 55 insertions, 10 deletions
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 2548ec92faa2..dc50c9fb488d 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -302,6 +302,13 @@ static bool hwp_forced __read_mostly;
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
+#define HYBRID_SCALING_FACTOR 78741
+
+static inline int core_get_scaling(void)
+{
+ return 100000;
+}
+
#ifdef CONFIG_ACPI
static bool acpi_ppc;
#endif
@@ -400,6 +407,26 @@ static int intel_pstate_get_cppc_guaranteed(int cpu)
return cppc_perf.nominal_perf;
}
+
+static int intel_pstate_cppc_get_scaling(int cpu)
+{
+ struct cppc_perf_caps cppc_perf;
+ int ret;
+
+ ret = cppc_get_perf_caps(cpu, &cppc_perf);
+
+ /*
+ * If the nominal frequency and the nominal performance are not
+ * zero and the ratio between them is not 100, return the hybrid
+ * scaling factor.
+ */
+ if (!ret && cppc_perf.nominal_perf && cppc_perf.nominal_freq &&
+ cppc_perf.nominal_perf * 100 != cppc_perf.nominal_freq)
+ return HYBRID_SCALING_FACTOR;
+
+ return core_get_scaling();
+}
+
#else /* CONFIG_ACPI_CPPC_LIB */
static inline void intel_pstate_set_itmt_prio(int cpu)
{
@@ -492,6 +519,11 @@ static inline int intel_pstate_get_cppc_guaranteed(int cpu)
{
return -ENOTSUPP;
}
+
+static int intel_pstate_cppc_get_scaling(int cpu)
+{
+ return core_get_scaling();
+}
#endif /* CONFIG_ACPI_CPPC_LIB */
/**
@@ -824,6 +856,8 @@ static ssize_t store_energy_performance_preference(
err = cpufreq_start_governor(policy);
if (!ret)
ret = err;
+ } else {
+ ret = 0;
}
}
@@ -1895,11 +1929,6 @@ static int core_get_turbo_pstate(int cpu)
return ret;
}
-static inline int core_get_scaling(void)
-{
- return 100000;
-}
-
static u64 core_get_val(struct cpudata *cpudata, int pstate)
{
u64 val;
@@ -1936,16 +1965,28 @@ static void hybrid_get_type(void *data)
*cpu_type = get_this_hybrid_cpu_type();
}
-static int hybrid_get_cpu_scaling(int cpu)
+static int hwp_get_cpu_scaling(int cpu)
{
u8 cpu_type = 0;
smp_call_function_single(cpu, hybrid_get_type, &cpu_type, 1);
/* P-cores have a smaller perf level-to-freqency scaling factor. */
if (cpu_type == 0x40)
- return 78741;
+ return HYBRID_SCALING_FACTOR;
- return core_get_scaling();
+ /* Use default core scaling for E-cores */
+ if (cpu_type == 0x20)
+ return core_get_scaling();
+
+ /*
+ * If reached here, this system is either non-hybrid (like Tiger
+ * Lake) or hybrid-capable (like Alder Lake or Raptor Lake) with
+ * no E cores (in which case CPUID for hybrid support is 0).
+ *
+ * The CPPC nominal_frequency field is 0 for non-hybrid systems,
+ * so the default core scaling will be used for them.
+ */
+ return intel_pstate_cppc_get_scaling(cpu);
}
static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
@@ -2568,6 +2609,11 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
intel_pstate_clear_update_util_hook(policy->cpu);
intel_pstate_hwp_set(policy->cpu);
}
+ /*
+ * policy->cur is never updated with the intel_pstate driver, but it
+ * is used as a stale frequency value. So, keep it within limits.
+ */
+ policy->cur = policy->min;
mutex_unlock(&intel_pstate_limits_lock);
@@ -3393,8 +3439,7 @@ static int __init intel_pstate_init(void)
if (!default_driver)
default_driver = &intel_pstate;
- if (boot_cpu_has(X86_FEATURE_HYBRID_CPU))
- pstate_funcs.get_cpu_scaling = hybrid_get_cpu_scaling;
+ pstate_funcs.get_cpu_scaling = hwp_get_cpu_scaling;
goto hwp_cpu_matched;
}