Update the amd-pstate driver to set the initial scaling frequency policy

lower bound to be lowest non-linear frequency. This will have a slight
 power consumption impact but should lead to increased efficiency.
 
 Also amd-pstate is enabled by default on servers starting with newer
 AMD Epyc processors.
 
 Align more codepaths between shared memory and MSR designs.
 
 Add various code cleanups to rename functions and remove redundant calls.
 -----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCgA4FiEECwtuSU6dXvs5GA2aLRkspiR3AnYFAmcg6D8aHG1hcmlvLmxp
 bW9uY2llbGxvQGFtZC5jb20ACgkQLRkspiR3AnYzKg//QeOoaUb1PHiRfLFw10n3
 HD3VeLvqOp7X5ZV3jVZh1QUs7VMg8hrBTKTx1Kk5l6GucEocToZuhfV20Ed4Jllr
 JOR7uPJ0GByMJsDOKxHL9aD8Z7MEk1nL8MqZ8lQeL9ENFThLPblg2yLmPQZoF5+6
 DoP8VKK/D7brydjlGMw0Z2HmVlJBiGN4z85ND0VzML8kkv18Q497FnY4s4HLJb4d
 TIDi8OC7BxSmG2+QDvVLs6MA7PBI/NRYcqB3hCJqcCsV2XOls5eWdRhQ/pH7bElN
 2r0gSFAVzHBypKVIGGFLwAMp3g4QmE6TR9qhecOwJQNrPLYMtXRKjCvB8Kshtupd
 uU9cvaAwZUWJJ79UqksvlGSVM+ZdKqpjjWwryM3RiTxje3WpwQedEyGfdbq8UiBZ
 4QMx4RQT8PVQAko8AFgcZpIKEOSsc3GA7rc/wAgJ1GrGnli7YTlKu50UJeUs5izW
 WVpdTokXxspz4LiC0UZ08MybUOKvj5Z3G+XtvuD3rhI9LGvWoBo2XxpLp+Hpn5HL
 /yyZnwRiHrnT02G/f9LQzyW9/xAItQku/vF7xrb0+X5ksTVTTxcUIKyFlblN/WJy
 tA/jxT0ulLR/Nhh03svnFiBdcHhJ8mnli+f/9oDKq7kc6i+fhpjtFwgiJkhRU0m+
 8TPBQzF7dAHZQS4R/EssuYE=
 =Z28c
 -----END PGP SIGNATURE-----

Merge tag 'amd-pstate-v6.13-2024-10-29' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux

Merge amd-pstate driver updates for 6.13 from Mario Limonciello:

"Update the amd-pstate driver to set the initial scaling frequency policy
 lower bound to be lowest non-linear frequency. This will have a slight
 power consumption impact but should lead to increased efficiency.

 Also amd-pstate is enabled by default on servers starting with newer
 AMD Epyc processors.

 Align more codepaths between shared memory and MSR designs.

 Add various code cleanups to rename functions and remove redundant calls."

* tag 'amd-pstate-v6.13-2024-10-29' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux:
  cpufreq/amd-pstate: Move registration after static function call update
  cpufreq/amd-pstate: Push adjust_perf vfunc init into cpu_init
  cpufreq/amd-pstate: Align offline flow of shared memory and MSR based systems
  cpufreq/amd-pstate: Call cppc_set_epp_perf in the reenable function
  cpufreq/amd-pstate: Do not attempt to clear MSR_AMD_CPPC_ENABLE
  cpufreq/amd-pstate: Rename functions that enable CPPC
  cpufreq/amd-pstate-ut: Add fix for min freq unit test
  amd-pstate: Switch to amd-pstate by default on some Server platforms
  amd-pstate: Set min_perf to nominal_perf for active mode performance gov
  cpufreq/amd-pstate: Remove the redundant amd_pstate_set_driver() call
  cpufreq/amd-pstate: Remove the switch case in amd_pstate_init()
  cpufreq/amd-pstate: Call amd_pstate_set_driver() in amd_pstate_register_driver()
  cpufreq/amd-pstate: Call amd_pstate_register() in amd_pstate_init()
  cpufreq/amd-pstate: Set the initial min_freq to lowest_nonlinear_freq
  cpufreq/amd-pstate: Remove the redundant verify() function
  cpufreq/amd-pstate: Drop needless EPP initialization
  cpufreq/amd-pstate: Use amd_pstate_update_min_max_limit() for EPP limits
  cpufreq/amd-pstate: Don't update CPPC request in amd_pstate_cpu_boost_update()
  cpufreq/amd-pstate: Fix non kerneldoc comment
  cpufreq/amd-pstate: Rename MSR and shared memory specific functions
