summaryrefslogtreecommitdiff
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-10-12 13:47:24 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-10-12 13:47:24 +0200
commitb85cc49bc29895673ceb2f85370cb8af34768170 (patch)
treee042223d7c47c24587034dcdd5b7c297c2d6a672 /arch/x86/kernel
parent85a6229f08d4d9f17441413f5c43fb2dc2286e15 (diff)
parent6b64d65c83688db2e58fbd9de7c74090f15271b7 (diff)
Merge tag 'amd-pstate-v7.4-2026-10-14' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux
Pull amd-pstate content for 7.4 (10/4/26) from Mario Limonciello: "* Fixups for a few bugs identified by Sashiko * Initial support for maximum frequency capacity handling on Zen6 / client * Updated EPP tunings for Zen6 / client"
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/acpi/cppc.c166
1 files changed, 110 insertions, 56 deletions
diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c
index bbade0da5130..f230e9323187 100644
--- a/arch/x86/kernel/acpi/cppc.c
+++ b/arch/x86/kernel/acpi/cppc.c
@@ -10,6 +10,7 @@
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/topology.h>
+#include <asm/cpu_device_id.h>
#define CPPC_HIGHEST_PERF_PERFORMANCE 196
#define CPPC_HIGHEST_PERF_PREFCORE 166
@@ -81,31 +82,18 @@ int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
static void amd_set_max_freq_ratio(void)
{
- struct cppc_perf_caps perf_caps;
- u64 numerator, nominal_perf;
+ u64 numerator, denominator;
u64 perf_ratio;
int rc;
- rc = cppc_get_perf_caps(0, &perf_caps);
- if (rc) {
- pr_debug("Could not retrieve perf counters (%d)\n", rc);
- return;
- }
-
- rc = amd_get_boost_ratio_numerator(0, &numerator);
+ rc = amd_get_boost_ratio(0, &numerator, &denominator);
if (rc) {
- pr_debug("Could not retrieve highest performance (%d)\n", rc);
- return;
- }
- nominal_perf = perf_caps.nominal_perf;
-
- if (!nominal_perf) {
- pr_debug("Could not retrieve nominal performance\n");
+ pr_debug("Could not retrieve boost ratio (%d)\n", rc);
return;
}
/* midpoint between max_boost and max_P */
- perf_ratio = (div_u64(numerator * SCHED_CAPACITY_SCALE, nominal_perf) + SCHED_CAPACITY_SCALE) >> 1;
+ perf_ratio = (div_u64(numerator * SCHED_CAPACITY_SCALE, denominator) + SCHED_CAPACITY_SCALE) >> 1;
freq_invariance_set_perf_ratio(perf_ratio, false);
}
@@ -225,35 +213,30 @@ int amd_detect_prefcore(bool *detected)
EXPORT_SYMBOL_GPL(amd_detect_prefcore);
/**
- * amd_get_boost_ratio_numerator: Get the numerator to use for boost ratio calculation
- * @cpu: CPU to get numerator for.
- * @numerator: Output variable for numerator.
- *
- * Determine the numerator to use for calculating the boost ratio on
- * a CPU. On systems that support preferred cores, this will be a hardcoded
- * value. On other systems this will the highest performance register value.
+ * amd_get_effective_highest_perf: Get the effective highest performance value
+ * @cpu: CPU to get highest performance for.
*
- * If booting the system with amd-pstate enabled but preferred cores disabled then
- * the correct boost numerator will be returned to match hardware capabilities
- * even if the preferred cores scheduling hints are not enabled.
+ * Get the effective highest performance value for a CPU, accounting for
+ * preferred cores and heterogeneous topologies. On systems with preferred
+ * cores, this may be a hardcoded value. On heterogeneous systems, this
+ * may be a per-CPU value. On other systems, this is the shared highest
+ * performance value.
*
- * Return: 0 for success, negative error code otherwise.
+ * Return: Effective highest performance value, or negative error code.
*/
-int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
+int amd_get_effective_highest_perf(unsigned int cpu)
{
bool prefcore;
int ret;
u32 tmp;
ret = amd_detect_prefcore(&prefcore);
- if (ret)
+ if (ret < 0)
return ret;
/* without preferred cores, return the highest perf register value */
- if (!prefcore) {
- *numerator = boost_numerator;
- return 0;
- }
+ if (!prefcore)
+ return boost_numerator;
/*
* For AMD CPUs with Family ID 19H and Model ID range 0x70 to 0x7f,
@@ -263,8 +246,7 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
if (cpu_feature_enabled(X86_FEATURE_ZEN4)) {
switch (boot_cpu_data.x86_model) {
case 0x70 ... 0x7f:
- *numerator = CPPC_HIGHEST_PERF_PERFORMANCE;
- return 0;
+ return CPPC_HIGHEST_PERF_PERFORMANCE;
default:
break;
}
@@ -272,28 +254,100 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
/* detect if running on heterogeneous design */
if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) {
- switch (cpu_data(cpu).topo.cpu_type) {
- case TOPO_CPU_TYPE_UNKNOWN:
- case TOPO_CPU_TYPE_ANY:
- pr_warn("Undefined core type found for cpu %d\n", cpu);
- break;
- case TOPO_CPU_TYPE_PERFORMANCE:
- /* use the max scale for performance cores */
- *numerator = CPPC_HIGHEST_PERF_PERFORMANCE;
- return 0;
- case TOPO_CPU_TYPE_LOW_POWER:
- case TOPO_CPU_TYPE_EFFICIENCY:
- /* use the highest perf value for efficiency and low-power cores */
- ret = amd_get_highest_perf(cpu, &tmp);
- if (ret)
- return ret;
- *numerator = tmp;
- return 0;
- }
+ if (cpu_feature_enabled(X86_FEATURE_ZEN5) &&
+ cpu_data(cpu).topo.cpu_type == TOPO_CPU_TYPE_PERFORMANCE)
+ return CPPC_HIGHEST_PERF_PERFORMANCE;
+
+ /* Zen 5 efficiency, and Zen 6+ */
+ ret = amd_get_highest_perf(cpu, &tmp);
+ if (ret < 0)
+ return ret;
+
+ return tmp;
+ }
+
+ return CPPC_HIGHEST_PERF_PREFCORE;
+}
+EXPORT_SYMBOL_GPL(amd_get_effective_highest_perf);
+
+struct amd_max_freq {
+ u32 performance;
+ u32 efficiency;
+ u32 low_power;
+};
+
+static const struct amd_max_freq max_freq_zen6_client = {
+ .performance = 5025,
+ .efficiency = 3524,
+ .low_power = 2399,
+};
+
+int amd_get_max_frequency(unsigned int cpu)
+{
+ enum x86_topology_cpu_type type = cpu_data(cpu).topo.cpu_type;
+ const struct amd_max_freq *max_freq = NULL;
+
+ if (cpu_feature_enabled(X86_FEATURE_ZEN6) &&
+ cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES))
+ max_freq = &max_freq_zen6_client;
+
+ if (!max_freq)
+ return 0;
+
+ switch (type) {
+ case TOPO_CPU_TYPE_PERFORMANCE:
+ return max_freq->performance;
+ case TOPO_CPU_TYPE_EFFICIENCY:
+ return max_freq->efficiency;
+ case TOPO_CPU_TYPE_LOW_POWER:
+ return max_freq->low_power;
+ default:
+ break;
}
- *numerator = CPPC_HIGHEST_PERF_PREFCORE;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(amd_get_max_frequency);
+
+/**
+ * amd_get_boost_ratio: Get numerator and denominator for boost ratio
+ * @cpu: CPU to get the boost ratio for.
+ * @numerator: Output variable for numerator.
+ * @denominator: Output variable for denominator.
+ *
+ * Get the numerator and denominator for calculating the boost ratio.
+ *
+ * Return: 0 for success, negative error code otherwise.
+ */
+int amd_get_boost_ratio(unsigned int cpu, u64 *numerator, u64 *denominator)
+{
+ struct cppc_perf_caps perf_caps;
+ int max_frequency;
+ int ret;
+
+ ret = cppc_get_perf_caps(cpu, &perf_caps);
+ if (ret)
+ return ret;
+
+ max_frequency = amd_get_max_frequency(cpu);
+ /* Use frequency values if available */
+ if (max_frequency && perf_caps.nominal_freq) {
+ *numerator = max_frequency;
+ *denominator = perf_caps.nominal_freq;
+ return 0;
+ }
+
+ /* Fall back to performance values */
+ ret = amd_get_effective_highest_perf(cpu);
+ if (ret < 0)
+ return ret;
+
+ *numerator = ret;
+
+ *denominator = perf_caps.nominal_perf;
+ if (!*denominator)
+ return -EINVAL;
return 0;
}
-EXPORT_SYMBOL_GPL(amd_get_boost_ratio_numerator);
+EXPORT_SYMBOL_GPL(amd_get_boost_ratio);