diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2026-10-12 13:47:24 +0200 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2026-10-12 13:47:24 +0200 |
| commit | b85cc49bc29895673ceb2f85370cb8af34768170 (patch) | |
| tree | e042223d7c47c24587034dcdd5b7c297c2d6a672 /arch/x86/kernel | |
| parent | 85a6229f08d4d9f17441413f5c43fb2dc2286e15 (diff) | |
| parent | 6b64d65c83688db2e58fbd9de7c74090f15271b7 (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.c | 166 |
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); |
