amd-pstate content for 6.15 (3/6/25)

A lot of code optimization to avoid cases where call paths will end up calling
 the same writes multiple times and needlessly caching variables.  To accomplish
 this some of the writes are now made into an atomically written "perf" variable.
 Locking has been overhauled to ensure it only applies to the necessary functions.
 Tracing has been adjusted to ensure trace events only are used right before
 writing out to the hardware.
 
 NOTE: This is a redo of amd-pstate-v6.15-2025-03-03 with a fixed Fixes tag.
 -----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCgA4FiEECwtuSU6dXvs5GA2aLRkspiR3AnYFAmfJ8w8aHG1hcmlvLmxp
 bW9uY2llbGxvQGFtZC5jb20ACgkQLRkspiR3AnaugQ/9GvheK3/lWweGF3f4ixdl
 xS0XTj3DYQBxDvP2H35QRBHaUQQADJnJLjpl1HHy0x9Hem6m3oLZH3QpqKDLb1xX
 QWzI2JJZ9+KPZRKRwlBnzENcHtBraKX4M/+vvhTo6LSbLfSz47cdZhX6r+9siwPR
 ofWfusfBlEVPPLaul2Q+oOaQzvwy9Or2q2y3xICzo+Vo3QilSk3pekN8bd2CVd9y
 L1t1sAeN1StiOLBRbdbh8B2oyJfCCmSI85P8+sEKKR58G1q42Dv4NRl7fgzuJAfO
 4ATgX0RjNZcI9yLPmLr5PFmHJYvpHr29MAWKAo5a8VwMu1cBTv0FFkEboRvUgiXl
 3+hjQJGkyCZJTxIWhnvKl6Ci00N5apmwc1iMeoa1A1xvvTVkXLmn8RrYIJm2xMCH
 27SPJAQx+7e2cRcgjb3orz2Ymj+I9WoGy68/wdmnWM+ZxF1QaKguhM0lrIKFbu7K
 6CzVnndVgtYt9kFi/SQ4m1e8zr6RnvPWTxqQxTCVQZBNahe3b7DgnrrNrB/NBU86
 QotiTBIxQed6oqHAtL2mFRb9SdTGh9PE5xGcR94qlEGqVtu9KZIFqCDG1OgZKkR5
 9yLLai7sUGfMCLuEsdM5hXvf4fOHaGSQ0Cxx2qYWC3DDnS651fMNKh/taBo8RmS3
 r18loH2dKvBvOi2beCA5sMk=
 =VkdW
 -----END PGP SIGNATURE-----

Merge tag 'amd-pstate-v6.15-2025-03-06' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux

Merge amd-pstate updates for 6.15 (3/6/25) from Mario Limonciello:

"A lot of code optimization to avoid cases where call paths will end up
 calling the same writes multiple times and needlessly caching variables.
 To accomplish this some of the writes are now made into an atomically
 written "perf" variable. Locking has been overhauled to ensure it only
 applies to the necessary functions. Tracing has been adjusted to ensure
 trace events only are used right before writing out to the hardware."

NOTE: This is a redo of amd-pstate-v6.15-2025-03-03 with a fixed Fixes tag.

* tag 'amd-pstate-v6.15-2025-03-06' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux: (29 commits)
  cpufreq/amd-pstate: Drop actions in amd_pstate_epp_cpu_offline()
  cpufreq/amd-pstate: Stop caching EPP
  cpufreq/amd-pstate: Rework CPPC enabling
  cpufreq/amd-pstate: Drop debug statements for policy setting
  cpufreq/amd-pstate: Update cppc_req_cached for shared mem EPP writes
  cpufreq/amd-pstate: Move all EPP tracing into *_update_perf and *_set_epp functions
  cpufreq/amd-pstate: Cache CPPC request in shared mem case too
  cpufreq/amd-pstate: Replace all AMD_CPPC_* macros with masks
  cpufreq/amd-pstate-ut: Adjust variable scope
  cpufreq/amd-pstate-ut: Run on all of the correct CPUs
  cpufreq/amd-pstate-ut: Drop SUCCESS and FAIL enums
  cpufreq/amd-pstate-ut: Allow lowest nonlinear and lowest to be the same
  cpufreq/amd-pstate-ut: Use _free macro to free put policy
  cpufreq/amd-pstate: Drop `cppc_cap1_cached`
  cpufreq/amd-pstate: Overhaul locking
  cpufreq/amd-pstate: Move perf values into a union
  cpufreq/amd-pstate: Drop min and max cached frequencies
  cpufreq/amd-pstate: Show a warning when a CPU fails to setup
  cpufreq/amd-pstate: Invalidate cppc_req_cached during suspend
  cpufreq/amd-pstate: Fix the clamping of perf values
  ...
