Add CPPC HighestFreq support
Subsystems (7)
cover Add CPPC HighestFreq support
On some systems, the boost ratio cannot be accurately calculated using linear interpolation of CPPC performance values because the performance-to-frequency mapping is not linear across all cores.
This series introduces support for the CPPC HighestFreq register. This register is under a proposal with ASWG at the moment and trending for inclusion in ACPI 6.7.
This optionally provides the actual highest frequency eliminating the need for interpolation. When available, this frequency value is used for more accurate CPU capacity calculations and boost ratio determination.
This series brings the existing CPPC definitions up to ACPI 6.6 and then adds support for the ACPI 6.7 proposal.
Mario Limonciello (6):
Revert "ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio()
to warn"
ACPI: Add CPPC v4 definitions
ACPI: CPPC: Add support for reading HighestFreq
ACPI: CPPC: Refactor boost ratio handling cpufreq/acpi-cpufreq: Use amd_get_boost_ratio() cpufreq/amd-pstate: Get highest freq from CPPC if available
arch/x86/kernel/acpi/cppc.c | 122 ++++++++++++++++++--------------- drivers/acpi/cppc_acpi.c | 39 ++++++++--- drivers/cpufreq/acpi-cpufreq.c | 17 +++-- drivers/cpufreq/amd-pstate.c | 18 +++-- include/acpi/cppc_acpi.h | 27 ++++++-- 5 files changed, 139 insertions(+), 84 deletions(-)
Signature · 1 line
2.43.0
PATCH 1/6 Revert "ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio() to warn"
Some older systems don't support CPPC in the firmware and this just makes noise for them when booting. Drop back to debug.
This reverts commit 21fb59ab4b9767085f4fe1edbdbe3177fbb9ec97.
--- arch/x86/kernel/acpi/cppc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/acpi/cppc.c +3 -3
@@ -88,19 +88,19 @@ static void amd_set_max_freq_ratio(void) rc =cppc_get_perf_caps (0 , &perf_caps);if (rc) { -pr_warn ("Could not retrieve perf counters (%d)\n" , rc); +pr_debug ("Could not retrieve perf counters (%d)\n" , rc);return ; } rc =amd_get_boost_ratio_numerator (0 , &numerator);if (rc) { -pr_warn ("Could not retrieve highest performance (%d)\n" , rc); +pr_debug ("Could not retrieve highest performance (%d)\n" , rc);return ; } nominal_perf = perf_caps.nominal_perf;if (!nominal_perf) { -pr_warn ("Could not retrieve nominal performance\n" ); +pr_debug ("Could not retrieve nominal performance\n" );return ; }
Signature · 1 line
2.43.0
PATCH 2/6 ACPI: Add CPPC v4 definitions
In reply to Mario Limonciello (AMD)ACPI 6.6 introduced new optional package values for OSPMNominalPerformanceRegister and ResourcePriorityRegisters.
Add these into the defines. As they're not used right now they are not wired up to anything at this time.
--- drivers/acpi/cppc_acpi.c | 16 ++++++++++++---- include/acpi/cppc_acpi.h | 13 +++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +12 -4
@@ -755,14 +755,15 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)*/ if ((cpc_rev ==CPPC_V2_REV && num_ent !=CPPC_V2_NUM_ENT ) || (cpc_rev ==CPPC_V3_REV && num_ent !=CPPC_V3_NUM_ENT ) || - (cpc_rev >CPPC_V3_REV && num_ent <=CPPC_V3_NUM_ENT )) { + (cpc_rev ==CPPC_V4_REV && num_ent !=CPPC_V4_NUM_ENT ) || + (cpc_rev >CPPC_V4_REV && num_ent <=CPPC_V4_NUM_ENT )) {pr_debug ("Unexpected number of _CPC return package entries (%d) for CPU:%d\n" , num_ent, pr->id); goto out_free; } -if (cpc_rev >CPPC_V3_REV ) { - num_ent =CPPC_V3_NUM_ENT ; - cpc_rev =CPPC_V3_REV ; +if (cpc_rev >CPPC_V4_REV ) { + num_ent =CPPC_V4_NUM_ENT ; + cpc_rev =CPPC_V4_REV ; } cpc_ptr->num_entries = num_ent;
@@ -845,6 +846,13 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_BUFFER ;memcpy (&cpc_ptr->cpc_regs[i-2 ].cpc_entry.reg, gas_t,sizeof (*gas_t)); + }else if (cpc_obj->type ==ACPI_TYPE_PACKAGE ) { +/* +* CPPC v4 ResourcePriorityRegisters is a Package. +* Store NULL for now as it's not wired up to anything. +*/ + cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_PACKAGE ; + cpc_ptr->cpc_regs[i-2 ].cpc_entry.pkg_data =NULL ; }else {pr_debug ("Invalid entry type (%d) in _CPC for CPU:%d\n" , i, pr->id);
include/acpi/cppc_acpi.h +9 -4
@@ -17,16 +17,18 @@#include <acpi/pcc.h> #include <acpi/processor.h> -/* CPPCv2 and CPPCv3 support */ +/* CPPC support */ #define CPPC_V2_REV 2#define CPPC_V3_REV 3 +#define CPPC_V4_REV 4#define CPPC_V2_NUM_ENT 21#define CPPC_V3_NUM_ENT 23 +#define CPPC_V4_NUM_ENT 25#define PCC_CMD_COMPLETE_MASK (1 << 0)#define PCC_ERROR_MASK (1 << 2) -#define MAX_CPC_REG_ENT 21 +#define MAX_CPC_REG_ENT 23/* CPPC specific PCC commands. */ #define CMD_READ 0
@@ -60,8 +62,8 @@ struct cpc_reg {/* * Each entry in the CPC table is either -* of type ACPI_TYPE_BUFFER or -* ACPI_TYPE_INTEGER. +* of type ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, +* or ACPI_TYPE_PACKAGE (for CPPC v4 ResourcePriorityRegisters). */ struct cpc_register_resource {acpi_object_type type;
@@ -69,6 +71,7 @@ struct cpc_register_resource {union {struct cpc_reg reg;u64 int_value; +void *pkg_data; } cpc_entry; };
@@ -109,6 +112,8 @@ enum cppc_regs {REFERENCE_PERF ,LOWEST_FREQ ,NOMINAL_FREQ , +OSPM_NOMINAL_PERF , + RESOURCE_PRIO, };/*
Signature · 1 line
2.43.0
Re: [PATCH 2/6] ACPI: Add CPPC v4 definitions
Quoted 9 lines · Mario Limonciello (AMD)
ACPI 6.6 introduced new optional package values for
OSPMNominalPerformanceRegisterandResourcePriorityRegisters.Add these into the defines. As they're not used right now they are not wired up to anything at this time.
This patch will be dropped in favor of Sumit's patches on the same subject.
https://lore.kernel.org/linux-acpi/[email protected]/
I will rebase the next version of the series on this instead.
Quoted 96 lines
--- drivers/acpi/cppc_acpi.c | 16 ++++++++++++---- include/acpi/cppc_acpi.h | 13 +++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-)drivers/acpi/cppc_acpi.c +12
-4@@ -755,14 +755,15 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)*/ if ((cpc_rev ==CPPC_V2_REV && num_ent !=CPPC_V2_NUM_ENT ) || (cpc_rev ==CPPC_V3_REV && num_ent !=CPPC_V3_NUM_ENT ) || - (cpc_rev >CPPC_V3_REV && num_ent <=CPPC_V3_NUM_ENT )) { + (cpc_rev ==CPPC_V4_REV && num_ent !=CPPC_V4_NUM_ENT ) || + (cpc_rev >CPPC_V4_REV && num_ent <=CPPC_V4_NUM_ENT )) {pr_debug ("Unexpected number of _CPC return package entries (%d) for CPU:%d\n" , num_ent, pr->id); goto out_free; } -if (cpc_rev >CPPC_V3_REV ) { - num_ent =CPPC_V3_NUM_ENT ; - cpc_rev =CPPC_V3_REV ; +if (cpc_rev >CPPC_V4_REV ) { + num_ent =CPPC_V4_NUM_ENT ; + cpc_rev =CPPC_V4_REV ; } cpc_ptr->num_entries = num_ent;@@ -845,6 +846,13 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_BUFFER ;memcpy (&cpc_ptr->cpc_regs[i-2 ].cpc_entry.reg, gas_t,sizeof (*gas_t)); + }else if (cpc_obj->type ==ACPI_TYPE_PACKAGE ) { +/* +* CPPC v4 ResourcePriorityRegisters is a Package. +* Store NULL for now as it's not wired up to anything. +*/ + cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_PACKAGE ; + cpc_ptr->cpc_regs[i-2 ].cpc_entry.pkg_data =NULL ; }else {pr_debug ("Invalid entry type (%d) in _CPC for CPU:%d\n" , i, pr->id);include/acpi/cppc_acpi.h +9
-4@@ -17,16 +17,18 @@#include <acpi/pcc.h> #include <acpi/processor.h> -/* CPPCv2 and CPPCv3 support */ +/* CPPC support */ #define CPPC_V2_REV 2#define CPPC_V3_REV 3 +#define CPPC_V4_REV 4#define CPPC_V2_NUM_ENT 21#define CPPC_V3_NUM_ENT 23 +#define CPPC_V4_NUM_ENT 25#define PCC_CMD_COMPLETE_MASK (1 << 0)#define PCC_ERROR_MASK (1 << 2) -#define MAX_CPC_REG_ENT 21 +#define MAX_CPC_REG_ENT 23/* CPPC specific PCC commands. */ #define CMD_READ 0@@ -60,8 +62,8 @@ struct cpc_reg {/* * Each entry in the CPC table is either -* of type ACPI_TYPE_BUFFER or -* ACPI_TYPE_INTEGER. +* of type ACPI_TYPE_BUFFER, ACPI_TYPE_INTEGER, +* or ACPI_TYPE_PACKAGE (for CPPC v4 ResourcePriorityRegisters). */ struct cpc_register_resource {acpi_object_type type;@@ -69,6 +71,7 @@ struct cpc_register_resource {union {struct cpc_reg reg;u64 int_value; +void *pkg_data; } cpc_entry; };@@ -109,6 +112,8 @@ enum cppc_regs {REFERENCE_PERF ,LOWEST_FREQ ,NOMINAL_FREQ , +OSPM_NOMINAL_PERF , + RESOURCE_PRIO, };/*
PATCH 3/6 ACPI: CPPC: Add support for reading HighestFreq
In reply to Mario Limonciello (AMD)A future revision of the ACPI specification will be including a definition for HighestFreq. Add support for reading it.
--- drivers/acpi/cppc_acpi.c | 31 +++++++++++++++++++++---------- include/acpi/cppc_acpi.h | 7 ++++++- 2 files changed, 27 insertions(+), 11 deletions(-)
drivers/acpi/cppc_acpi.c +21 -10
@@ -182,6 +182,7 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf);show_cppc_data (cppc_get_perf_caps, cppc_perf_caps, guaranteed_perf);show_cppc_data (cppc_get_perf_caps, cppc_perf_caps, lowest_freq);show_cppc_data (cppc_get_perf_caps, cppc_perf_caps, nominal_freq); +show_cppc_data (cppc_get_perf_caps, cppc_perf_caps, highest_freq);show_cppc_data (cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
@@ -222,6 +223,7 @@ static struct attribute *cppc_attrs[] = { &nominal_perf.attr, &nominal_freq.attr, &lowest_freq.attr, + &highest_freq.attr, NULL };ATTRIBUTE_GROUPS (cppc);
@@ -751,19 +753,20 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)/* * Disregard _CPC if the number of entries in the return package is not * as expected, but support future revisions being proper supersets of -* the v3 and only causing more entries to be returned by _CPC. +* the v4 and only causing more entries to be returned by _CPC. */ if ((cpc_rev ==CPPC_V2_REV && num_ent !=CPPC_V2_NUM_ENT ) || (cpc_rev ==CPPC_V3_REV && num_ent !=CPPC_V3_NUM_ENT ) || (cpc_rev ==CPPC_V4_REV && num_ent !=CPPC_V4_NUM_ENT ) || - (cpc_rev >CPPC_V4_REV && num_ent <=CPPC_V4_NUM_ENT )) { + (cpc_rev ==CPPC_V5_REV && num_ent !=CPPC_V5_NUM_ENT ) || + (cpc_rev >CPPC_V5_REV && num_ent <=CPPC_V5_NUM_ENT )) {pr_debug ("Unexpected number of _CPC return package entries (%d) for CPU:%d\n" , num_ent, pr->id); goto out_free; } -if (cpc_rev >CPPC_V4_REV ) { - num_ent =CPPC_V4_NUM_ENT ; - cpc_rev =CPPC_V4_REV ; +if (cpc_rev >CPPC_V5_REV ) { + num_ent =CPPC_V5_NUM_ENT ; + cpc_rev =CPPC_V5_REV ; } cpc_ptr->num_entries = num_ent;
@@ -1361,9 +1364,10 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpunum);struct cpc_register_resource *highest_reg, *lowest_reg, *lowest_non_linear_reg, *nominal_reg, *reference_reg, - *guaranteed_reg, *low_freq_reg =NULL , *nom_freq_reg =NULL ; + *guaranteed_reg, *low_freq_reg =NULL , *nom_freq_reg =NULL , + *highest_freq_reg =NULL ;u64 high, low, guaranteed, nom, ref, min_nonlinear, - low_f =0 , nom_f =0 ; + low_f =0 , nom_f =0 , high_f =0 ;int pcc_ss_id =per_cpu (cpu_pcc_subspace_idx, cpunum);struct cppc_pcc_data *pcc_ss_data =NULL ;int ret =0 , regs_in_pcc =0 ;
@@ -1380,6 +1384,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) reference_reg = &cpc_desc->cpc_regs[REFERENCE_PERF ]; low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ ]; nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ ]; + highest_freq_reg = &cpc_desc->cpc_regs[HIGHEST_FREQ ]; guaranteed_reg = &cpc_desc->cpc_regs[GUARANTEED_PERF ];/* Are any of the regs PCC ?*/
@@ -1387,7 +1392,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)CPC_IN_PCC (lowest_non_linear_reg) ||CPC_IN_PCC (nominal_reg) || (CPC_SUPPORTED (reference_reg) &&CPC_IN_PCC (reference_reg)) ||CPC_IN_PCC (low_freq_reg) ||CPC_IN_PCC (nom_freq_reg) || - CPC_IN_PCC(guaranteed_reg)) { + CPC_IN_PCC(guaranteed_reg) || CPC_IN_PCC(highest_freq_reg)) { if (pcc_ss_id < 0) {pr_debug ("Invalid pcc_ss_id\n" );return -ENODEV ;
@@ -1450,7 +1455,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) goto out_err; } -/* Read optional lowest and nominal frequencies if present */ +/* Read optional lowest, highest and nominal frequencies if present */ if (CPC_SUPPORTED (low_freq_reg)) { ret =cpc_read (cpunum, low_freq_reg, &low_f);if (ret)
@@ -1463,9 +1468,15 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) goto out_err; } +if (CPC_SUPPORTED (highest_freq_reg)) { + ret =cpc_read (cpunum, highest_freq_reg, &high_f); +if (ret) + goto out_err; + } + perf_caps->lowest_freq = low_f; perf_caps->nominal_freq = nom_f; - + perf_caps->highest_freq = high_f; out_err:if (regs_in_pcc)
include/acpi/cppc_acpi.h +6 -1
@@ -21,14 +21,16 @@#define CPPC_V2_REV 2#define CPPC_V3_REV 3#define CPPC_V4_REV 4 +#define CPPC_V5_REV 5#define CPPC_V2_NUM_ENT 21#define CPPC_V3_NUM_ENT 23#define CPPC_V4_NUM_ENT 25 +#define CPPC_V5_NUM_ENT 27#define PCC_CMD_COMPLETE_MASK (1 << 0)#define PCC_ERROR_MASK (1 << 2) -#define MAX_CPC_REG_ENT 23 +#define MAX_CPC_REG_ENT 25/* CPPC specific PCC commands. */ #define CMD_READ 0
@@ -114,6 +116,8 @@ enum cppc_regs {NOMINAL_FREQ ,OSPM_NOMINAL_PERF ,RESOURCE_PRIO , +HIGHEST_FREQ , + CURRENT_FREQ, };/*
@@ -131,6 +135,7 @@ struct cppc_perf_caps {u32 lowest_nonlinear_perf;u32 lowest_freq;u32 nominal_freq; +u32 highest_freq; };struct cppc_perf_ctrls {
Signature · 1 line
2.43.0
PATCH 4/6 ACPI: CPPC: Refactor boost ratio handling
In reply to Mario Limonciello (AMD)Rename amd_get_boost_ratio_numerator() to amd_get_effective_highest_perf() to better reflect that it returns the effective highest performance value for a CPU, accounting for preferred cores and heterogeneous topologies.
Add a new helper amd_get_boost_ratio() for doing both for boost ratio calculations and update callers to use it.
This refactoring is needed because on some AMD systems (Zen6+), the boost ratio should be calculated from frequency values rather than performance values.
--- arch/x86/kernel/acpi/cppc.c | 122 ++++++++++++++++++--------------- drivers/cpufreq/acpi-cpufreq.c | 5 +- drivers/cpufreq/amd-pstate.c | 12 ++-- include/acpi/cppc_acpi.h | 9 ++- 4 files changed, 86 insertions(+), 62 deletions(-)
arch/x86/kernel/acpi/cppc.c +68 -54
@@ -81,31 +81,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,21 +212,18 @@ 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. +* amd_get_effective_highest_perf: Get the effective highest performance value +* @cpu: CPU to get highest performance for. * -* 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. +* 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. * -* 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. -* -* 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) {enum x86_topology_cpu_type core_type =get_topology_cpu_type (&cpu_data (cpu));bool prefcore;
@@ -247,14 +231,12 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)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,
@@ -264,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 ; }
@@ -273,26 +254,59 @@ 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 (core_type) { -case TOPO_CPU_TYPE_UNKNOWN : -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_EFFICIENCY : -/* use the highest perf value for efficiency cores */ - ret =amd_get_highest_perf (cpu, &tmp); -if (ret) -return ret; - *numerator = tmp; -return 0 ; - } +if (cpu_feature_enabled (X86_FEATURE_ZEN5 ) && + core_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); + +/** +* 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 ret; + + ret =cppc_get_perf_caps (cpu, &perf_caps); +if (ret) +return ret; + +/* Use frequency values if available */ +if (perf_caps.highest_freq && perf_caps.nominal_freq) { + *numerator = perf_caps.highest_freq; + *denominator = perf_caps.nominal_freq; +return 0 ; } - *numerator =CPPC_HIGHEST_PERF_PREFCORE ; +/* 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);
drivers/cpufreq/acpi-cpufreq.c +3 -2
@@ -640,12 +640,13 @@ static u64 get_max_boost_ratio(unsigned int cpu, u64 *nominal_freq) }if (boot_cpu_data.x86_vendor ==X86_VENDOR_AMD ) { - ret =amd_get_boost_ratio_numerator (cpu, &highest_perf); -if (ret) { + ret =amd_get_effective_highest_perf (cpu); +if (ret <0 ) {pr_debug ("CPU%d: Unable to get boost ratio numerator (%d)\n" , cpu, ret);return 0 ; } + highest_perf = ret; }else { highest_perf = perf_caps.highest_perf; }
drivers/cpufreq/amd-pstate.c +8 -4
@@ -476,10 +476,12 @@ static int msr_init_perf(struct amd_cpudata *cpudata)if (ret)return ret; - ret =amd_get_boost_ratio_numerator (cpudata->cpu, &numerator); -if (ret) + ret =amd_get_effective_highest_perf (cpudata->cpu); +if (ret <0 )return ret; + numerator = ret; + ret =rdmsrl_on_cpu (cpudata->cpu,MSR_AMD_CPPC_REQ , &cppc_req);if (ret)return ret;
@@ -520,10 +522,12 @@ static int shmem_init_perf(struct amd_cpudata *cpudata)if (ret)return ret; - ret =amd_get_boost_ratio_numerator (cpudata->cpu, &numerator); -if (ret) + ret =amd_get_effective_highest_perf (cpudata->cpu); +if (ret <0 )return ret; + numerator = ret; + perf.highest_perf = numerator; perf.max_limit_perf = numerator; perf.min_limit_perf = cppc_perf.lowest_perf;
include/acpi/cppc_acpi.h +7 -2
@@ -193,7 +193,8 @@ extern int cppc_set_auto_sel(int cpu, bool enable);extern int cppc_get_perf_limited (int cpu,u64 *perf_limited);extern int cppc_set_perf_limited (int cpu,u64 bits_to_clear);extern int amd_get_highest_perf (unsigned int cpu,u32 *highest_perf); -extern int amd_get_boost_ratio_numerator (unsigned int cpu,u64 *numerator); +extern int amd_get_effective_highest_perf (unsigned int cpu); +extern int amd_get_boost_ratio (unsigned int cpu,u64 *numerator,u64 *denominator);extern int amd_detect_prefcore (bool *detected);#else /* !CONFIG_ACPI_CPPC_LIB */ static inline int cppc_get_desired_perf (int cpunum,u64 *desired_perf)
@@ -300,7 +301,11 @@ static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf) {return -ENODEV ; } -static inline int amd_get_boost_ratio_numerator (unsigned int cpu,u64 *numerator) +static inline int amd_get_effective_highest_perf (unsigned int cpu) +{ +return -EOPNOTSUPP ; +} +static inline int amd_get_boost_ratio (unsigned int cpu,u64 *numerator,u64 *denominator) {return -EOPNOTSUPP ; }
Signature · 1 line
2.43.0
PATCH 5/6 cpufreq/acpi-cpufreq: Use amd_get_boost_ratio()
In reply to Mario Limonciello (AMD)Update get_max_boost_ratio() to use the new amd_get_boost_ratio() helper function instead of calling amd_get_effective_highest_perf() directly.
This ensures the boost ratio is calculated correctly on systems where frequency values should be used instead of performance values.
--- drivers/cpufreq/acpi-cpufreq.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
drivers/cpufreq/acpi-cpufreq.c +9 -11
@@ -626,7 +626,7 @@ static int acpi_cpufreq_blacklist(struct cpuinfo_x86 *c)static u64 get_max_boost_ratio (unsigned int cpu,u64 *nominal_freq) {struct cppc_perf_caps perf_caps; -u64 highest_perf, nominal_perf; +u64 numerator, denominator;int ret;if (acpi_pstate_strict)
@@ -640,33 +640,31 @@ static u64 get_max_boost_ratio(unsigned int cpu, u64 *nominal_freq) }if (boot_cpu_data.x86_vendor ==X86_VENDOR_AMD ) { - ret =amd_get_effective_highest_perf (cpu); -if (ret <0 ) { -pr_debug ("CPU%d: Unable to get boost ratio numerator (%d)\n" , + ret =amd_get_boost_ratio (cpu, &numerator, &denominator); +if (ret) { +pr_debug ("CPU%d: Unable to get boost ratio (%d)\n" , cpu, ret);return 0 ; } - highest_perf = ret; }else { - highest_perf = perf_caps.highest_perf; + numerator = perf_caps.highest_perf; + denominator = perf_caps.nominal_perf; } - nominal_perf = perf_caps.nominal_perf; -if (nominal_freq) *nominal_freq = perf_caps.nominal_freq *1000 ; -if (!highest_perf || !nominal_perf) { +if (!numerator || !denominator) {pr_debug ("CPU%d: highest or nominal performance missing\n" , cpu);return 0 ; } -if (highest_perf < nominal_perf) { +if (numerator < denominator) {pr_debug ("CPU%d: nominal performance above highest\n" , cpu);return 0 ; } -return div_u64 (highest_perf <<SCHED_CAPACITY_SHIFT , nominal_perf); +return div_u64 (numerator <<SCHED_CAPACITY_SHIFT , denominator); }#else
Signature · 1 line
2.43.0
PATCH 6/6 cpufreq/amd-pstate: Get highest freq from CPPC if available
In reply to Mario Limonciello (AMD)If the _CPC object advertises the highest frequency for a CPU, use this instead of trying to calculate by linear interpolation.
--- drivers/cpufreq/amd-pstate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/cpufreq/amd-pstate.c +5 -1
@@ -1026,8 +1026,12 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)WRITE_ONCE (cpudata->nominal_freq, nominal_freq); +/* max freq came from _CPC */ +if (cppc_perf.highest_freq) + max_freq = cppc_perf.highest_freq *1000 ;/* max_freq is calculated according to (nominal_freq * highest_perf)/nominal_perf */ - max_freq =perf_to_freq (perf, nominal_freq, perf.highest_perf); +else + max_freq =perf_to_freq (perf, nominal_freq, perf.highest_perf);WRITE_ONCE (cpudata->max_freq, max_freq); lowest_nonlinear_freq =perf_to_freq (perf, nominal_freq, perf.lowest_nonlinear_perf);
Signature · 1 line
2.43.0