Skip to content

Commit

Permalink
cpufreq: amd-pstate: initialize core precision boost state
Browse files Browse the repository at this point in the history
The "Core Performance Boost (CPB) feature, when enabled in the BIOS,
allows the OS to control the highest performance for each individual
core. The active, passive and the guided modes of the amd-pstate driver
do support controlling the core frequency boost when this BIOS feature
is enabled. Additionally, the amd-pstate driver provides a sysfs
interface allowing the user to activate/deactivate this core performance
boost feature at runtime.

Add support for the set_boost callback in the active mode driver to
enable boost control via the cpufreq core. This ensures a consistent
boost control interface across all pstate modes, including passive
mode, guided mode, and active mode.

With this addition, all three pstate modes can support the same boost
control interface with unique interface and global CPB control. Each
CPU also supports individual boost control, allowing global CPB to
change all cores' boost states simultaneously. Specific CPUs can
update their boost states separately, ensuring all cores' boost
states are synchronized.

Cc: Oleksandr Natalenko <oleksandr@natalenko.name>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217931
Signed-off-by: Perry Yuan <Perry.Yuan@amd.com>
Co-developed-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
Link: https://lore.kernel.org/r/20240626042733.3747-3-mario.limonciello@amd.com
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
  • Loading branch information
Perry Yuan authored and Mario Limonciello committed Jun 26, 2024
1 parent 4f460bf commit c8c68c3
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 22 deletions.
117 changes: 95 additions & 22 deletions drivers/cpufreq/amd-pstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,43 +679,105 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
cpufreq_cpu_put(policy);
}

static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state)
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;

if (!cpudata->boost_supported) {
pr_err("Boost mode is not supported by this processor or SBIOS\n");
return -EINVAL;
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 (state)
policy->cpuinfo.max_freq = cpudata->max_freq;
else
policy->cpuinfo.max_freq = cpudata->nominal_freq * 1000;
if (on)
policy->cpuinfo.max_freq = max_freq;
else if (policy->cpuinfo.max_freq > nominal_freq * 1000)
policy->cpuinfo.max_freq = 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;
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 0;
return ret < 0 ? ret : 0;
}

static void amd_pstate_boost_init(struct amd_cpudata *cpudata)
static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state)
{
u32 highest_perf, nominal_perf;
struct amd_cpudata *cpudata = policy->driver_data;
int ret;

highest_perf = READ_ONCE(cpudata->highest_perf);
nominal_perf = READ_ONCE(cpudata->nominal_perf);
if (!cpudata->boost_supported) {
pr_err("Boost mode is not supported by this processor or SBIOS\n");
return -EOPNOTSUPP;
}
mutex_lock(&amd_pstate_driver_lock);
ret = amd_pstate_cpu_boost_update(policy, state);
WRITE_ONCE(cpudata->boost_state, !ret ? state : false);
policy->boost_enabled = !ret ? state : false;
refresh_frequency_limits(policy);
mutex_unlock(&amd_pstate_driver_lock);

if (highest_perf <= nominal_perf)
return;
return ret;
}

cpudata->boost_supported = true;
static int amd_pstate_init_boost_support(struct amd_cpudata *cpudata)
{
u64 boost_val;
int ret = -1;

/*
* If platform has no CPB support or disable 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;
}

/* at least one CPU supports CPB, even if others fail later on to set up */
current_pstate_driver->boost_enabled = true;

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;
}

if (!(boost_val & MSR_K7_HWCR_CPB_DIS))
cpudata->boost_supported = true;

return 0;

exit_err:
cpudata->boost_supported = false;
return ret;
}

static void amd_perf_ctl_reset(unsigned int cpu)
Expand Down Expand Up @@ -968,6 +1030,10 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
if (ret)
goto free_cpudata1;

ret = amd_pstate_init_boost_support(cpudata);
if (ret)
goto free_cpudata1;

min_freq = READ_ONCE(cpudata->min_freq);
max_freq = READ_ONCE(cpudata->max_freq);

Expand All @@ -980,6 +1046,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = min_freq;
policy->cpuinfo.max_freq = max_freq;

policy->boost_enabled = READ_ONCE(cpudata->boost_supported);

/* It will be updated by governor */
policy->cur = policy->cpuinfo.min_freq;

Expand All @@ -1005,7 +1073,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;

Expand Down Expand Up @@ -1420,6 +1487,10 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
if (ret)
goto free_cpudata1;

ret = amd_pstate_init_boost_support(cpudata);
if (ret)
goto free_cpudata1;

min_freq = READ_ONCE(cpudata->min_freq);
max_freq = READ_ONCE(cpudata->max_freq);

Expand All @@ -1435,6 +1506,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;

policy->boost_enabled = READ_ONCE(cpudata->boost_supported);

/*
* Set the policy to provide a valid fallback value in case
* the default cpufreq governor is neither powersave nor performance.
Expand All @@ -1456,7 +1529,6 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
return ret;
WRITE_ONCE(cpudata->cppc_cap1_cached, value);
}
amd_pstate_boost_init(cpudata);

return 0;

Expand Down Expand Up @@ -1718,6 +1790,7 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
.suspend = amd_pstate_epp_suspend,
.resume = amd_pstate_epp_resume,
.update_limits = amd_pstate_update_limits,
.set_boost = amd_pstate_set_boost,
.name = "amd-pstate-epp",
.attr = amd_pstate_epp_attr,
};
Expand Down
1 change: 1 addition & 0 deletions drivers/cpufreq/amd-pstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ struct amd_cpudata {
u64 cppc_cap1_cached;
bool suspended;
s16 epp_default;
bool boost_state;
};

#endif /* _LINUX_AMD_PSTATE_H */

0 comments on commit c8c68c3

Please sign in to comment.