mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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. -----BEGIN PGP SIGNATURE----- iQJOBAABCgA4FiEECwtuSU6dXvs5GA2aLRkspiR3AnYFAmZ8fvEaHG1hcmlvLmxp bW9uY2llbGxvQGFtZC5jb20ACgkQLRkspiR3AnbmPQ/9FrmbFf8t0e7WQJ7wrlHz 8HmeHGLNLQbOWLrNPP2um+33i97hxJ+h8RHnPnr9wzdDl1R+u2oR1vu5DXCYgBBA d9rLJv1YSFnEu9VPklAHWMyHHb+F6OsUyk6yPl8R50j2E3HOb/TjwLxIfxC0C80p ox2ffArMfO5iKEAcVkpKQuh0prWDoxl4eQ8UI2DoKLMu1UyZRmH/jWL8l1qNGpwF 4nRwYl4xERF2qnMaszN+QZREirmXwzU5y1gylx25qKDpFwzotulkEyQDGVPfqBr2 kTz0mvc+i1mrJ2P5MG5gi1Mgsxd5dA1VPhYDk+4vgE+oPnJp3kdBtOKWfkmN+mgn PB6gFMWJFpLm/Kl4Lu8TS3m+aE0Euctcu/pVYEhxeP5bEJ82gbxgT9/kd2hfMtMi 6QbBTIpoJcLnUuMEaOXRYlpuAmaG3cp/gDI4UO8tid+BgoyGbOK8fkToL2s0mIFx JrH19ZBAEXSWcoMQVmY118H8Uy4J+1IsA4IlZweTV0ZQPQ/W8VQ2blfyvRo7dSGj JtGhkOYtXdtYKahqC06fyi5lfzy+huiLjQElBOFWTl5x+usntpeCuJrG2kZ/gAiS gxVsL1FX6J7cxN866ty3jdwNYwOt5/JwG/oq3buBCeKYobQB3qY9bK6V42siC+Qv bcmTcy0lrfzZoNW5fvo3JZE= =EZq/ -----END PGP SIGNATURE----- Merge tag 'amd-pstate-v6.11-2024-06-26' of ssh://gitolite.kernel.org/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
This commit is contained in:
commit
f53b4bb83d
@ -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`.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
@ -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);
|
||||
|
||||
@ -679,6 +684,53 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
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 if (policy->cpuinfo.max_freq > nominal_freq * 1000)
|
||||
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_set_boost(struct cpufreq_policy *policy, int state)
|
||||
{
|
||||
struct amd_cpudata *cpudata = policy->driver_data;
|
||||
@ -686,36 +738,51 @@ 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 -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 (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;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
if (highest_perf <= nominal_perf)
|
||||
return;
|
||||
|
||||
cpudata->boost_supported = true;
|
||||
/* 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)
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
@ -100,6 +100,7 @@ struct amd_cpudata {
|
||||
u64 cppc_cap1_cached;
|
||||
bool suspended;
|
||||
s16 epp_default;
|
||||
bool boost_state;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_AMD_PSTATE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user