This commit is contained in:
Rafael J. Wysocki 2024-10-29 15:46:33 +01:00
commit d90adb5a70
2 changed files with 97 additions and 138 deletions

View File

@ -227,10 +227,10 @@ static void amd_pstate_ut_check_freq(u32 index)
goto skip_test;
}
if (cpudata->min_freq != policy->min) {
if (cpudata->lowest_nonlinear_freq != policy->min) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cpu%d cpudata_min_freq=%d policy_min=%d, they should be equal!\n",
__func__, cpu, cpudata->min_freq, policy->min);
pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n",
__func__, cpu, cpudata->lowest_nonlinear_freq, policy->min);
goto skip_test;
}

View File

@ -233,7 +233,7 @@ static int amd_pstate_get_energy_pref_index(struct amd_cpudata *cpudata)
return index;
}
static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf,
static void msr_update_perf(struct amd_cpudata *cpudata, u32 min_perf,
u32 des_perf, u32 max_perf, bool fast_switch)
{
if (fast_switch)
@ -243,7 +243,7 @@ static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf,
READ_ONCE(cpudata->cppc_req_cached));
}
DEFINE_STATIC_CALL(amd_pstate_update_perf, pstate_update_perf);
DEFINE_STATIC_CALL(amd_pstate_update_perf, msr_update_perf);
static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata,
u32 min_perf, u32 des_perf,
@ -306,11 +306,17 @@ static int amd_pstate_set_energy_pref_index(struct amd_cpudata *cpudata,
return ret;
}
static inline int pstate_enable(bool enable)
static inline int msr_cppc_enable(bool enable)
{
int ret, cpu;
unsigned long logical_proc_id_mask = 0;
/*
* MSR_AMD_CPPC_ENABLE is write-once, once set it cannot be cleared.
*/
if (!enable)
return 0;
if (enable == cppc_enabled)
return 0;
@ -332,7 +338,7 @@ static inline int pstate_enable(bool enable)
return 0;
}
static int cppc_enable(bool enable)
static int shmem_cppc_enable(bool enable)
{
int cpu, ret = 0;
struct cppc_perf_ctrls perf_ctrls;
@ -359,14 +365,14 @@ static int cppc_enable(bool enable)
return ret;
}
DEFINE_STATIC_CALL(amd_pstate_enable, pstate_enable);
DEFINE_STATIC_CALL(amd_pstate_cppc_enable, msr_cppc_enable);
static inline int amd_pstate_enable(bool enable)
static inline int amd_pstate_cppc_enable(bool enable)
{
return static_call(amd_pstate_enable)(enable);
return static_call(amd_pstate_cppc_enable)(enable);
}
static int pstate_init_perf(struct amd_cpudata *cpudata)
static int msr_init_perf(struct amd_cpudata *cpudata)
{
u64 cap1;
@ -385,7 +391,7 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)
return 0;
}
static int cppc_init_perf(struct amd_cpudata *cpudata)
static int shmem_init_perf(struct amd_cpudata *cpudata)
{
struct cppc_perf_caps cppc_perf;
@ -420,14 +426,14 @@ static int cppc_init_perf(struct amd_cpudata *cpudata)
return ret;
}
DEFINE_STATIC_CALL(amd_pstate_init_perf, pstate_init_perf);
DEFINE_STATIC_CALL(amd_pstate_init_perf, msr_init_perf);
static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata)
{
return static_call(amd_pstate_init_perf)(cpudata);
}
static void cppc_update_perf(struct amd_cpudata *cpudata,
static void shmem_update_perf(struct amd_cpudata *cpudata,
u32 min_perf, u32 des_perf,
u32 max_perf, bool fast_switch)
{
@ -527,9 +533,28 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
cpufreq_cpu_put(policy);
}
static int amd_pstate_verify(struct cpufreq_policy_data *policy)
static int amd_pstate_verify(struct cpufreq_policy_data *policy_data)
{
cpufreq_verify_within_cpu_limits(policy);
/*
* Initialize lower frequency limit (i.e.policy->min) with
* lowest_nonlinear_frequency which is the most energy efficient
* frequency. Override the initial value set by cpufreq core and
* amd-pstate qos_requests.
*/
if (policy_data->min == FREQ_QOS_MIN_DEFAULT_VALUE) {
struct cpufreq_policy *policy = cpufreq_cpu_get(policy_data->cpu);
struct amd_cpudata *cpudata;
if (!policy)
return -EINVAL;
cpudata = policy->driver_data;
policy_data->min = cpudata->lowest_nonlinear_freq;
cpufreq_cpu_put(policy);
}
cpufreq_verify_within_cpu_limits(policy_data);
pr_debug("policy_max =%d, policy_min=%d\n", policy_data->max, policy_data->min);
return 0;
}
@ -665,34 +690,12 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
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;
u32 nominal_freq, max_freq;
int ret = 0;
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 if (policy->cpuinfo.max_freq > nominal_freq * 1000)
@ -1001,7 +1004,7 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
policy->fast_switch_possible = true;
ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0],
FREQ_QOS_MIN, policy->cpuinfo.min_freq);
FREQ_QOS_MIN, FREQ_QOS_MIN_DEFAULT_VALUE);
if (ret < 0) {
dev_err(dev, "Failed to add min-freq constraint (%d)\n", ret);
goto free_cpudata1;
@ -1045,7 +1048,7 @@ static int amd_pstate_cpu_resume(struct cpufreq_policy *policy)
{
int ret;
ret = amd_pstate_enable(true);
ret = amd_pstate_cppc_enable(true);
if (ret)
pr_err("failed to enable amd-pstate during resume, return %d\n", ret);
@ -1056,7 +1059,7 @@ static int amd_pstate_cpu_suspend(struct cpufreq_policy *policy)
{
int ret;
ret = amd_pstate_enable(false);
ret = amd_pstate_cppc_enable(false);
if (ret)
pr_err("failed to disable amd-pstate during suspend, return %d\n", ret);
@ -1189,25 +1192,41 @@ static ssize_t show_energy_performance_preference(
static void amd_pstate_driver_cleanup(void)
{
amd_pstate_enable(false);
amd_pstate_cppc_enable(false);
cppc_state = AMD_PSTATE_DISABLE;
current_pstate_driver = NULL;
}
static int amd_pstate_set_driver(int mode_idx)
{
if (mode_idx >= AMD_PSTATE_DISABLE && mode_idx < AMD_PSTATE_MAX) {
cppc_state = mode_idx;
if (cppc_state == AMD_PSTATE_DISABLE)
pr_info("driver is explicitly disabled\n");
if (cppc_state == AMD_PSTATE_ACTIVE)
current_pstate_driver = &amd_pstate_epp_driver;
if (cppc_state == AMD_PSTATE_PASSIVE || cppc_state == AMD_PSTATE_GUIDED)
current_pstate_driver = &amd_pstate_driver;
return 0;
}
return -EINVAL;
}
static int amd_pstate_register_driver(int mode)
{
int ret;
if (mode == AMD_PSTATE_PASSIVE || mode == AMD_PSTATE_GUIDED)
current_pstate_driver = &amd_pstate_driver;
else if (mode == AMD_PSTATE_ACTIVE)
current_pstate_driver = &amd_pstate_epp_driver;
else
return -EINVAL;
ret = amd_pstate_set_driver(mode);
if (ret)
return ret;
cppc_state = mode;
ret = amd_pstate_enable(true);
ret = amd_pstate_cppc_enable(true);
if (ret) {
pr_err("failed to enable cppc during amd-pstate driver registration, return %d\n",
ret);
@ -1485,6 +1504,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
WRITE_ONCE(cpudata->cppc_cap1_cached, value);
}
current_pstate_driver->adjust_perf = NULL;
return 0;
free_cpudata1:
@ -1507,26 +1528,13 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
{
struct amd_cpudata *cpudata = policy->driver_data;
u32 max_perf, min_perf, min_limit_perf, max_limit_perf;
u32 max_perf, min_perf;
u64 value;
s16 epp;
if (cpudata->boost_supported && !policy->boost_enabled)
max_perf = READ_ONCE(cpudata->nominal_perf);
else
max_perf = READ_ONCE(cpudata->highest_perf);
max_perf = READ_ONCE(cpudata->highest_perf);
min_perf = READ_ONCE(cpudata->lowest_perf);
max_limit_perf = div_u64(policy->max * max_perf, policy->cpuinfo.max_freq);
min_limit_perf = div_u64(policy->min * max_perf, policy->cpuinfo.max_freq);
if (min_limit_perf < min_perf)
min_limit_perf = min_perf;
if (max_limit_perf < min_limit_perf)
max_limit_perf = min_limit_perf;
WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf);
WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf);
amd_pstate_update_min_max_limit(policy);
max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf,
cpudata->max_limit_perf);
@ -1535,7 +1543,7 @@ static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
value = READ_ONCE(cpudata->cppc_req_cached);
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
min_perf = max_perf;
min_perf = min(cpudata->nominal_perf, max_perf);
/* Initial min/max values for CPPC Performance Controls Register */
value &= ~AMD_CPPC_MIN_PERF(~0L);
@ -1563,12 +1571,6 @@ static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
epp = 0;
/* Set initial EPP value */
if (cpu_feature_enabled(X86_FEATURE_CPPC)) {
value &= ~GENMASK_ULL(31, 24);
value |= (u64)epp << 24;
}
WRITE_ONCE(cpudata->cppc_req_cached, value);
return amd_pstate_set_epp(cpudata, epp);
}
@ -1605,7 +1607,7 @@ static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata)
u64 value, max_perf;
int ret;
ret = amd_pstate_enable(true);
ret = amd_pstate_cppc_enable(true);
if (ret)
pr_err("failed to enable amd pstate during resume, return %d\n", ret);
@ -1616,8 +1618,9 @@ static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata)
wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
} else {
perf_ctrls.max_perf = max_perf;
perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(cpudata->epp_cached);
cppc_set_perf(cpudata->cpu, &perf_ctrls);
perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(cpudata->epp_cached);
cppc_set_epp_perf(cpudata->cpu, &perf_ctrls, 1);
}
}
@ -1657,9 +1660,11 @@ static void amd_pstate_epp_offline(struct cpufreq_policy *policy)
wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value);
} else {
perf_ctrls.desired_perf = 0;
perf_ctrls.min_perf = min_perf;
perf_ctrls.max_perf = min_perf;
perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(HWP_EPP_BALANCE_POWERSAVE);
cppc_set_perf(cpudata->cpu, &perf_ctrls);
perf_ctrls.energy_perf = AMD_CPPC_ENERGY_PERF_PREF(HWP_EPP_BALANCE_POWERSAVE);
cppc_set_epp_perf(cpudata->cpu, &perf_ctrls, 1);
}
mutex_unlock(&amd_pstate_limits_lock);
}
@ -1679,13 +1684,6 @@ static int amd_pstate_epp_cpu_offline(struct cpufreq_policy *policy)
return 0;
}
static int amd_pstate_epp_verify_policy(struct cpufreq_policy_data *policy)
{
cpufreq_verify_within_cpu_limits(policy);
pr_debug("policy_max =%d, policy_min=%d\n", policy->max, policy->min);
return 0;
}
static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
{
struct amd_cpudata *cpudata = policy->driver_data;
@ -1699,7 +1697,7 @@ static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
cpudata->suspended = true;
/* disable CPPC in lowlevel firmware */
ret = amd_pstate_enable(false);
ret = amd_pstate_cppc_enable(false);
if (ret)
pr_err("failed to suspend, return %d\n", ret);
@ -1741,7 +1739,7 @@ static struct cpufreq_driver amd_pstate_driver = {
static struct cpufreq_driver amd_pstate_epp_driver = {
.flags = CPUFREQ_CONST_LOOPS,
.verify = amd_pstate_epp_verify_policy,
.verify = amd_pstate_verify,
.setpolicy = amd_pstate_epp_set_policy,
.init = amd_pstate_epp_cpu_init,
.exit = amd_pstate_epp_cpu_exit,
@ -1755,26 +1753,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
.attr = amd_pstate_epp_attr,
};
static int __init amd_pstate_set_driver(int mode_idx)
{
if (mode_idx >= AMD_PSTATE_DISABLE && mode_idx < AMD_PSTATE_MAX) {
cppc_state = mode_idx;
if (cppc_state == AMD_PSTATE_DISABLE)
pr_info("driver is explicitly disabled\n");
if (cppc_state == AMD_PSTATE_ACTIVE)
current_pstate_driver = &amd_pstate_epp_driver;
if (cppc_state == AMD_PSTATE_PASSIVE || cppc_state == AMD_PSTATE_GUIDED)
current_pstate_driver = &amd_pstate_driver;
return 0;
}
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.
*/
@ -1864,10 +1843,10 @@ static int __init amd_pstate_init(void)
if (cppc_state == AMD_PSTATE_UNDEFINED) {
/* Disable on the following configs by default:
* 1. Undefined platforms
* 2. Server platforms
* 2. Server platforms with CPUs older than Family 0x1A.
*/
if (amd_pstate_acpi_pm_profile_undefined() ||
amd_pstate_acpi_pm_profile_server()) {
(amd_pstate_acpi_pm_profile_server() && boot_cpu_data.x86 < 0x1A)) {
pr_info("driver load is disabled, boot with specific mode to enable this\n");
return -ENODEV;
}
@ -1875,31 +1854,25 @@ static int __init amd_pstate_init(void)
cppc_state = CONFIG_X86_AMD_PSTATE_DEFAULT_MODE;
}
switch (cppc_state) {
case AMD_PSTATE_DISABLE:
if (cppc_state == 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 (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;
} else {
pr_debug("AMD CPPC shared memory based functionality is supported\n");
static_call_update(amd_pstate_enable, cppc_enable);
static_call_update(amd_pstate_init_perf, cppc_init_perf);
static_call_update(amd_pstate_update_perf, cppc_update_perf);
static_call_update(amd_pstate_cppc_enable, shmem_cppc_enable);
static_call_update(amd_pstate_init_perf, shmem_init_perf);
static_call_update(amd_pstate_update_perf, shmem_update_perf);
}
ret = amd_pstate_register_driver(cppc_state);
if (ret) {
pr_err("failed to register with return %d\n", ret);
return ret;
}
if (amd_pstate_prefcore) {
@ -1908,19 +1881,6 @@ static int __init amd_pstate_init(void)
return ret;
}
/* enable amd pstate feature */
ret = amd_pstate_enable(true);
if (ret) {
pr_err("failed to enable driver mode(%d)\n", cppc_state);
return ret;
}
ret = cpufreq_register_driver(current_pstate_driver);
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) {
ret = sysfs_create_group(&dev_root->kobj, &amd_pstate_global_attr_group);
@ -1935,8 +1895,7 @@ static int __init amd_pstate_init(void)
global_attr_free:
cpufreq_unregister_driver(current_pstate_driver);
disable_driver:
amd_pstate_enable(false);
amd_pstate_cppc_enable(false);
return ret;
}
device_initcall(amd_pstate_init);