diff options
Diffstat (limited to 'SOURCES/0001-amd-pstate.patch')
-rw-r--r-- | SOURCES/0001-amd-pstate.patch | 941 |
1 files changed, 889 insertions, 52 deletions
diff --git a/SOURCES/0001-amd-pstate.patch b/SOURCES/0001-amd-pstate.patch index 8e7b5cb..f654f25 100644 --- a/SOURCES/0001-amd-pstate.patch +++ b/SOURCES/0001-amd-pstate.patch @@ -1,19 +1,163 @@ -From 14416a42f37d3455e6de7d249df9a76b40a456bf Mon Sep 17 00:00:00 2001 +From b36ccc153f8a2ee04f046a4e10220dbe308f37ef Mon Sep 17 00:00:00 2001 From: Peter Jung <admin@ptr1337.dev> -Date: Fri, 21 Jun 2024 15:31:56 +0200 +Date: Tue, 25 Jun 2024 13:29:13 +0200 Subject: [PATCH 02/10] amd-pstate Signed-off-by: Peter Jung <admin@ptr1337.dev> --- - drivers/cpufreq/amd-pstate.c | 115 +++++++++++++++++++---------------- - drivers/cpufreq/amd-pstate.h | 14 +++-- - 2 files changed, 70 insertions(+), 59 deletions(-) + Documentation/admin-guide/pm/amd-pstate.rst | 40 +- + arch/x86/include/asm/cpufeatures.h | 1 + + arch/x86/include/asm/msr-index.h | 2 + + arch/x86/kernel/cpu/scattered.c | 1 + + drivers/cpufreq/acpi-cpufreq.c | 2 - + drivers/cpufreq/amd-pstate-ut.c | 2 +- + drivers/cpufreq/amd-pstate.c | 463 +++++++++++++++----- + drivers/cpufreq/amd-pstate.h | 29 +- + drivers/cpufreq/cpufreq.c | 25 +- + include/linux/cpufreq.h | 2 + + 10 files changed, 436 insertions(+), 131 deletions(-) +diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst +index 1e0d101b020a0..57995f54f0c88 100644 +--- a/Documentation/admin-guide/pm/amd-pstate.rst ++++ b/Documentation/admin-guide/pm/amd-pstate.rst +@@ -281,6 +281,27 @@ integer values defined between 0 to 255 when EPP feature is enabled by platform + firmware, if EPP feature is disabled, driver will ignore the written value + This attribute is read-write. + ++``boost`` ++The `boost` sysfs attribute provides control over the CPU core ++performance boost, allowing users to manage the maximum frequency limitation ++of the CPU. This attribute can be used to enable or disable the boost feature ++on individual CPUs. ++ ++When the boost feature is enabled, the CPU can dynamically increase its frequency ++beyond the base frequency, providing enhanced performance for demanding workloads. ++On the other hand, disabling the boost feature restricts the CPU to operate at the ++base frequency, which may be desirable in certain scenarios to prioritize power ++efficiency or manage temperature. ++ ++To manipulate the `boost` attribute, users can write a value of `0` to disable the ++boost or `1` to enable it, for the respective CPU using the sysfs path ++`/sys/devices/system/cpu/cpuX/cpufreq/boost`, where `X` represents the CPU number. ++ ++It is important to note that modifying the global variable ++`/sys/devices/system/cpu/amd_pstate/cpb_boost` will override the individual CPU ++settings. ++ ++ + Other performance and frequency values can be read back from + ``/sys/devices/system/cpu/cpuX/acpi_cppc/``, see :ref:`cppc_sysfs`. + +@@ -406,7 +427,7 @@ control its functionality at the system level. They are located in the + ``/sys/devices/system/cpu/amd_pstate/`` directory and affect all CPUs. + + ``status`` +- Operation mode of the driver: "active", "passive" or "disable". ++ Operation mode of the driver: "active", "passive", "guided" or "disable". + + "active" + The driver is functional and in the ``active mode`` +@@ -440,6 +461,23 @@ control its functionality at the system level. They are located in the + This attribute is read-only to check the state of preferred core set + by the kernel parameter. + ++``cpb_boost`` ++ Specifies whether core performance boost is requested to be enabled or disabled ++ If core performance boost is disabled while a core is in a boosted P-state, the ++ core automatically transitions to the highest performance non-boosted P-state. ++ AMD Core Performance Boost(CPB) is controlled by this attribute file which allows ++ user to change all cores frequency boosting state. It supports all amd-pstate modes. ++ ++ States of the driver "/sys/devices/system/cpu/amd_pstate/cpb_boost" ++ "disabled" Core Performance Boosting Disabled. ++ "enabled" Core Performance Boosting Enabled. ++ ++ To enable core performance boost: ++ # echo "enabled" > /sys/devices/system/cpu/amd_pstate/cpb_boost ++ ++ To disable core performance boost: ++ # echo "disabled" > /sys/devices/system/cpu/amd_pstate/cpb_boost ++ + ``cpupower`` tool support for ``amd-pstate`` + =============================================== + +diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h +index 3c7434329661c..6c128d463a143 100644 +--- a/arch/x86/include/asm/cpufeatures.h ++++ b/arch/x86/include/asm/cpufeatures.h +@@ -470,6 +470,7 @@ + #define X86_FEATURE_BHI_CTRL (21*32+ 2) /* "" BHI_DIS_S HW control available */ + #define X86_FEATURE_CLEAR_BHB_HW (21*32+ 3) /* "" BHI_DIS_S HW control enabled */ + #define X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT (21*32+ 4) /* "" Clear branch history at vmexit using SW loop */ ++#define X86_FEATURE_FAST_CPPC (21*32 + 5) /* "" AMD Fast CPPC */ + + /* + * BUG word(s) +diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h +index e72c2b8729579..8738a7b3917d8 100644 +--- a/arch/x86/include/asm/msr-index.h ++++ b/arch/x86/include/asm/msr-index.h +@@ -782,6 +782,8 @@ + #define MSR_K7_HWCR_IRPERF_EN BIT_ULL(MSR_K7_HWCR_IRPERF_EN_BIT) + #define MSR_K7_FID_VID_CTL 0xc0010041 + #define MSR_K7_FID_VID_STATUS 0xc0010042 ++#define MSR_K7_HWCR_CPB_DIS_BIT 25 ++#define MSR_K7_HWCR_CPB_DIS BIT_ULL(MSR_K7_HWCR_CPB_DIS_BIT) + + /* K6 MSRs */ + #define MSR_K6_WHCR 0xc0000082 +diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c +index af5aa2c754c22..c84c30188fdf2 100644 +--- a/arch/x86/kernel/cpu/scattered.c ++++ b/arch/x86/kernel/cpu/scattered.c +@@ -45,6 +45,7 @@ static const struct cpuid_bit cpuid_bits[] = { + { X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 }, + { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, + { X86_FEATURE_PROC_FEEDBACK, CPUID_EDX, 11, 0x80000007, 0 }, ++ { X86_FEATURE_FAST_CPPC, CPUID_EDX, 15, 0x80000007, 0 }, + { X86_FEATURE_MBA, CPUID_EBX, 6, 0x80000008, 0 }, + { X86_FEATURE_SMBA, CPUID_EBX, 2, 0x80000020, 0 }, + { X86_FEATURE_BMEC, CPUID_EBX, 3, 0x80000020, 0 }, +diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c +index 37f1cdf46d291..2fc82831bddd5 100644 +--- a/drivers/cpufreq/acpi-cpufreq.c ++++ b/drivers/cpufreq/acpi-cpufreq.c +@@ -50,8 +50,6 @@ enum { + #define AMD_MSR_RANGE (0x7) + #define HYGON_MSR_RANGE (0x7) + +-#define MSR_K7_HWCR_CPB_DIS (1ULL << 25) +- + struct acpi_cpufreq_data { + unsigned int resume; + unsigned int cpu_feature; +diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c +index fc275d41d51e9..b528f198f4c36 100644 +--- a/drivers/cpufreq/amd-pstate-ut.c ++++ b/drivers/cpufreq/amd-pstate-ut.c +@@ -227,7 +227,7 @@ static void amd_pstate_ut_check_freq(u32 index) + goto skip_test; + } + +- if (cpudata->boost_supported) { ++ if (amd_pstate_global_params.cpb_boost) { + if ((policy->max == cpudata->max_freq) || + (policy->max == cpudata->nominal_freq)) + amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS; diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index 6c989d859b39..c08463f8dcac 100644 +index 6af175e6c08ac..6eeba793bf442 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c -@@ -85,15 +85,6 @@ struct quirk_entry { +@@ -51,6 +51,7 @@ + + #define AMD_PSTATE_TRANSITION_LATENCY 20000 + #define AMD_PSTATE_TRANSITION_DELAY 1000 ++#define AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY 600 + #define CPPC_HIGHEST_PERF_PERFORMANCE 196 + #define CPPC_HIGHEST_PERF_DEFAULT 166 + +@@ -85,15 +86,6 @@ struct quirk_entry { u32 lowest_freq; }; @@ -29,7 +173,136 @@ index 6c989d859b39..c08463f8dcac 100644 static struct cpufreq_driver *current_pstate_driver; static struct cpufreq_driver amd_pstate_driver; static struct cpufreq_driver amd_pstate_epp_driver; -@@ -688,26 +679,6 @@ static void amd_pstate_adjust_perf(unsigned int cpu, +@@ -102,6 +94,11 @@ static bool cppc_enabled; + static bool amd_pstate_prefcore = true; + static struct quirk_entry *quirks; + ++/* export the amd_pstate_global_params for unit test */ ++struct amd_pstate_global_params amd_pstate_global_params; ++EXPORT_SYMBOL_GPL(amd_pstate_global_params); ++static int amd_pstate_cpu_boost(int cpu, bool state); ++ + /* + * AMD Energy Preference Performance (EPP) + * The EPP is used in the CCLK DPM controller to drive +@@ -143,6 +140,16 @@ static unsigned int epp_values[] = { + [EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_POWERSAVE, + }; + ++enum CPB_STATE_INDEX { ++ CPB_STATE_DISABLED = 0, ++ CPB_STATE_ENABLED = 1, ++}; ++ ++static const char * const cpb_state[] = { ++ [CPB_STATE_DISABLED] = "disabled", ++ [CPB_STATE_ENABLED] = "enabled", ++}; ++ + typedef int (*cppc_mode_transition_fn)(int); + + static struct quirk_entry quirk_amd_7k62 = { +@@ -157,7 +164,7 @@ static int __init dmi_matched_7k62_bios_bug(const struct dmi_system_id *dmi) + * broken BIOS lack of nominal_freq and lowest_freq capabilities + * definition in ACPI tables + */ +- if (boot_cpu_has(X86_FEATURE_ZEN2)) { ++ if (cpu_feature_enabled(X86_FEATURE_ZEN2)) { + quirks = dmi->driver_data; + pr_info("Overriding nominal and lowest frequencies for %s\n", dmi->ident); + return 1; +@@ -199,7 +206,7 @@ static s16 amd_pstate_get_epp(struct amd_cpudata *cpudata, u64 cppc_req_cached) + u64 epp; + int ret; + +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + if (!cppc_req_cached) { + epp = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, + &cppc_req_cached); +@@ -252,7 +259,7 @@ static int amd_pstate_set_epp(struct amd_cpudata *cpudata, u32 epp) + int ret; + struct cppc_perf_ctrls perf_ctrls; + +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + u64 value = READ_ONCE(cpudata->cppc_req_cached); + + value &= ~GENMASK_ULL(31, 24); +@@ -281,10 +288,8 @@ static int amd_pstate_set_energy_pref_index(struct amd_cpudata *cpudata, + int epp = -EINVAL; + int ret; + +- if (!pref_index) { +- pr_debug("EPP pref_index is invalid\n"); +- return -EINVAL; +- } ++ if (!pref_index) ++ epp = cpudata->epp_default; + + if (epp == -EINVAL) + epp = epp_values[pref_index]; +@@ -521,7 +526,10 @@ static inline bool amd_pstate_sample(struct amd_cpudata *cpudata) + static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, + u32 des_perf, u32 max_perf, bool fast_switch, int gov_flags) + { ++ unsigned long max_freq; ++ struct cpufreq_policy *policy = cpufreq_cpu_get(cpudata->cpu); + u64 prev = READ_ONCE(cpudata->cppc_req_cached); ++ u32 nominal_perf = READ_ONCE(cpudata->nominal_perf); + u64 value = prev; + + min_perf = clamp_t(unsigned long, min_perf, cpudata->min_limit_perf, +@@ -530,6 +538,9 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, + cpudata->max_limit_perf); + des_perf = clamp_t(unsigned long, des_perf, min_perf, max_perf); + ++ max_freq = READ_ONCE(cpudata->max_limit_freq); ++ policy->cur = div_u64(des_perf * max_freq, max_perf); ++ + if ((cppc_state == AMD_PSTATE_GUIDED) && (gov_flags & CPUFREQ_GOV_DYNAMIC_SWITCHING)) { + min_perf = des_perf; + des_perf = 0; +@@ -541,6 +552,10 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, + value &= ~AMD_CPPC_DES_PERF(~0L); + value |= AMD_CPPC_DES_PERF(des_perf); + ++ /* limit the max perf when core performance boost feature is disabled */ ++ if (!amd_pstate_global_params.cpb_boost) ++ max_perf = min_t(unsigned long, nominal_perf, max_perf); ++ + value &= ~AMD_CPPC_MAX_PERF(~0L); + value |= AMD_CPPC_MAX_PERF(max_perf); + +@@ -651,10 +666,9 @@ static void amd_pstate_adjust_perf(unsigned int cpu, + unsigned long capacity) + { + unsigned long max_perf, min_perf, des_perf, +- cap_perf, lowest_nonlinear_perf, max_freq; ++ cap_perf, lowest_nonlinear_perf; + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct amd_cpudata *cpudata = policy->driver_data; +- unsigned int target_freq; + + if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq) + amd_pstate_update_min_max_limit(policy); +@@ -662,7 +676,6 @@ static void amd_pstate_adjust_perf(unsigned int cpu, + + cap_perf = READ_ONCE(cpudata->highest_perf); + lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); +- max_freq = READ_ONCE(cpudata->max_freq); + + des_perf = cap_perf; + if (target_perf < capacity) +@@ -680,34 +693,12 @@ static void amd_pstate_adjust_perf(unsigned int cpu, + max_perf = min_perf; + + des_perf = clamp_t(unsigned long, des_perf, min_perf, max_perf); +- target_freq = div_u64(des_perf * max_freq, max_perf); +- policy->cur = target_freq; + + amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true, + policy->governor->flags); cpufreq_cpu_put(policy); } @@ -56,7 +329,92 @@ index 6c989d859b39..c08463f8dcac 100644 static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state) { struct amd_cpudata *cpudata = policy->driver_data; -@@ -860,7 +831,37 @@ static void amd_pstate_update_limits(unsigned int cpu) +@@ -715,36 +706,53 @@ static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state) + + if (!cpudata->boost_supported) { + pr_err("Boost mode is not supported by this processor or SBIOS\n"); +- return -EINVAL; ++ return -ENOTSUPP; + } ++ mutex_lock(&amd_pstate_driver_lock); ++ ret = amd_pstate_cpu_boost(policy->cpu, state); ++ mutex_unlock(&amd_pstate_driver_lock); + +- if (state) +- policy->cpuinfo.max_freq = cpudata->max_freq; +- else +- policy->cpuinfo.max_freq = cpudata->nominal_freq * 1000; +- +- policy->max = policy->cpuinfo.max_freq; +- +- ret = freq_qos_update_request(&cpudata->req[1], +- policy->cpuinfo.max_freq); +- if (ret < 0) +- return ret; +- +- return 0; ++ return ret < 0 ? ret : 0; + } + +-static void amd_pstate_boost_init(struct amd_cpudata *cpudata) ++static int amd_pstate_init_boost_support(struct amd_cpudata *cpudata) + { +- u32 highest_perf, nominal_perf; ++ u64 boost_val; ++ int ret = -1; + +- highest_perf = READ_ONCE(cpudata->highest_perf); +- nominal_perf = READ_ONCE(cpudata->nominal_perf); ++ /* ++ * If platform has no CPB support or disble it, initialize current driver ++ * boost_enabled state to be false, it is not an error for cpufreq core to handle. ++ */ ++ if (!cpu_feature_enabled(X86_FEATURE_CPB)) { ++ pr_debug_once("Boost CPB capabilities not present in the processor\n"); ++ ret = 0; ++ goto exit_err; ++ } + +- if (highest_perf <= nominal_perf) +- return; ++ ret = rdmsrl_on_cpu(cpudata->cpu, MSR_K7_HWCR, &boost_val); ++ if (ret) { ++ pr_err_once("failed to read initial CPU boost state!\n"); ++ ret = -EIO; ++ goto exit_err; ++ } ++ ++ amd_pstate_global_params.cpb_supported = !(boost_val & MSR_K7_HWCR_CPB_DIS); ++ if (amd_pstate_global_params.cpb_supported) { ++ current_pstate_driver->boost_enabled = true; ++ cpudata->boost_supported = true; ++ cpudata->boost_state = true; ++ } + +- cpudata->boost_supported = true; +- current_pstate_driver->boost_enabled = true; ++ amd_pstate_global_params.cpb_boost = amd_pstate_global_params.cpb_supported; ++ return 0; ++ ++exit_err: ++ cpudata->boost_supported = false; ++ cpudata->boost_state = false; ++ current_pstate_driver->boost_enabled = false; ++ amd_pstate_global_params.cpb_boost = false; ++ return ret; + } + + static void amd_perf_ctl_reset(unsigned int cpu) +@@ -773,7 +781,7 @@ static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf) + { + int ret; + +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + u64 cap1; + + ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1); +@@ -860,7 +868,41 @@ static void amd_pstate_update_limits(unsigned int cpu) mutex_unlock(&amd_pstate_driver_lock); } @@ -70,8 +428,12 @@ index 6c989d859b39..c08463f8dcac 100644 + u32 transition_delay_ns; + + transition_delay_ns = cppc_get_transition_latency(cpu); -+ if (transition_delay_ns == CPUFREQ_ETERNAL) -+ return AMD_PSTATE_TRANSITION_DELAY; ++ if (transition_delay_ns == CPUFREQ_ETERNAL) { ++ if (cpu_feature_enabled(X86_FEATURE_FAST_CPPC)) ++ return AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY; ++ else ++ return AMD_PSTATE_TRANSITION_DELAY; ++ } + + return transition_delay_ns / NSEC_PER_USEC; +} @@ -95,7 +457,7 @@ index 6c989d859b39..c08463f8dcac 100644 * amd_pstate_init_freq: Initialize the max_freq, min_freq, * nominal_freq and lowest_nonlinear_freq for * the @cpudata object. -@@ -881,7 +882,6 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) +@@ -881,7 +923,6 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) u32 boost_ratio, lowest_nonlinear_ratio; struct cppc_perf_caps cppc_perf; @@ -103,16 +465,39 @@ index 6c989d859b39..c08463f8dcac 100644 ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf); if (ret) return ret; -@@ -917,7 +917,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) +@@ -912,12 +953,30 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata) + WRITE_ONCE(cpudata->nominal_freq, nominal_freq); + WRITE_ONCE(cpudata->max_freq, max_freq); + ++ /** ++ * Below values need to be initialized correctly, otherwise driver will fail to load ++ * max_freq is calculated according to (nominal_freq * highest_perf)/nominal_perf ++ * lowest_nonlinear_freq is a value between [min_freq, nominal_freq] ++ * Check _CPC in ACPI table objects if any values are incorrect ++ */ ++ if (min_freq <= 0 || max_freq <= 0 || nominal_freq <= 0 || min_freq > max_freq) { ++ pr_err("min_freq(%d) or max_freq(%d) or nominal_freq(%d) value is incorrect\n", ++ min_freq, max_freq, nominal_freq * 1000); ++ return -EINVAL; ++ } ++ ++ if (lowest_nonlinear_freq <= min_freq || lowest_nonlinear_freq > nominal_freq * 1000) { ++ pr_err("lowest_nonlinear_freq(%d) value is out of range [min_freq(%d), nominal_freq(%d)]\n", ++ lowest_nonlinear_freq, min_freq, nominal_freq * 1000); ++ return -EINVAL; ++ } ++ + return 0; + } static int amd_pstate_cpu_init(struct cpufreq_policy *policy) { - int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; -+ int min_freq, max_freq, nominal_freq, ret; ++ int min_freq, max_freq, ret; struct device *dev; struct amd_cpudata *cpudata; -@@ -946,20 +946,21 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) +@@ -946,20 +1005,11 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) if (ret) goto free_cpudata1; @@ -120,21 +505,15 @@ index 6c989d859b39..c08463f8dcac 100644 - max_freq = amd_get_max_freq(cpudata); - nominal_freq = amd_get_nominal_freq(cpudata); - lowest_nonlinear_freq = amd_get_lowest_nonlinear_freq(cpudata); -+ min_freq = READ_ONCE(cpudata->min_freq); -+ max_freq = READ_ONCE(cpudata->max_freq); -+ nominal_freq = READ_ONCE(cpudata->nominal_freq); - +- - if (min_freq < 0 || max_freq < 0 || min_freq > max_freq) { - dev_err(dev, "min_freq(%d) or max_freq(%d) value is incorrect\n", - min_freq, max_freq); -+ if (min_freq <= 0 || max_freq <= 0 || -+ nominal_freq <= 0 || min_freq > max_freq) { -+ dev_err(dev, -+ "min_freq(%d) or max_freq(%d) or nominal_freq (%d) value is incorrect, check _CPC in ACPI tables\n", -+ min_freq, max_freq, nominal_freq); - ret = -EINVAL; - goto free_cpudata1; - } +- ret = -EINVAL; +- goto free_cpudata1; +- } ++ min_freq = READ_ONCE(cpudata->min_freq); ++ max_freq = READ_ONCE(cpudata->max_freq); - policy->cpuinfo.transition_latency = AMD_PSTATE_TRANSITION_LATENCY; - policy->transition_delay_us = AMD_PSTATE_TRANSITION_DELAY; @@ -143,7 +522,24 @@ index 6c989d859b39..c08463f8dcac 100644 policy->min = min_freq; policy->max = max_freq; -@@ -1052,7 +1053,7 @@ static ssize_t show_amd_pstate_max_freq(struct cpufreq_policy *policy, +@@ -970,7 +1020,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + /* It will be updated by governor */ + policy->cur = policy->cpuinfo.min_freq; + +- if (boot_cpu_has(X86_FEATURE_CPPC)) ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) + policy->fast_switch_possible = true; + + ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0], +@@ -992,7 +1042,6 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + + policy->driver_data = cpudata; + +- amd_pstate_boost_init(cpudata); + if (!current_pstate_driver->adjust_perf) + current_pstate_driver->adjust_perf = amd_pstate_adjust_perf; + +@@ -1052,7 +1101,7 @@ static ssize_t show_amd_pstate_max_freq(struct cpufreq_policy *policy, int max_freq; struct amd_cpudata *cpudata = policy->driver_data; @@ -152,7 +548,7 @@ index 6c989d859b39..c08463f8dcac 100644 if (max_freq < 0) return max_freq; -@@ -1065,7 +1066,7 @@ static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *poli +@@ -1065,7 +1114,7 @@ static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *poli int freq; struct amd_cpudata *cpudata = policy->driver_data; @@ -161,16 +557,177 @@ index 6c989d859b39..c08463f8dcac 100644 if (freq < 0) return freq; -@@ -1376,7 +1377,7 @@ static bool amd_pstate_acpi_pm_profile_undefined(void) +@@ -1203,7 +1252,7 @@ static int amd_pstate_change_mode_without_dvr_change(int mode) + + cppc_state = mode; +- if (boot_cpu_has(X86_FEATURE_CPPC) || cppc_state == AMD_PSTATE_ACTIVE) ++ if (cpu_feature_enabled(X86_FEATURE_CPPC) || cppc_state == AMD_PSTATE_ACTIVE) + return 0; + + for_each_present_cpu(cpu) { +@@ -1312,6 +1361,118 @@ static ssize_t prefcore_show(struct device *dev, + return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore)); + } + ++static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on) ++{ ++ struct amd_cpudata *cpudata = policy->driver_data; ++ struct cppc_perf_ctrls perf_ctrls; ++ u32 highest_perf, nominal_perf, nominal_freq, max_freq; ++ int ret; ++ ++ highest_perf = READ_ONCE(cpudata->highest_perf); ++ nominal_perf = READ_ONCE(cpudata->nominal_perf); ++ nominal_freq = READ_ONCE(cpudata->nominal_freq); ++ max_freq = READ_ONCE(cpudata->max_freq); ++ ++ if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ u64 value = READ_ONCE(cpudata->cppc_req_cached); ++ ++ value &= ~GENMASK_ULL(7, 0); ++ value |= on ? highest_perf : nominal_perf; ++ WRITE_ONCE(cpudata->cppc_req_cached, value); ++ ++ wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); ++ } else { ++ perf_ctrls.max_perf = on ? highest_perf : nominal_perf; ++ ret = cppc_set_perf(cpudata->cpu, &perf_ctrls); ++ if (ret) { ++ cpufreq_cpu_release(policy); ++ pr_debug("Failed to set max perf on CPU:%d. ret:%d\n", ++ cpudata->cpu, ret); ++ return ret; ++ } ++ } ++ ++ if (on) ++ policy->cpuinfo.max_freq = max_freq; ++ else ++ policy->cpuinfo.max_freq = nominal_freq * 1000; ++ ++ policy->max = policy->cpuinfo.max_freq; ++ ++ if (cppc_state == AMD_PSTATE_PASSIVE) { ++ ret = freq_qos_update_request(&cpudata->req[1], policy->cpuinfo.max_freq); ++ if (ret < 0) ++ pr_debug("Failed to update freq constraint: CPU%d\n", cpudata->cpu); ++ } ++ ++ return ret < 0 ? ret : 0; ++} ++ ++static int amd_pstate_cpu_boost(int cpu, bool state) ++{ ++ int ret; ++ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); ++ struct amd_cpudata *cpudata = policy->driver_data; ++ ++ if (!policy) { ++ pr_err("policy is NULL\n"); ++ ret = -ENODATA; ++ goto err_exit; ++ } ++ ++ ret = amd_pstate_cpu_boost_update(policy, state); ++ refresh_frequency_limits(policy); ++ WRITE_ONCE(cpudata->boost_state, state); ++ policy->boost_enabled = state; ++ ++err_exit: ++ cpufreq_cpu_put(policy); ++ return ret < 0 ? ret : 0; ++} ++ ++static ssize_t cpb_boost_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ bool cpb_idx; ++ ++ cpb_idx = amd_pstate_global_params.cpb_boost; ++ ++ return sysfs_emit(buf, "%s\n", cpb_state[cpb_idx]); ++} ++ ++static ssize_t cpb_boost_store(struct device *dev, struct device_attribute *b, ++ const char *buf, size_t count) ++{ ++ bool new_state; ++ ssize_t ret; ++ int cpu, cpb_idx; ++ ++ if (!amd_pstate_global_params.cpb_supported) { ++ pr_err("Boost mode is not supported by this processor or SBIOS\n"); ++ return -EINVAL; ++ } ++ ++ cpb_idx = sysfs_match_string(cpb_state, buf); ++ if (cpb_idx < 0) ++ return -EINVAL; ++ ++ new_state = cpb_idx; ++ ++ mutex_lock(&amd_pstate_driver_lock); ++ for_each_present_cpu(cpu) { ++ ret = amd_pstate_cpu_boost(cpu, new_state); ++ if (ret < 0) { ++ pr_warn("failed to update cpu boost for CPU%d (%zd)\n", cpu, ret); ++ goto err_exit; ++ } ++ } ++ amd_pstate_global_params.cpb_boost = !!new_state; ++ ++err_exit: ++ mutex_unlock(&amd_pstate_driver_lock); ++ return ret < 0 ? ret : count; ++} ++ + cpufreq_freq_attr_ro(amd_pstate_max_freq); + cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq); + +@@ -1322,6 +1483,7 @@ cpufreq_freq_attr_rw(energy_performance_preference); + cpufreq_freq_attr_ro(energy_performance_available_preferences); + static DEVICE_ATTR_RW(status); + static DEVICE_ATTR_RO(prefcore); ++static DEVICE_ATTR_RW(cpb_boost); + + static struct freq_attr *amd_pstate_attr[] = { + &amd_pstate_max_freq, +@@ -1346,6 +1508,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = { + static struct attribute *pstate_global_attributes[] = { + &dev_attr_status.attr, + &dev_attr_prefcore.attr, ++ &dev_attr_cpb_boost.attr, + NULL + }; + +@@ -1374,9 +1537,24 @@ static bool amd_pstate_acpi_pm_profile_undefined(void) + return false; + } + ++static int amd_pstate_init_boost(struct cpufreq_policy *policy) ++{ ++ struct amd_cpudata *cpudata = policy->driver_data; ++ int ret; ++ ++ /* initialize cpu cores boot state */ ++ ret = amd_pstate_init_boost_support(cpudata); ++ if (ret) ++ return ret; ++ ++ policy->boost_enabled = READ_ONCE(cpudata->boost_state); ++ ++ return 0; ++} ++ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) { - int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; -+ int min_freq, max_freq, nominal_freq, ret; ++ int min_freq, max_freq, ret; struct amd_cpudata *cpudata; struct device *dev; u64 value; -@@ -1407,13 +1408,14 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) +@@ -1407,16 +1585,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) if (ret) goto free_cpudata1; @@ -181,32 +738,169 @@ index 6c989d859b39..c08463f8dcac 100644 - if (min_freq < 0 || max_freq < 0 || min_freq > max_freq) { - dev_err(dev, "min_freq(%d) or max_freq(%d) value is incorrect\n", - min_freq, max_freq); +- ret = -EINVAL; +- goto free_cpudata1; +- } + min_freq = READ_ONCE(cpudata->min_freq); + max_freq = READ_ONCE(cpudata->max_freq); -+ nominal_freq = READ_ONCE(cpudata->nominal_freq); -+ if (min_freq <= 0 || max_freq <= 0 || -+ nominal_freq <= 0 || min_freq > max_freq) { -+ dev_err(dev, -+ "min_freq(%d) or max_freq(%d) or nominal_freq(%d) value is incorrect, check _CPC in ACPI tables\n", -+ min_freq, max_freq, nominal_freq); - ret = -EINVAL; - goto free_cpudata1; + + policy->cpuinfo.min_freq = min_freq; + policy->cpuinfo.max_freq = max_freq; +@@ -1425,7 +1595,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + + policy->driver_data = cpudata; + +- cpudata->epp_cached = amd_pstate_get_epp(cpudata, 0); ++ cpudata->epp_cached = cpudata->epp_default = amd_pstate_get_epp(cpudata, 0); + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; +@@ -1440,7 +1610,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + else + policy->policy = CPUFREQ_POLICY_POWERSAVE; + +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, &value); + if (ret) + return ret; +@@ -1451,7 +1621,6 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) + return ret; + WRITE_ONCE(cpudata->cppc_cap1_cached, value); } -@@ -1462,6 +1464,13 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy) +- amd_pstate_boost_init(cpudata); - static int amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy) - { -+ struct amd_cpudata *cpudata = policy->driver_data; -+ -+ if (cpudata) { -+ kfree(cpudata); -+ policy->driver_data = NULL; -+ } + return 0; + +@@ -1530,7 +1699,7 @@ static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy) + epp = 0; + + /* Set initial EPP value */ +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + value &= ~GENMASK_ULL(31, 24); + value |= (u64)epp << 24; + } +@@ -1553,6 +1722,12 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy) + + amd_pstate_epp_update_limit(policy); + ++ /* ++ * policy->cur is never updated with the amd_pstate_epp driver, but it ++ * is used as a stale frequency value. So, keep it within limits. ++ */ ++ policy->cur = policy->min; + - pr_debug("CPU %d exiting\n", policy->cpu); return 0; } -@@ -1750,11 +1759,9 @@ static int __init amd_pstate_init(void) + +@@ -1569,7 +1744,7 @@ static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata) + value = READ_ONCE(cpudata->cppc_req_cached); + max_perf = READ_ONCE(cpudata->highest_perf); + +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); + } else { + perf_ctrls.max_perf = max_perf; +@@ -1603,7 +1778,7 @@ static void amd_pstate_epp_offline(struct cpufreq_policy *policy) + value = READ_ONCE(cpudata->cppc_req_cached); + + mutex_lock(&amd_pstate_limits_lock); +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + cpudata->epp_policy = CPUFREQ_POLICY_UNKNOWN; + + /* Set max perf same as min perf */ +@@ -1690,6 +1865,7 @@ static struct cpufreq_driver amd_pstate_driver = { + .exit = amd_pstate_cpu_exit, + .suspend = amd_pstate_cpu_suspend, + .resume = amd_pstate_cpu_resume, ++ .init_boost = amd_pstate_init_boost, + .set_boost = amd_pstate_set_boost, + .update_limits = amd_pstate_update_limits, + .name = "amd-pstate", +@@ -1707,6 +1883,8 @@ static struct cpufreq_driver amd_pstate_epp_driver = { + .suspend = amd_pstate_epp_suspend, + .resume = amd_pstate_epp_resume, + .update_limits = amd_pstate_update_limits, ++ .init_boost = amd_pstate_init_boost, ++ .set_boost = amd_pstate_set_boost, + .name = "amd-pstate-epp", + .attr = amd_pstate_epp_attr, + }; +@@ -1730,6 +1908,46 @@ static int __init amd_pstate_set_driver(int mode_idx) + return -EINVAL; + } + ++/** ++ * CPPC function is not supported for family ID 17H with model_ID ranging from 0x10 to 0x2F. ++ * show the debug message that helps to check if the CPU has CPPC support for loading issue. ++ */ ++static bool amd_cppc_supported(void) ++{ ++ struct cpuinfo_x86 *c = &cpu_data(0); ++ bool warn = false; ++ ++ if ((boot_cpu_data.x86 == 0x17) && (boot_cpu_data.x86_model < 0x30)) { ++ pr_debug_once("CPPC feature is not supported by the processor\n"); ++ return false; ++ } ++ ++ /* ++ * If the CPPC feature is disabled in the BIOS for processors that support MSR-based CPPC, ++ * the AMD Pstate driver may not function correctly. ++ * Check the CPPC flag and display a warning message if the platform supports CPPC. ++ * Note: below checking code will not abort the driver registeration process because of ++ * the code is added for debugging purposes. ++ */ ++ if (!cpu_feature_enabled(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_ZEN1) || cpu_feature_enabled(X86_FEATURE_ZEN2)) { ++ if (c->x86_model > 0x60 && c->x86_model < 0xaf) ++ warn = true; ++ } else if (cpu_feature_enabled(X86_FEATURE_ZEN3) || cpu_feature_enabled(X86_FEATURE_ZEN4)) { ++ if ((c->x86_model > 0x10 && c->x86_model < 0x1F) || ++ (c->x86_model > 0x40 && c->x86_model < 0xaf)) ++ warn = true; ++ } else if (cpu_feature_enabled(X86_FEATURE_ZEN5)) { ++ warn = true; ++ } ++ } ++ ++ if (warn) ++ pr_warn_once("The CPPC feature is supported but currently disabled by the BIOS.\n" ++ "Please enable it if your BIOS has the CPPC option.\n"); ++ return true; ++} ++ + static int __init amd_pstate_init(void) + { + struct device *dev_root; +@@ -1738,6 +1956,11 @@ static int __init amd_pstate_init(void) + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return -ENODEV; + ++ /* show debug message only if CPPC is not supported */ ++ if (!amd_cppc_supported()) ++ return -EOPNOTSUPP; ++ ++ /* show warning message when BIOS broken or ACPI disabled */ + if (!acpi_cpc_valid()) { + pr_warn_once("the _CPC object is not present in SBIOS or ACPI disabled\n"); + return -ENODEV; +@@ -1752,35 +1975,43 @@ static int __init amd_pstate_init(void) + /* check if this machine need CPPC quirks */ + dmi_check_system(amd_pstate_quirks_table); + +- switch (cppc_state) { +- case AMD_PSTATE_UNDEFINED: ++ /* ++ * determine the driver mode from the command line or kernel config. ++ * If no command line input is provided, cppc_state will be AMD_PSTATE_UNDEFINED. ++ * command line options will override the kernel config settings. ++ */ ++ ++ if (cppc_state == AMD_PSTATE_UNDEFINED) { /* Disable on the following configs by default: * 1. Undefined platforms * 2. Server platforms @@ -219,8 +913,64 @@ index 6c989d859b39..c08463f8dcac 100644 pr_info("driver load is disabled, boot with specific mode to enable this\n"); return -ENODEV; } +- ret = amd_pstate_set_driver(CONFIG_X86_AMD_PSTATE_DEFAULT_MODE); +- if (ret) +- return ret; +- break; ++ /* get driver mode from kernel config option [1:4] */ ++ cppc_state = CONFIG_X86_AMD_PSTATE_DEFAULT_MODE; ++ } ++ ++ switch (cppc_state) { + case AMD_PSTATE_DISABLE: ++ pr_info("driver load is disabled, boot with specific mode to enable this\n"); + return -ENODEV; + case AMD_PSTATE_PASSIVE: + case AMD_PSTATE_ACTIVE: + case AMD_PSTATE_GUIDED: ++ ret = amd_pstate_set_driver(cppc_state); ++ if (ret) ++ return ret; + break; + default: + return -EINVAL; + } + + /* capability check */ +- if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ if (cpu_feature_enabled(X86_FEATURE_CPPC)) { + pr_debug("AMD CPPC MSR based functionality is supported\n"); + if (cppc_state != AMD_PSTATE_ACTIVE) + current_pstate_driver->adjust_perf = amd_pstate_adjust_perf; +@@ -1794,13 +2025,15 @@ static int __init amd_pstate_init(void) + /* enable amd pstate feature */ + ret = amd_pstate_enable(true); + if (ret) { +- pr_err("failed to enable with return %d\n", ret); ++ pr_err("failed to enable driver mode(%d)\n", cppc_state); + return ret; + } + + ret = cpufreq_register_driver(current_pstate_driver); +- if (ret) ++ if (ret) { + pr_err("failed to register with return %d\n", ret); ++ goto disable_driver; ++ } + + dev_root = bus_get_dev_root(&cpu_subsys); + if (dev_root) { +@@ -1816,6 +2049,8 @@ static int __init amd_pstate_init(void) + + global_attr_free: + cpufreq_unregister_driver(current_pstate_driver); ++disable_driver: ++ amd_pstate_enable(false); + return ret; + } + device_initcall(amd_pstate_init); diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h -index bc341f35908d..e6a28e7f4dbf 100644 +index bc341f35908d7..fb240a8702892 100644 --- a/drivers/cpufreq/amd-pstate.h +++ b/drivers/cpufreq/amd-pstate.h @@ -42,13 +42,17 @@ struct amd_aperf_mperf { @@ -246,6 +996,93 @@ index bc341f35908d..e6a28e7f4dbf 100644 * @boost_supported: check whether the Processor or SBIOS supports boost mode * @hw_prefcore: check whether HW supports preferred core featue. * Only when hw_prefcore and early prefcore param are true, +@@ -95,6 +99,21 @@ struct amd_cpudata { + u32 policy; + u64 cppc_cap1_cached; + bool suspended; ++ s16 epp_default; ++ bool boost_state; + }; + ++/** ++ * struct amd_pstate_global_params - Global parameters, mostly tunable via sysfs. ++ * @cpb_boost: Whether or not to use boost CPU P-states. ++ * @cpb_supported: Whether or not CPU boost P-states are available ++ * based on the MSR_K7_HWCR bit[25] state ++ */ ++struct amd_pstate_global_params { ++ bool cpb_boost; ++ bool cpb_supported; ++}; ++ ++extern struct amd_pstate_global_params amd_pstate_global_params; ++ + #endif /* _LINUX_AMD_PSTATE_H */ +diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c +index fd9c3ed21f49c..35296d8f9cdfa 100644 +--- a/drivers/cpufreq/cpufreq.c ++++ b/drivers/cpufreq/cpufreq.c +@@ -614,10 +614,9 @@ static ssize_t show_boost(struct kobject *kobj, + static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) + { +- int ret, enable; ++ bool enable; + +- ret = sscanf(buf, "%d", &enable); +- if (ret != 1 || enable < 0 || enable > 1) ++ if (kstrtobool(buf, &enable)) + return -EINVAL; + + if (cpufreq_boost_trigger_state(enable)) { +@@ -641,10 +640,10 @@ static ssize_t show_local_boost(struct cpufreq_policy *policy, char *buf) + static ssize_t store_local_boost(struct cpufreq_policy *policy, + const char *buf, size_t count) + { +- int ret, enable; ++ int ret; ++ bool enable; + +- ret = kstrtoint(buf, 10, &enable); +- if (ret || enable < 0 || enable > 1) ++ if (kstrtobool(buf, &enable)) + return -EINVAL; + + if (!cpufreq_driver->boost_enabled) +@@ -1430,8 +1429,18 @@ static int cpufreq_online(unsigned int cpu) + goto out_free_policy; + } + +- /* Let the per-policy boost flag mirror the cpufreq_driver boost during init */ +- policy->boost_enabled = cpufreq_boost_enabled() && policy_has_boost_freq(policy); ++ /* init boost state to prepare set_boost callback for each CPU */ ++ if (cpufreq_driver->init_boost) { ++ ret = cpufreq_driver->init_boost(policy); ++ if (ret) { ++ pr_debug("%s: %d: boost initialization failed\n", __func__, ++ __LINE__); ++ goto out_offline_policy; ++ } ++ } else { ++ /* Let the per-policy boost flag mirror the cpufreq_driver boost during init */ ++ policy->boost_enabled = cpufreq_boost_enabled() && policy_has_boost_freq(policy); ++ } + + /* + * The initialization has succeeded and the policy is online. +diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h +index 9956afb9acc23..3eb5ce712c587 100644 +--- a/include/linux/cpufreq.h ++++ b/include/linux/cpufreq.h +@@ -399,6 +399,8 @@ struct cpufreq_driver { + bool boost_enabled; + int (*set_boost)(struct cpufreq_policy *policy, int state); + ++ /* initialize boost state to be consistent before calling set_boost */ ++ int (*init_boost)(struct cpufreq_policy *policy); + /* + * Set by drivers that want to register with the energy model after the + * policy is properly initialized, but before the governor is started. -- 2.45.2 |