Skip to content

Commit

Permalink
Merge tag 'amd-pstate-v6.11-2024-06-26' of ssh://gitolite.kernel.org/…
Browse files Browse the repository at this point in the history
…pub/scm/linux/kernel/git/superm1/linux

Merge more amd-pstate driver updates for 6.11 from Mario Limonciello:

"Add support for amd-pstate core performance boost support which
 allows controlling which CPU cores can operate above nominal
 frequencies for short periods of time."

* tag 'amd-pstate-v6.11-2024-06-26' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux:
  Documentation: cpufreq: amd-pstate: update doc for Per CPU boost control method
  cpufreq: amd-pstate: Cap the CPPC.max_perf to nominal_perf if CPB is off
  cpufreq: amd-pstate: initialize core precision boost state
  cpufreq: acpi: move MSR_K7_HWCR_CPB_DIS_BIT into msr-index.h
  • Loading branch information
Rafael J. Wysocki committed Jun 27, 2024
2 parents b11ec63 + 6d58889 commit f53b4bb
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 24 deletions.
16 changes: 16 additions & 0 deletions Documentation/admin-guide/pm/amd-pstate.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,22 @@ 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.

Other performance and frequency values can be read back from
``/sys/devices/system/cpu/cpuX/acpi_cppc/``, see :ref:`cppc_sysfs`.

Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/msr-index.h
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,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
Expand Down
2 changes: 0 additions & 2 deletions drivers/cpufreq/acpi-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
122 changes: 100 additions & 22 deletions drivers/cpufreq/amd-pstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
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,
Expand All @@ -536,6 +537,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 (!cpudata->boost_supported)
max_perf = min_t(unsigned long, nominal_perf, max_perf);

value &= ~AMD_CPPC_MAX_PERF(~0L);
value |= AMD_CPPC_MAX_PERF(max_perf);

Expand Down Expand Up @@ -679,43 +684,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 +1035,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 +1051,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 +1078,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 +1492,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 +1511,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 +1534,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 +1795,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 f53b4bb

Please sign in to comment.