mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-01 18:22:16 -05:00
Merge tag 'amd-pstate-v6.16-2025-05-08' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux
Merge amd-pstate content for 6.16 (5/8/25) from Mario Limonciello: - Add support for a new feature on some BIOS that allows setting "lowest CPU minimum frequency". - Fix the amd-pstate-ut unit tests to restore system settings when done. * tag 'amd-pstate-v6.16-2025-05-08' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux: amd-pstate-ut: Reset amd-pstate driver mode after running selftests cpufreq/amd-pstate: Add support for the "Requested CPU Min frequency" BIOS option cpufreq/amd-pstate: Add offline, online and suspend callbacks for amd_pstate_driver cpufreq/amd-pstate: Move max_perf limiting in amd_pstate_update
This commit is contained in:
@@ -242,6 +242,8 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
|
||||
static int amd_pstate_ut_check_driver(u32 index)
|
||||
{
|
||||
enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
|
||||
enum amd_pstate_mode orig_mode = amd_pstate_get_status();
|
||||
int ret;
|
||||
|
||||
for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
|
||||
int ret = amd_pstate_set_mode(mode1);
|
||||
@@ -251,16 +253,19 @@ static int amd_pstate_ut_check_driver(u32 index)
|
||||
if (mode1 == mode2)
|
||||
continue;
|
||||
ret = amd_pstate_set_mode(mode2);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to update status for %s->%s\n", __func__,
|
||||
amd_pstate_get_mode_string(mode1),
|
||||
amd_pstate_get_mode_string(mode2));
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if (ret)
|
||||
pr_warn("%s: failed to update status for %s->%s: %d\n", __func__,
|
||||
amd_pstate_get_mode_string(mode1),
|
||||
amd_pstate_get_mode_string(mode2), ret);
|
||||
|
||||
amd_pstate_set_mode(orig_mode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init amd_pstate_ut_init(void)
|
||||
|
||||
@@ -389,7 +389,8 @@ static inline int amd_pstate_cppc_enable(struct cpufreq_policy *policy)
|
||||
static int msr_init_perf(struct amd_cpudata *cpudata)
|
||||
{
|
||||
union perf_cached perf = READ_ONCE(cpudata->perf);
|
||||
u64 cap1, numerator;
|
||||
u64 cap1, numerator, cppc_req;
|
||||
u8 min_perf;
|
||||
|
||||
int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
|
||||
&cap1);
|
||||
@@ -400,6 +401,22 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, &cppc_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
WRITE_ONCE(cpudata->cppc_req_cached, cppc_req);
|
||||
min_perf = FIELD_GET(AMD_CPPC_MIN_PERF_MASK, cppc_req);
|
||||
|
||||
/*
|
||||
* Clear out the min_perf part to check if the rest of the MSR is 0, if yes, this is an
|
||||
* indication that the min_perf value is the one specified through the BIOS option
|
||||
*/
|
||||
cppc_req &= ~(AMD_CPPC_MIN_PERF_MASK);
|
||||
|
||||
if (!cppc_req)
|
||||
perf.bios_min_perf = min_perf;
|
||||
|
||||
perf.highest_perf = numerator;
|
||||
perf.max_limit_perf = numerator;
|
||||
perf.min_limit_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
|
||||
@@ -554,6 +571,10 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u8 min_perf,
|
||||
if (!policy)
|
||||
return;
|
||||
|
||||
/* limit the max perf when core performance boost feature is disabled */
|
||||
if (!cpudata->boost_supported)
|
||||
max_perf = min_t(u8, perf.nominal_perf, max_perf);
|
||||
|
||||
des_perf = clamp_t(u8, des_perf, min_perf, max_perf);
|
||||
|
||||
policy->cur = perf_to_freq(perf, cpudata->nominal_freq, des_perf);
|
||||
@@ -563,10 +584,6 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u8 min_perf,
|
||||
des_perf = 0;
|
||||
}
|
||||
|
||||
/* limit the max perf when core performance boost feature is disabled */
|
||||
if (!cpudata->boost_supported)
|
||||
max_perf = min_t(u8, perf.nominal_perf, max_perf);
|
||||
|
||||
if (trace_amd_pstate_perf_enabled() && amd_pstate_sample(cpudata)) {
|
||||
trace_amd_pstate_perf(min_perf, des_perf, max_perf, cpudata->freq,
|
||||
cpudata->cur.mperf, cpudata->cur.aperf, cpudata->cur.tsc,
|
||||
@@ -580,20 +597,26 @@ static int amd_pstate_verify(struct cpufreq_policy_data *policy_data)
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
* lowest_nonlinear_frequency or the min frequency (if) specified in BIOS,
|
||||
* 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 __free(put_cpufreq_policy) =
|
||||
cpufreq_cpu_get(policy_data->cpu);
|
||||
struct amd_cpudata *cpudata;
|
||||
union perf_cached perf;
|
||||
|
||||
if (!policy)
|
||||
return -EINVAL;
|
||||
|
||||
cpudata = policy->driver_data;
|
||||
policy_data->min = cpudata->lowest_nonlinear_freq;
|
||||
perf = READ_ONCE(cpudata->perf);
|
||||
|
||||
if (perf.bios_min_perf)
|
||||
policy_data->min = perf_to_freq(perf, cpudata->nominal_freq,
|
||||
perf.bios_min_perf);
|
||||
else
|
||||
policy_data->min = cpudata->lowest_nonlinear_freq;
|
||||
}
|
||||
|
||||
cpufreq_verify_within_cpu_limits(policy_data);
|
||||
@@ -1021,6 +1044,10 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||
static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
union perf_cached perf = READ_ONCE(cpudata->perf);
|
||||
|
||||
/* Reset CPPC_REQ MSR to the BIOS value */
|
||||
amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
|
||||
|
||||
freq_qos_remove_request(&cpudata->req[1]);
|
||||
freq_qos_remove_request(&cpudata->req[0]);
|
||||
@@ -1302,6 +1329,12 @@ static ssize_t amd_pstate_show_status(char *buf)
|
||||
return sysfs_emit(buf, "%s\n", amd_pstate_mode_string[cppc_state]);
|
||||
}
|
||||
|
||||
int amd_pstate_get_status(void)
|
||||
{
|
||||
return cppc_state;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_pstate_get_status);
|
||||
|
||||
int amd_pstate_update_status(const char *buf, size_t size)
|
||||
{
|
||||
int mode_idx;
|
||||
@@ -1416,7 +1449,6 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
|
||||
struct amd_cpudata *cpudata;
|
||||
union perf_cached perf;
|
||||
struct device *dev;
|
||||
u64 value;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@@ -1481,12 +1513,6 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
|
||||
cpudata->epp_default = AMD_CPPC_EPP_BALANCE_PERFORMANCE;
|
||||
}
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_CPPC)) {
|
||||
ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
WRITE_ONCE(cpudata->cppc_req_cached, value);
|
||||
}
|
||||
ret = amd_pstate_set_epp(policy, cpudata->epp_default);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1506,6 +1532,11 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
|
||||
if (cpudata) {
|
||||
union perf_cached perf = READ_ONCE(cpudata->perf);
|
||||
|
||||
/* Reset CPPC_REQ MSR to the BIOS value */
|
||||
amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
|
||||
|
||||
kfree(cpudata);
|
||||
policy->driver_data = NULL;
|
||||
}
|
||||
@@ -1556,21 +1587,38 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_pstate_epp_cpu_online(struct cpufreq_policy *policy)
|
||||
static int amd_pstate_cpu_online(struct cpufreq_policy *policy)
|
||||
{
|
||||
pr_debug("AMD CPU Core %d going online\n", policy->cpu);
|
||||
|
||||
return amd_pstate_cppc_enable(policy);
|
||||
}
|
||||
|
||||
static int amd_pstate_epp_cpu_offline(struct cpufreq_policy *policy)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
|
||||
static int amd_pstate_cpu_offline(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
union perf_cached perf = READ_ONCE(cpudata->perf);
|
||||
|
||||
/*
|
||||
* Reset CPPC_REQ MSR to the BIOS value, this will allow us to retain the BIOS specified
|
||||
* min_perf value across kexec reboots. If this CPU is just onlined normally after this, the
|
||||
* limits, epp and desired perf will get reset to the cached values in cpudata struct
|
||||
*/
|
||||
return amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
|
||||
}
|
||||
|
||||
static int amd_pstate_suspend(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
union perf_cached perf = READ_ONCE(cpudata->perf);
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Reset CPPC_REQ MSR to the BIOS value, this will allow us to retain the BIOS specified
|
||||
* min_perf value across kexec reboots. If this CPU is just resumed back without kexec,
|
||||
* the limits, epp and desired perf will get reset to the cached values in cpudata struct
|
||||
*/
|
||||
ret = amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* invalidate to ensure it's rewritten during resume */
|
||||
cpudata->cppc_req_cached = 0;
|
||||
@@ -1581,6 +1629,17 @@ static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_pstate_resume(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
union perf_cached perf = READ_ONCE(cpudata->perf);
|
||||
int cur_perf = freq_to_perf(perf, cpudata->nominal_freq, policy->cur);
|
||||
|
||||
/* Set CPPC_REQ to last sane value until the governor updates it */
|
||||
return amd_pstate_update_perf(policy, perf.min_limit_perf, cur_perf, perf.max_limit_perf,
|
||||
0U, false);
|
||||
}
|
||||
|
||||
static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
@@ -1606,6 +1665,10 @@ static struct cpufreq_driver amd_pstate_driver = {
|
||||
.fast_switch = amd_pstate_fast_switch,
|
||||
.init = amd_pstate_cpu_init,
|
||||
.exit = amd_pstate_cpu_exit,
|
||||
.online = amd_pstate_cpu_online,
|
||||
.offline = amd_pstate_cpu_offline,
|
||||
.suspend = amd_pstate_suspend,
|
||||
.resume = amd_pstate_resume,
|
||||
.set_boost = amd_pstate_set_boost,
|
||||
.update_limits = amd_pstate_update_limits,
|
||||
.name = "amd-pstate",
|
||||
@@ -1618,9 +1681,9 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
|
||||
.setpolicy = amd_pstate_epp_set_policy,
|
||||
.init = amd_pstate_epp_cpu_init,
|
||||
.exit = amd_pstate_epp_cpu_exit,
|
||||
.offline = amd_pstate_epp_cpu_offline,
|
||||
.online = amd_pstate_epp_cpu_online,
|
||||
.suspend = amd_pstate_epp_suspend,
|
||||
.offline = amd_pstate_cpu_offline,
|
||||
.online = amd_pstate_cpu_online,
|
||||
.suspend = amd_pstate_suspend,
|
||||
.resume = amd_pstate_epp_resume,
|
||||
.update_limits = amd_pstate_update_limits,
|
||||
.set_boost = amd_pstate_set_boost,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
* @lowest_perf: the absolute lowest performance level of the processor
|
||||
* @min_limit_perf: Cached value of the performance corresponding to policy->min
|
||||
* @max_limit_perf: Cached value of the performance corresponding to policy->max
|
||||
* @bios_min_perf: Cached perf value corresponding to the "Requested CPU Min Frequency" BIOS option
|
||||
*/
|
||||
union perf_cached {
|
||||
struct {
|
||||
@@ -39,6 +40,7 @@ union perf_cached {
|
||||
u8 lowest_perf;
|
||||
u8 min_limit_perf;
|
||||
u8 max_limit_perf;
|
||||
u8 bios_min_perf;
|
||||
};
|
||||
u64 val;
|
||||
};
|
||||
@@ -119,6 +121,7 @@ enum amd_pstate_mode {
|
||||
AMD_PSTATE_MAX,
|
||||
};
|
||||
const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode);
|
||||
int amd_pstate_get_status(void);
|
||||
int amd_pstate_update_status(const char *buf, size_t size);
|
||||
|
||||
#endif /* _LINUX_AMD_PSTATE_H */
|
||||
|
||||
Reference in New Issue
Block a user