This commit is contained in:
Rafael J. Wysocki 2025-03-06 21:28:48 +01:00
commit f96d92fcbb
7 changed files with 463 additions and 567 deletions

View File

@ -701,15 +701,17 @@
#define MSR_AMD_CPPC_REQ 0xc00102b3
#define MSR_AMD_CPPC_STATUS 0xc00102b4
#define AMD_CPPC_LOWEST_PERF(x) (((x) >> 0) & 0xff)
#define AMD_CPPC_LOWNONLIN_PERF(x) (((x) >> 8) & 0xff)
#define AMD_CPPC_NOMINAL_PERF(x) (((x) >> 16) & 0xff)
#define AMD_CPPC_HIGHEST_PERF(x) (((x) >> 24) & 0xff)
/* Masks for use with MSR_AMD_CPPC_CAP1 */
#define AMD_CPPC_LOWEST_PERF_MASK GENMASK(7, 0)
#define AMD_CPPC_LOWNONLIN_PERF_MASK GENMASK(15, 8)
#define AMD_CPPC_NOMINAL_PERF_MASK GENMASK(23, 16)
#define AMD_CPPC_HIGHEST_PERF_MASK GENMASK(31, 24)
#define AMD_CPPC_MAX_PERF(x) (((x) & 0xff) << 0)
#define AMD_CPPC_MIN_PERF(x) (((x) & 0xff) << 8)
#define AMD_CPPC_DES_PERF(x) (((x) & 0xff) << 16)
#define AMD_CPPC_ENERGY_PERF_PREF(x) (((x) & 0xff) << 24)
/* Masks for use with MSR_AMD_CPPC_REQ */
#define AMD_CPPC_MAX_PERF_MASK GENMASK(7, 0)
#define AMD_CPPC_MIN_PERF_MASK GENMASK(15, 8)
#define AMD_CPPC_DES_PERF_MASK GENMASK(23, 16)
#define AMD_CPPC_EPP_PERF_MASK GENMASK(31, 24)
/* AMD Performance Counter Global Status and Control MSRs */
#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS 0xc0000300

View File

