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