summaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-07-31 19:36:04 +0200
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2026-07-31 19:36:04 +0200
commiteb49643e66e0dd0b989e30a1c556e8c5d5398dc0 (patch)
tree86d7e8dfebd3873b8cdc771692a6fe5400b6e5fa /drivers/cpufreq
parent9e4cb21f2940230efc09f90c8335b5cbb3e26c41 (diff)
parentd06c75c22d5c95ee27e01fedcaa07231c9bd5c88 (diff)
downloadlinux-next-eb49643e66e0dd0b989e30a1c556e8c5d5398dc0.tar.gz
linux-next-eb49643e66e0dd0b989e30a1c556e8c5d5398dc0.zip
Merge tag 'amd-pstate-v7.3-2026-07-30' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux
Pull amd-pstate 7.3 content (07/30/26) from Mario Limonciello: "* Changes for dynamic EPP * Adjustments to the bios min perf feature * Fixes to kernel doc" * tag 'amd-pstate-v7.3-2026-07-30' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux: cpufreq/amd-pstate: Document missing kernel-doc members cpufreq/amd-pstate-ut: Add unit test for CPPC Performance Priority cpufreq/amd-pstate-ut: Add unit test for "dynamic" EPP mode cpufreq/amd-pstate: Reduce the scope of exported symbols Documentation/amd-pstate: Update dynamic_epp documentation with new behavior cpufreq/amd-pstate: Remove "amd_dynamic_epp" cmdline and "dynamic_epp" sysfs cpufreq/amd-pstate: Add dynamic EPP as an "energy_performance_preference" mode cpufreq/amd-pstate: Extract platform profile to EPP conversion into a helper cpufreq/amd-pstate: Remove the defensive check for bios_min_perf cpufreq/amd-pstate: Set min_limit_freq based on bios_min_perf
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/amd-pstate-ut.c131
-rw-r--r--drivers/cpufreq/amd-pstate.c243
-rw-r--r--drivers/cpufreq/amd-pstate.h15
3 files changed, 242 insertions, 147 deletions
diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c
index 2142838ad6cc..e23773680e05 100644
--- a/drivers/cpufreq/amd-pstate-ut.c
+++ b/drivers/cpufreq/amd-pstate-ut.c
@@ -59,6 +59,7 @@ static int amd_pstate_ut_check_freq(u32 index);
static int amd_pstate_ut_epp(u32 index);
static int amd_pstate_ut_check_driver(u32 index);
static int amd_pstate_ut_check_freq_attrs(u32 index);
+static int amd_pstate_ut_check_floor_freq(u32 index);
static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
{"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid },
@@ -68,6 +69,7 @@ static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
{"amd_pstate_ut_epp", amd_pstate_ut_epp },
{"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver },
{"amd_pstate_ut_check_freq_attrs", amd_pstate_ut_check_freq_attrs },
+ {"amd_pstate_ut_check_floor_freq", amd_pstate_ut_check_floor_freq },
};
static bool test_in_list(const char *list, const char *name)
@@ -275,6 +277,7 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
static int amd_pstate_ut_epp(u32 index)
{
static const char * const epp_strings[] = {
+ "dynamic",
"power",
"balance_power",
"balance_performance",
@@ -282,10 +285,10 @@ static int amd_pstate_ut_epp(u32 index)
};
char *buf __free(cleanup_page) = NULL;
struct cpufreq_policy *policy = NULL;
+ unsigned long orig_dynamic_epp = 0;
enum amd_pstate_mode orig_mode;
struct amd_cpudata *cpudata;
unsigned long orig_policy;
- bool orig_dynamic_epp;
int ret, cpu = 0;
u16 epp;
int i;
@@ -294,9 +297,11 @@ static int amd_pstate_ut_epp(u32 index)
if (!policy)
return -ENODEV;
- cpudata = policy->driver_data;
orig_mode = amd_pstate_get_status();
- orig_dynamic_epp = cpudata->dynamic_epp;
+ if (policy->driver_data) {
+ cpudata = policy->driver_data;
+ orig_dynamic_epp = cpudata->dynamic_epp;
+ }
/* Drop reference before potential driver change. */
cpufreq_cpu_put(policy);
@@ -321,16 +326,6 @@ static int amd_pstate_ut_epp(u32 index)
orig_policy = cpudata->policy;
cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
- /*
- * Disable dynamic EPP before running test. If "orig_dynamic_epp" is
- * true, the driver will do a redundant switch at the end and there
- * is no need for enabling it again at the end of the test.
- */
- if (cpudata->dynamic_epp) {
- pr_debug("Dynamic EPP is enabled, disabling it\n");
- amd_pstate_clear_dynamic_epp(policy);
- }
-
for (epp = 0; epp <= U8_MAX; epp++) {
u8 val;
@@ -367,6 +362,11 @@ static int amd_pstate_ut_epp(u32 index)
if (ret < 0)
goto out;
strreplace(buf, '\n', '\0');
+ /*
+ * "dynamic" mode reports the EPP as "dynamic(profile:X)"
+ * Trim at "(" and just compare tie the epp string.
+ */
+ strreplace(buf, '(', '\0');
if (strcmp(buf, epp_strings[i])) {
pr_err("String EPP value mismatch: %s != %s\n", buf, epp_strings[i]);
@@ -380,18 +380,23 @@ static int amd_pstate_ut_epp(u32 index)
out:
if (policy) {
cpudata->policy = orig_policy;
+ /*
+ * If the driver had enabled dynamic_epp to begin with,
+ * restore it here before dropping policy reference.
+ */
+ if (orig_dynamic_epp) {
+ int ret2;
+
+ ret2 = store_energy_performance_preference(policy,
+ epp_strings[0],
+ strlen(epp_strings[0]));
+ if (!ret && (ret2 < 0))
+ ret = ret2;
+ }
up_write(&policy->rwsem);
cpufreq_cpu_put(policy);
}
- if (orig_dynamic_epp) {
- int ret2;
-
- ret2 = amd_pstate_set_mode(AMD_PSTATE_DISABLE);
- if (!ret && ret2)
- ret = ret2;
- }
-
if (orig_mode != amd_pstate_get_status()) {
int ret2;
@@ -557,6 +562,80 @@ out:
return ret;
}
+static int amd_pstate_ut_check_floor_freq(u32 index)
+{
+ struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
+ char *buf __free(cleanup_page) = NULL;
+ unsigned int orig_floor_freq;
+ unsigned int floor_freq;
+ int ret, cpu = 0;
+
+ if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO))
+ return -EOPNOTSUPP;
+
+ policy = cpufreq_cpu_get(cpu);
+ if (!policy)
+ return -ENODEV;
+
+ buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ guard(rwsem_write)(&policy->rwsem);
+
+ if (!policy->driver_data)
+ return -ENODEV;
+
+ /* Retrieve original floor frequency */
+ memset(buf, 0, PAGE_SIZE);
+ ret = show_amd_pstate_floor_freq(policy, buf);
+ if (ret < 0)
+ return ret;
+
+ ret = kstrtou32(buf, 0, &orig_floor_freq);
+ if (ret)
+ return ret;
+
+ memset(buf, 0, PAGE_SIZE);
+ snprintf(buf, PAGE_SIZE, "%u", policy->cpuinfo.min_freq);
+
+ /* Set floor frequency to cpuinfo.min_freq */
+ ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf));
+ if (ret < 0) {
+ pr_err("Failed to set floor frequency to %s\n", buf);
+ return ret;
+ }
+
+ memset(buf, 0, PAGE_SIZE);
+ ret = show_amd_pstate_floor_freq(policy, buf);
+ if (ret < 0)
+ return ret;
+
+ strreplace(buf, '\n', '\0');
+ ret = kstrtou32(buf, 0, &floor_freq);
+ if (ret)
+ return ret;
+
+ /* Confirm sysfs reflects the change correctly. */
+ if (floor_freq != policy->cpuinfo.min_freq) {
+ pr_err("Floor frequency value mismatch: %u != %u\n",
+ floor_freq, policy->cpuinfo.min_freq);
+ return -EINVAL;
+ }
+
+ memset(buf, 0, PAGE_SIZE);
+ snprintf(buf, PAGE_SIZE, "%u", orig_floor_freq);
+
+ /* Restore the original value. */
+ ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf));
+ if (ret < 0) {
+ pr_err("Failed to restore floor frequency to %s\n", buf);
+ return ret;
+ }
+
+ return 0;
+}
+
static int __init amd_pstate_ut_init(void)
{
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
@@ -575,10 +654,16 @@ static int __init amd_pstate_ut_init(void)
ret = amd_pstate_ut_cases[i].func(i);
- if (ret)
+ if (ret) {
+ /* Platform does not support the feature being tested. */
+ if (ret == -EOPNOTSUPP) {
+ pr_err("%-4d %-20s\t skipped!\n", i+1, amd_pstate_ut_cases[i].name);
+ continue;
+ }
pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret);
- else
+ } else {
pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name);
+ }
}
return 0;
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 6e255a22a0b8..d4ff8b228f86 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -75,7 +75,7 @@ const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode)
mode = AMD_PSTATE_UNDEFINED;
return amd_pstate_mode_string[mode];
}
-EXPORT_SYMBOL_GPL(amd_pstate_get_mode_string);
+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_get_mode_string);
struct quirk_entry {
u32 nominal_freq;
@@ -87,7 +87,6 @@ static struct cpufreq_driver amd_pstate_driver;
static struct cpufreq_driver amd_pstate_epp_driver;
static int cppc_state = AMD_PSTATE_UNDEFINED;
static bool amd_pstate_prefcore = true;
-static bool dynamic_epp;
static struct quirk_entry *quirks;
/*
@@ -106,6 +105,7 @@ static struct quirk_entry *quirks;
* 3 balance_power
* 4 power
* 5 custom (for raw EPP values)
+ * 6 dynamic (platform profile driven selection)
*/
enum energy_perf_value_index {
EPP_INDEX_DEFAULT = 0,
@@ -114,6 +114,7 @@ enum energy_perf_value_index {
EPP_INDEX_BALANCE_POWERSAVE,
EPP_INDEX_POWERSAVE,
EPP_INDEX_CUSTOM,
+ EPP_INDEX_DYNAMIC,
EPP_INDEX_MAX,
};
@@ -124,6 +125,7 @@ static const char * const energy_perf_strings[] = {
[EPP_INDEX_BALANCE_POWERSAVE] = "balance_power",
[EPP_INDEX_POWERSAVE] = "power",
[EPP_INDEX_CUSTOM] = "custom",
+ [EPP_INDEX_DYNAMIC] = "dynamic",
};
static_assert(ARRAY_SIZE(energy_perf_strings) == EPP_INDEX_MAX);
@@ -134,7 +136,7 @@ static unsigned int epp_values[] = {
[EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_BALANCE_POWERSAVE,
[EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_POWERSAVE,
};
-static_assert(ARRAY_SIZE(epp_values) == EPP_INDEX_MAX - 1);
+static_assert(ARRAY_SIZE(epp_values) == EPP_INDEX_MAX - 2);
typedef int (*cppc_mode_transition_fn)(int);
@@ -462,7 +464,6 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
{
union perf_cached perf = READ_ONCE(cpudata->perf);
u64 cap1, numerator, cppc_req;
- u8 min_perf;
int ret = rdmsrq_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
&cap1);
@@ -478,16 +479,6 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
return ret;
WRITE_ONCE(cpudata->cppc_req_cached, cppc_req);
- min_perf = FIELD_GET(AMD_CPPC_MIN_PERF_MASK, cppc_req);
-
- /*
- * Clear out the min_perf part to check if the rest of the MSR is 0, if yes, this is an
- * indication that the min_perf value is the one specified through the BIOS option
- */
- cppc_req &= ~(AMD_CPPC_MIN_PERF_MASK);
-
- if (!cppc_req)
- perf.bios_min_perf = min_perf;
perf.highest_perf = numerator;
perf.max_limit_perf = numerator;
@@ -495,6 +486,7 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
perf.nominal_perf = FIELD_GET(AMD_CPPC_NOMINAL_PERF_MASK, cap1);
perf.lowest_nonlinear_perf = FIELD_GET(AMD_CPPC_LOWNONLIN_PERF_MASK, cap1);
perf.lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
+ perf.bios_min_perf = FIELD_GET(AMD_CPPC_MIN_PERF_MASK, cppc_req);
WRITE_ONCE(cpudata->perf, perf);
WRITE_ONCE(cpudata->prefcore_ranking, FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1));
WRITE_ONCE(cpudata->floor_perf_cnt, FIELD_GET(AMD_CPPC_FLOOR_PERF_CNT_MASK, cap1));
@@ -699,9 +691,12 @@ static void amd_pstate_update_min_max_limit(struct cpufreq_policy *policy)
WRITE_ONCE(cpudata->max_limit_freq, policy->max);
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
+ u8 min_limit_perf = perf.bios_min_perf ?: perf.nominal_perf;
+ u32 min_limit_freq;
+
/*
- * For performance policy, set MinPerf to nominal_perf rather than
- * highest_perf or lowest_nonlinear_perf.
+ * For performance policy, set MinPerf to nominal_perf / bios_min_perf
+ * rather than highest_perf or lowest_nonlinear_perf.
*
* Per commit 0c411b39e4f4c, using highest_perf was observed
* to cause frequency throttling on power-limited platforms, leading to
@@ -709,11 +704,18 @@ static void amd_pstate_update_min_max_limit(struct cpufreq_policy *policy)
* performance too much for HPC workloads requiring high frequency
* operation and minimal wakeup latency from idle states.
*
- * nominal_perf therefore provides a balance by avoiding throttling
- * while still maintaining enough performance for HPC workloads.
+ * nominal_perf therefore provides a balanced default by avoiding
+ * throttling while still maintaining enough performance for HPC
+ * workloads when bios_min_perf is not available.
+ *
+ * When bios_min_perf is available, users have profiled their workloads
+ * to understand the best idling frequency. Use that instead.
*/
- perf.min_limit_perf = min(perf.nominal_perf, perf.max_limit_perf);
- WRITE_ONCE(cpudata->min_limit_freq, min(cpudata->nominal_freq, cpudata->max_limit_freq));
+ min_limit_perf = min(min_limit_perf, perf.max_limit_perf);
+ min_limit_freq = perf_to_freq(perf, cpudata->nominal_freq, min_limit_perf);
+ perf.min_limit_perf = min_limit_perf;
+
+ WRITE_ONCE(cpudata->min_limit_freq, min(min_limit_freq, cpudata->max_limit_freq));
} else {
perf.min_limit_perf = freq_to_perf(perf, cpudata->nominal_freq, policy->min);
WRITE_ONCE(cpudata->min_limit_freq, policy->min);
@@ -1035,6 +1037,13 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
return -EINVAL;
}
+ if (perf.bios_min_perf) {
+ u32 bios_min_freq = perf_to_freq(perf, cpudata->nominal_freq, perf.bios_min_perf);
+
+ pr_debug("Found Requested CPU Min Frequency of %uKHz on CPU%d\n",
+ bios_min_freq, cpudata->cpu);
+ }
+
return 0;
}
@@ -1183,6 +1192,24 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
+static int amd_pstate_get_epp_from_platform_profile(struct cpufreq_policy *policy,
+ enum platform_profile_option profile)
+{
+ switch (profile) {
+ case PLATFORM_PROFILE_PERFORMANCE:
+ return AMD_CPPC_EPP_PERFORMANCE;
+ case PLATFORM_PROFILE_BALANCED:
+ return amd_pstate_get_balanced_epp(policy);
+ case PLATFORM_PROFILE_LOW_POWER:
+ return AMD_CPPC_EPP_POWERSAVE;
+ default:
+ break;
+ }
+
+ pr_err("Unknown Platform Profile %d\n", profile);
+ return -EOPNOTSUPP;
+}
+
static int amd_pstate_profile_probe(void *drvdata, unsigned long *choices)
{
set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
@@ -1208,31 +1235,19 @@ static int amd_pstate_profile_set(struct device *dev,
struct amd_cpudata *cpudata = dev_get_drvdata(dev);
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu);
int ret;
+ u8 epp;
if (!policy)
return -ENODEV;
- switch (profile) {
- case PLATFORM_PROFILE_LOW_POWER:
- ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_POWERSAVE);
- if (ret)
- return ret;
- break;
- case PLATFORM_PROFILE_BALANCED:
- ret = amd_pstate_set_epp(policy,
- amd_pstate_get_balanced_epp(policy));
- if (ret)
- return ret;
- break;
- case PLATFORM_PROFILE_PERFORMANCE:
- ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_PERFORMANCE);
- if (ret)
- return ret;
- break;
- default:
- pr_err("Unknown Platform Profile %d\n", profile);
- return -EOPNOTSUPP;
- }
+ ret = amd_pstate_get_epp_from_platform_profile(policy, profile);
+ if (ret < 0)
+ return ret;
+
+ epp = (u8)ret;
+ ret = amd_pstate_set_epp(policy, epp);
+ if (ret)
+ return ret;
cpudata->current_profile = profile;
@@ -1258,28 +1273,20 @@ void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy)
kfree(cpudata->profile_name);
cpudata->dynamic_epp = false;
}
-EXPORT_SYMBOL_GPL(amd_pstate_clear_dynamic_epp);
+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_clear_dynamic_epp);
static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
{
struct amd_cpudata *cpudata = policy->driver_data;
+ u64 prev = READ_ONCE(cpudata->cppc_req_cached);
int ret;
u8 epp;
- switch (cpudata->current_profile) {
- case PLATFORM_PROFILE_PERFORMANCE:
- epp = AMD_CPPC_EPP_PERFORMANCE;
- break;
- case PLATFORM_PROFILE_LOW_POWER:
- epp = AMD_CPPC_EPP_POWERSAVE;
- break;
- case PLATFORM_PROFILE_BALANCED:
- epp = amd_pstate_get_balanced_epp(policy);
- break;
- default:
- pr_err("Unknown Platform Profile %d\n", cpudata->current_profile);
- return -EOPNOTSUPP;
- }
+ ret = amd_pstate_get_epp_from_platform_profile(policy, cpudata->current_profile);
+ if (ret < 0)
+ return ret;
+
+ epp = (u8)ret;
ret = amd_pstate_set_epp(policy, epp);
if (ret)
return ret;
@@ -1312,6 +1319,9 @@ static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
cleanup:
amd_pstate_clear_dynamic_epp(policy);
+ epp = FIELD_GET(AMD_CPPC_EPP_PERF_MASK, prev);
+ /* Restore previous EPP if toggling Dynamic EPP failed. */
+ amd_pstate_set_epp(policy, epp);
return ret;
}
@@ -1382,7 +1392,7 @@ static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy,
static ssize_t show_energy_performance_available_preferences(
struct cpufreq_policy *policy, char *buf)
{
- int offset = 0, i;
+ int i, offset = 0;
struct amd_cpudata *cpudata = policy->driver_data;
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
@@ -1405,11 +1415,6 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
bool raw_epp = false;
u8 epp;
- if (cpudata->dynamic_epp) {
- pr_debug("EPP cannot be set when dynamic EPP is enabled\n");
- return -EBUSY;
- }
-
/*
* if the value matches a number, use that, otherwise see if
* matches an index in the energy_perf_strings array
@@ -1420,6 +1425,25 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
ret = sysfs_match_string(energy_perf_strings, buf);
if (ret < 0 || ret == EPP_INDEX_CUSTOM)
return -EINVAL;
+
+ if (ret == EPP_INDEX_DYNAMIC) {
+ if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
+ return -EBUSY;
+ /*
+ * Dynamic EPP was already enabled for this CPU.
+ * Nothing to do.
+ */
+ if (cpudata->dynamic_epp)
+ return count;
+
+ cpudata->current_profile = PLATFORM_PROFILE_BALANCED;
+ ret = amd_pstate_set_dynamic_epp(policy);
+ if (ret)
+ return ret;
+
+ return count;
+ }
+
if (ret)
epp = epp_values[ret];
else
@@ -1431,6 +1455,13 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
return -EBUSY;
}
+ /*
+ * Dynamic EPP was enabled previously!
+ * Switch back to the static EPP mode.
+ */
+ if (cpudata->dynamic_epp)
+ amd_pstate_clear_dynamic_epp(policy);
+
ret = amd_pstate_set_epp(policy, epp);
if (ret)
return ret;
@@ -1439,7 +1470,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
return count;
}
-EXPORT_SYMBOL_GPL(store_energy_performance_preference);
+EXPORT_SYMBOL_FOR_PSTATE_UT(store_energy_performance_preference);
ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf)
{
@@ -1448,7 +1479,7 @@ ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *
epp = FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached);
- if (cpudata->raw_epp)
+ if (!cpudata->dynamic_epp && cpudata->raw_epp)
return sysfs_emit(buf, "%u\n", epp);
switch (epp) {
@@ -1468,12 +1499,14 @@ ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *
return -EINVAL;
}
+ if (cpudata->dynamic_epp)
+ return sysfs_emit(buf, "dynamic(profile:%s)\n", energy_perf_strings[preference]);
+
return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
}
-EXPORT_SYMBOL_GPL(show_energy_performance_preference);
+EXPORT_SYMBOL_FOR_PSTATE_UT(show_energy_performance_preference);
-static ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy,
- const char *buf, size_t count)
+ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy, const char *buf, size_t count)
{
struct amd_cpudata *cpudata = policy->driver_data;
union perf_cached perf = READ_ONCE(cpudata->perf);
@@ -1496,13 +1529,15 @@ static ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy,
return ret ?: count;
}
+EXPORT_SYMBOL_FOR_PSTATE_UT(store_amd_pstate_floor_freq);
-static ssize_t show_amd_pstate_floor_freq(struct cpufreq_policy *policy, char *buf)
+ssize_t show_amd_pstate_floor_freq(struct cpufreq_policy *policy, char *buf)
{
struct amd_cpudata *cpudata = policy->driver_data;
return sysfs_emit(buf, "%u\n", cpudata->floor_freq);
}
+EXPORT_SYMBOL_FOR_PSTATE_UT(show_amd_pstate_floor_freq);
static ssize_t show_amd_pstate_floor_count(struct cpufreq_policy *policy, char *buf)
{
@@ -1570,7 +1605,7 @@ struct freq_attr **amd_pstate_get_current_attrs(void)
return NULL;
return current_pstate_driver->attr;
}
-EXPORT_SYMBOL_GPL(amd_pstate_get_current_attrs);
+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_get_current_attrs);
static struct freq_attr **get_freq_attrs(void)
{
@@ -1755,7 +1790,7 @@ int amd_pstate_get_status(void)
{
return cppc_state;
}
-EXPORT_SYMBOL_GPL(amd_pstate_get_status);
+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_get_status);
int amd_pstate_update_status(const char *buf, size_t size)
{
@@ -1775,7 +1810,7 @@ int amd_pstate_update_status(const char *buf, size_t size)
return 0;
}
-EXPORT_SYMBOL_GPL(amd_pstate_update_status);
+EXPORT_SYMBOL_FOR_PSTATE_UT(amd_pstate_update_status);
static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1803,50 +1838,12 @@ static ssize_t prefcore_show(struct device *dev,
return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore));
}
-static ssize_t dynamic_epp_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sysfs_emit(buf, "%s\n", str_enabled_disabled(dynamic_epp));
-}
-
-static ssize_t dynamic_epp_store(struct device *a, struct device_attribute *b,
- const char *buf, size_t count)
-{
- bool enabled;
- int ret;
-
- ret = kstrtobool(buf, &enabled);
- if (ret)
- return ret;
-
- guard(mutex)(&amd_pstate_driver_lock);
-
- if (cppc_state != AMD_PSTATE_ACTIVE) {
- pr_debug("dynamic_epp can only be toggled in active mode\n");
- return -EINVAL;
- }
-
- /* Nothing to do */
- if (dynamic_epp == enabled)
- return count;
-
- /* reinitialize with desired dynamic EPP value */
- dynamic_epp = enabled;
- ret = amd_pstate_change_driver_mode(cppc_state);
- if (ret)
- dynamic_epp = false;
-
- return ret ? ret : count;
-}
-
static DEVICE_ATTR_RW(status);
static DEVICE_ATTR_RO(prefcore);
-static DEVICE_ATTR_RW(dynamic_epp);
static struct attribute *pstate_global_attributes[] = {
&dev_attr_status.attr,
&dev_attr_prefcore.attr,
- &dev_attr_dynamic_epp.attr,
NULL
};
@@ -1953,10 +1950,7 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
cpudata->current_profile = PLATFORM_PROFILE_BALANCED;
}
- if (dynamic_epp)
- ret = amd_pstate_set_dynamic_epp(policy);
- else
- ret = amd_pstate_set_epp(policy, cpudata->epp_default_dc);
+ ret = amd_pstate_set_epp(policy, cpudata->epp_default_dc);
if (ret)
goto free_cpudata1;
@@ -2028,6 +2022,18 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
if (!policy->cpuinfo.max_freq)
return -ENODEV;
+ /* Must be a switch between PERFORMANCE and POWERSAVE */
+ if (cpudata->policy != policy->policy) {
+ /*
+ * Disable dynamic_epp when switching
+ * out of CPUFREQ_POLICY_POWERSAVE.
+ */
+ if (cpudata->dynamic_epp) {
+ WARN_ON_ONCE(cpudata->policy != CPUFREQ_POLICY_POWERSAVE);
+ amd_pstate_clear_dynamic_epp(policy);
+ }
+ }
+
cpudata->policy = policy->policy;
ret = amd_pstate_epp_update_limit(policy, true);
@@ -2355,19 +2361,8 @@ static int __init amd_prefcore_param(char *str)
return 0;
}
-static int __init amd_dynamic_epp_param(char *str)
-{
- if (!strcmp(str, "disable"))
- dynamic_epp = false;
- if (!strcmp(str, "enable"))
- dynamic_epp = true;
-
- return 0;
-}
-
early_param("amd_pstate", amd_pstate_param);
early_param("amd_prefcore", amd_prefcore_param);
-early_param("amd_dynamic_epp", amd_dynamic_epp_param);
MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index 23e8baa05849..9f5a81976eae 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -11,6 +11,13 @@
#include <linux/pm_qos.h>
#include <linux/platform_profile.h>
+#if IS_MODULE(CONFIG_X86_AMD_PSTATE_UT)
+#define EXPORT_SYMBOL_FOR_PSTATE_UT(symbol) \
+ EXPORT_SYMBOL_FOR_MODULES(symbol, "amd-pstate-ut")
+#else
+#define EXPORT_SYMBOL_FOR_PSTATE_UT(symbol)
+#endif
+
/*********************************************************************
* AMD P-state INTERFACE *
*********************************************************************/
@@ -32,6 +39,7 @@
* @min_limit_perf: Cached value of the performance corresponding to policy->min
* @max_limit_perf: Cached value of the performance corresponding to policy->max
* @bios_min_perf: Cached perf value corresponding to the "Requested CPU Min Frequency" BIOS option
+ * @val: Raw 64-bit value for atomic access via READ_ONCE()/WRITE_ONCE()
*/
union perf_cached {
struct {
@@ -89,7 +97,12 @@ struct amd_aperf_mperf {
* @epp_default_ac: Default EPP value for AC power source
* @epp_default_dc: Default EPP value for DC power source
* @dynamic_epp: Whether dynamic EPP is enabled
+ * @raw_epp: Whether the last EPP write was a raw numeric value rather than a
+ * named preference
* @power_nb: Notifier block for power events
+ * @current_profile: Currently selected platform profile option
+ * @ppdev: Device registered with the platform profile handler
+ * @profile_name: Name under which @ppdev is registered
*
* 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.
@@ -153,6 +166,8 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
const char *buf, size_t count);
ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf);
void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy);
+ssize_t store_amd_pstate_floor_freq(struct cpufreq_policy *policy, const char *buf, size_t count);
+ssize_t show_amd_pstate_floor_freq(struct cpufreq_policy *policy, char *buf);
struct freq_attr;