@ -4,6 +4,8 @@
* Copyright (c) 2016, Intel Corporation.
*/
#include <linux/bitfield.h>
#include <acpi/cppc_acpi.h>
#include <asm/msr.h>
#include <asm/processor.h>
@ -149,7 +151,7 @@ int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
if (ret)
goto out;
val = AMD_CPPC_HIGHEST_PERF(val);
val = FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, val);
} else {
ret = cppc_get_highest_perf(cpu, &val);
if (ret)

View File

@ -24,9 +24,9 @@
TRACE_EVENT(amd_pstate_perf,
TP_PROTO(unsigned long min_perf,
unsigned long target_perf,
unsigned long capacity,
TP_PROTO(u8 min_perf,
u8 target_perf,
u8 capacity,
u64 freq,
u64 mperf,
u64 aperf,
@ -47,9 +47,9 @@ TRACE_EVENT(amd_pstate_perf,
),
TP_STRUCT__entry(
__field(unsigned long, min_perf)
__field(unsigned long, target_perf)
__field(unsigned long, capacity)
__field(u8, min_perf)
__field(u8, target_perf)
__field(u8, capacity)
__field(unsigned long long, freq)
__field(unsigned long long, mperf)
__field(unsigned long long, aperf)
@ -70,10 +70,10 @@ TRACE_EVENT(amd_pstate_perf,
__entry->fast_switch = fast_switch;
),
TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu freq=%llu mperf=%llu aperf=%llu tsc=%llu cpu_id=%u fast_switch=%s",
(unsigned long)__entry->min_perf,
(unsigned long)__entry->target_perf,
(unsigned long)__entry->capacity,
TP_printk("amd_min_perf=%hhu amd_des_perf=%hhu amd_max_perf=%hhu freq=%llu mperf=%llu aperf=%llu tsc=%llu cpu_id=%u fast_switch=%s",
(u8)__entry->min_perf,
(u8)__entry->target_perf,
(u8)__entry->capacity,
(unsigned long long)__entry->freq,
(unsigned long long)__entry->mperf,
(unsigned long long)__entry->aperf,
@ -86,11 +86,12 @@ TRACE_EVENT(amd_pstate_perf,
TRACE_EVENT(amd_pstate_epp_perf,
TP_PROTO(unsigned int cpu_id,
unsigned int highest_perf,
unsigned int epp,
unsigned int min_perf,
unsigned int max_perf,
bool boost
u8 highest_perf,
u8 epp,
u8 min_perf,
u8 max_perf,
bool boost,
bool changed
),
TP_ARGS(cpu_id,
@ -98,15 +99,17 @@ TRACE_EVENT(amd_pstate_epp_perf,
epp,
min_perf,
max_perf,
boost),
boost,
changed),
TP_STRUCT__entry(
__field(unsigned int, cpu_id)
__field(unsigned int, highest_perf)
__field(unsigned int, epp)
__field(unsigned int, min_perf)
__field(unsigned int, max_perf)
__field(u8, highest_perf)
__field(u8, epp)
__field(u8, min_perf)
__field(u8, max_perf)
__field(bool, boost)
__field(bool, changed)
),
TP_fast_assign(
@ -116,15 +119,17 @@ TRACE_EVENT(amd_pstate_epp_perf,
__entry->min_perf = min_perf;
__entry->max_perf = max_perf;
__entry->boost = boost;
__entry->changed = changed;
),
TP_printk("cpu%u: [%u<->%u]/%u, epp=%u, boost=%u",
TP_printk("cpu%u: [%hhu<->%hhu]/%hhu, epp=%hhu, boost=%u, changed=%u",
(unsigned int)__entry->cpu_id,
(unsigned int)__entry->min_perf,
(unsigned int)__entry->max_perf,
(unsigned int)__entry->highest_perf,
(unsigned int)__entry->epp,
(bool)__entry->boost
(u8)__entry->min_perf,
(u8)__entry->max_perf,
(u8)__entry->highest_perf,
(u8)__entry->epp,
(bool)__entry->boost,
(bool)__entry->changed
)
);

View File

@ -22,39 +22,31 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitfield.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/cleanup.h>
#include <acpi/cppc_acpi.h>
#include "amd-pstate.h"
/*
* Abbreviations:
* amd_pstate_ut: used as a shortform for AMD P-State unit test.
* It helps to keep variable names smaller, simpler
*/
enum amd_pstate_ut_result {
AMD_PSTATE_UT_RESULT_PASS,
AMD_PSTATE_UT_RESULT_FAIL,
};
struct amd_pstate_ut_struct {
const char *name;
void (*func)(u32 index);
enum amd_pstate_ut_result result;
int (*func)(u32 index);
};
/*
* Kernel module for testing the AMD P-State unit test
*/
static void amd_pstate_ut_acpi_cpc_valid(u32 index);
static void amd_pstate_ut_check_enabled(u32 index);
static void amd_pstate_ut_check_perf(u32 index);
static void amd_pstate_ut_check_freq(u32 index);
static void amd_pstate_ut_check_driver(u32 index);
static int amd_pstate_ut_acpi_cpc_valid(u32 index);
static int amd_pstate_ut_check_enabled(u32 index);
static int amd_pstate_ut_check_perf(u32 index);
static int amd_pstate_ut_check_freq(u32 index);
static int amd_pstate_ut_check_driver(u32 index);
static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
{"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid },
@ -77,71 +69,67 @@ static bool get_shared_mem(void)
/*
* check the _CPC object is present in SBIOS.
*/
static void amd_pstate_ut_acpi_cpc_valid(u32 index)
static int amd_pstate_ut_acpi_cpc_valid(u32 index)
{
if (acpi_cpc_valid())
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
else {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
if (!acpi_cpc_valid()) {
pr_err("%s the _CPC object is not present in SBIOS!\n", __func__);
return -EINVAL;
}
}
static void amd_pstate_ut_pstate_enable(u32 index)
{
int ret = 0;
u64 cppc_enable = 0;
ret = rdmsrl_safe(MSR_AMD_CPPC_ENABLE, &cppc_enable);
if (ret) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s rdmsrl_safe MSR_AMD_CPPC_ENABLE ret=%d error!\n", __func__, ret);
return;
}
if (cppc_enable)
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
else {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s amd pstate must be enabled!\n", __func__);
}
return 0;
}
/*
* check if amd pstate is enabled
*/
static void amd_pstate_ut_check_enabled(u32 index)
static int amd_pstate_ut_check_enabled(u32 index)
{
u64 cppc_enable = 0;
int ret;
if (get_shared_mem())
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
else
amd_pstate_ut_pstate_enable(index);
return 0;
ret = rdmsrl_safe(MSR_AMD_CPPC_ENABLE, &cppc_enable);
if (ret) {
pr_err("%s rdmsrl_safe MSR_AMD_CPPC_ENABLE ret=%d error!\n", __func__, ret);
return ret;
}
if (!cppc_enable) {
pr_err("%s amd pstate must be enabled!\n", __func__);
return -EINVAL;
}
return 0;
}
/*
* check if performance values are reasonable.
* highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0
*/
static void amd_pstate_ut_check_perf(u32 index)
static int amd_pstate_ut_check_perf(u32 index)
{
int cpu = 0, ret = 0;
u32 highest_perf = 0, nominal_perf = 0, lowest_nonlinear_perf = 0, lowest_perf = 0;
u64 cap1 = 0;
struct cppc_perf_caps cppc_perf;
struct cpufreq_policy *policy = NULL;
struct amd_cpudata *cpudata = NULL;
union perf_cached cur_perf;
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
struct amd_cpudata *cpudata;
for_each_possible_cpu(cpu) {
policy = cpufreq_cpu_get(cpu);
if (!policy)
break;
continue;
cpudata = policy->driver_data;
if (get_shared_mem()) {
ret = cppc_get_perf_caps(cpu, &cppc_perf);
if (ret) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret);
goto skip_test;
return ret;
}
highest_perf = cppc_perf.highest_perf;
@ -151,50 +139,44 @@ static void amd_pstate_ut_check_perf(u32 index)
} else {
ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
if (ret) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret);
goto skip_test;
return ret;
}
highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
nominal_perf = AMD_CPPC_NOMINAL_PERF(cap1);
lowest_nonlinear_perf = AMD_CPPC_LOWNONLIN_PERF(cap1);
lowest_perf = AMD_CPPC_LOWEST_PERF(cap1);
highest_perf = FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1);
nominal_perf = FIELD_GET(AMD_CPPC_NOMINAL_PERF_MASK, cap1);
lowest_nonlinear_perf = FIELD_GET(AMD_CPPC_LOWNONLIN_PERF_MASK, cap1);
lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
}
if (highest_perf != READ_ONCE(cpudata->highest_perf) && !cpudata->hw_prefcore) {
cur_perf = READ_ONCE(cpudata->perf);
if (highest_perf != cur_perf.highest_perf && !cpudata->hw_prefcore) {
pr_err("%s cpu%d highest=%d %d highest perf doesn't match\n",
__func__, cpu, highest_perf, cpudata->highest_perf);
goto skip_test;
__func__, cpu, highest_perf, cur_perf.highest_perf);
return -EINVAL;
}
if ((nominal_perf != READ_ONCE(cpudata->nominal_perf)) ||
(lowest_nonlinear_perf != READ_ONCE(cpudata->lowest_nonlinear_perf)) ||
(lowest_perf != READ_ONCE(cpudata->lowest_perf))) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
if (nominal_perf != cur_perf.nominal_perf ||
(lowest_nonlinear_perf != cur_perf.lowest_nonlinear_perf) ||
(lowest_perf != cur_perf.lowest_perf)) {
pr_err("%s cpu%d nominal=%d %d lowest_nonlinear=%d %d lowest=%d %d, they should be equal!\n",
__func__, cpu, nominal_perf, cpudata->nominal_perf,
lowest_nonlinear_perf, cpudata->lowest_nonlinear_perf,
lowest_perf, cpudata->lowest_perf);
goto skip_test;
__func__, cpu, nominal_perf, cur_perf.nominal_perf,
lowest_nonlinear_perf, cur_perf.lowest_nonlinear_perf,
lowest_perf, cur_perf.lowest_perf);
return -EINVAL;
}
if (!((highest_perf >= nominal_perf) &&
(nominal_perf > lowest_nonlinear_perf) &&
(lowest_nonlinear_perf > lowest_perf) &&
(lowest_nonlinear_perf >= lowest_perf) &&
(lowest_perf > 0))) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cpu%d highest=%d >= nominal=%d > lowest_nonlinear=%d > lowest=%d > 0, the formula is incorrect!\n",
__func__, cpu, highest_perf, nominal_perf,
lowest_nonlinear_perf, lowest_perf);
goto skip_test;
return -EINVAL;
}
cpufreq_cpu_put(policy);
}
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
return;
skip_test:
cpufreq_cpu_put(policy);
return 0;
}
/*
@ -202,59 +184,50 @@ static void amd_pstate_ut_check_perf(u32 index)
* max_freq >= nominal_freq > lowest_nonlinear_freq > min_freq > 0
* check max freq when set support boost mode.
*/
static void amd_pstate_ut_check_freq(u32 index)
static int amd_pstate_ut_check_freq(u32 index)
{
int cpu = 0;
struct cpufreq_policy *policy = NULL;
struct amd_cpudata *cpudata = NULL;
for_each_possible_cpu(cpu) {
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
struct amd_cpudata *cpudata;
policy = cpufreq_cpu_get(cpu);
if (!policy)
break;
continue;
cpudata = policy->driver_data;
if (!((cpudata->max_freq >= cpudata->nominal_freq) &&
if (!((policy->cpuinfo.max_freq >= cpudata->nominal_freq) &&
(cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) &&
(cpudata->lowest_nonlinear_freq > cpudata->min_freq) &&
(cpudata->min_freq > 0))) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
(cpudata->lowest_nonlinear_freq >= policy->cpuinfo.min_freq) &&
(policy->cpuinfo.min_freq > 0))) {
pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n",
__func__, cpu, cpudata->max_freq, cpudata->nominal_freq,
cpudata->lowest_nonlinear_freq, cpudata->min_freq);
goto skip_test;
__func__, cpu, policy->cpuinfo.max_freq, cpudata->nominal_freq,
cpudata->lowest_nonlinear_freq, policy->cpuinfo.min_freq);
return -EINVAL;
}
if (cpudata->lowest_nonlinear_freq != policy->min) {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n",
__func__, cpu, cpudata->lowest_nonlinear_freq, policy->min);
goto skip_test;
return -EINVAL;
}
if (cpudata->boost_supported) {
if ((policy->max == cpudata->max_freq) ||
(policy->max == cpudata->nominal_freq))
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
else {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
if ((policy->max != policy->cpuinfo.max_freq) &&
(policy->max != cpudata->nominal_freq)) {
pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n",
__func__, cpu, policy->max, cpudata->max_freq,
__func__, cpu, policy->max, policy->cpuinfo.max_freq,
cpudata->nominal_freq);
goto skip_test;
return -EINVAL;
}
} else {
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
pr_err("%s cpu%d must support boost!\n", __func__, cpu);
goto skip_test;
return -EINVAL;
}
cpufreq_cpu_put(policy);
}
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
return;
skip_test:
cpufreq_cpu_put(policy);
return 0;
}
static int amd_pstate_set_mode(enum amd_pstate_mode mode)
@ -266,32 +239,28 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
return amd_pstate_update_status(mode_str, strlen(mode_str));
}
static void amd_pstate_ut_check_driver(u32 index)
static int amd_pstate_ut_check_driver(u32 index)
{
enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
int ret;
for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
ret = amd_pstate_set_mode(mode1);
int ret = amd_pstate_set_mode(mode1);
if (ret)
goto out;
return ret;
for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) {
if (mode1 == mode2)
continue;
ret = amd_pstate_set_mode(mode2);
if (ret)
goto out;
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;
}
}
}
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_ut_cases[index].result = ret ?
AMD_PSTATE_UT_RESULT_FAIL :
AMD_PSTATE_UT_RESULT_PASS;
return 0;
}
static int __init amd_pstate_ut_init(void)
@ -299,16 +268,12 @@ static int __init amd_pstate_ut_init(void)
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
for (i = 0; i < arr_size; i++) {
amd_pstate_ut_cases[i].func(i);
switch (amd_pstate_ut_cases[i].result) {
case AMD_PSTATE_UT_RESULT_PASS:
int ret = amd_pstate_ut_cases[i].func(i);
if (ret)
pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret);
else
pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name);
break;
case AMD_PSTATE_UT_RESULT_FAIL:
default:
pr_info("%-4d %-20s\t fail!\n", i+1, amd_pstate_ut_cases[i].name);
break;
}
}
return 0;

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,36 @@
/*********************************************************************
* AMD P-state INTERFACE *
*********************************************************************/
/**
* union perf_cached - A union to cache performance-related data.
* @highest_perf: the maximum performance an individual processor may reach,
* assuming ideal conditions
* For platforms that support the preferred core feature, the highest_perf value maybe
* configured to any value in the range 166-255 by the firmware (because the preferred
* core ranking is encoded in the highest_perf value). To maintain consistency across
* all platforms, we split the highest_perf and preferred core ranking values into
* cpudata->perf.highest_perf and cpudata->prefcore_ranking.
* @nominal_perf: the maximum sustained performance level of the processor,
* assuming ideal operating conditions
* @lowest_nonlinear_perf: the lowest performance level at which nonlinear power
* savings are achieved
* @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
*/
union perf_cached {
struct {
u8 highest_perf;
u8 nominal_perf;
u8 lowest_nonlinear_perf;
u8 lowest_perf;
u8 min_limit_perf;
u8 max_limit_perf;
};
u64 val;
};
/**
* struct amd_aperf_mperf
* @aperf: actual performance frequency clock count
@ -30,24 +60,11 @@ struct amd_aperf_mperf {
* @cpu: CPU number
* @req: constraint request to apply
* @cppc_req_cached: cached performance request hints
* @highest_perf: the maximum performance an individual processor may reach,
* assuming ideal conditions
* For platforms that do not support the preferred core feature, the
* highest_pef may be configured with 166 or 255, to avoid max frequency
* calculated wrongly. we take the fixed value as the highest_perf.
* @nominal_perf: the maximum sustained performance level of the processor,
* assuming ideal operating conditions
* @lowest_nonlinear_perf: the lowest performance level at which nonlinear power
* savings are achieved
* @lowest_perf: the absolute lowest performance level of the processor
* @perf: cached performance-related data
* @prefcore_ranking: the preferred core ranking, the higher value indicates a higher
* priority.
* @min_limit_perf: Cached value of the performance corresponding to policy->min
* @max_limit_perf: Cached value of the performance corresponding to policy->max
* @min_limit_freq: Cached value of policy->min (in khz)
* @max_limit_freq: Cached value of policy->max (in khz)
* @max_freq: the frequency (in khz) that mapped to highest_perf
* @min_freq: the frequency (in khz) that mapped to lowest_perf
* @nominal_freq: the frequency (in khz) that mapped to nominal_perf
* @lowest_nonlinear_freq: the frequency (in khz) that mapped to lowest_nonlinear_perf
* @cur: Difference of Aperf/Mperf/tsc count between last and current sample
@ -59,7 +76,6 @@ struct amd_aperf_mperf {
* AMD P-State driver supports preferred core featue.
* @epp_cached: Cached CPPC energy-performance preference value
* @policy: Cpufreq policy value
* @cppc_cap1_cached Cached MSR_AMD_CPPC_CAP1 register value
*
* The amd_cpudata is key private data for each CPU thread in AMD P-State, and
* represents all the attributes and goals that AMD P-State requests at runtime.
@ -70,18 +86,11 @@ struct amd_cpudata {
struct freq_qos_request req[2];
u64 cppc_req_cached;
u32 highest_perf;
u32 nominal_perf;
u32 lowest_nonlinear_perf;
u32 lowest_perf;
u32 prefcore_ranking;
u32 min_limit_perf;
u32 max_limit_perf;
u32 min_limit_freq;
u32 max_limit_freq;
union perf_cached perf;
u32 max_freq;
u32 min_freq;
u8 prefcore_ranking;
u32 min_limit_freq;
u32 max_limit_freq;
u32 nominal_freq;
u32 lowest_nonlinear_freq;
@ -93,11 +102,9 @@ struct amd_cpudata {
bool hw_prefcore;
/* EPP feature related attributes*/
s16 epp_cached;
u32 policy;
u64 cppc_cap1_cached;
bool suspended;
s16 epp_default;
u8 epp_default;
};
/*

View File

@ -210,6 +210,9 @@ static inline struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
static inline void cpufreq_cpu_put(struct cpufreq_policy *policy) { }
#endif
/* Scope based cleanup macro for cpufreq_policy kobject reference counting */
DEFINE_FREE(put_cpufreq_policy, struct cpufreq_policy *, if (_T) cpufreq_cpu_put(_T))
static inline bool policy_is_inactive(struct cpufreq_policy *policy)
{
return cpumask_empty(policy->cpus);