From: K Prateek Nayak <kprateek.nayak@amd.com>
To: Mario Limonciello <mario.limonciello@amd.com>,
Huang Rui <ray.huang@amd.com>,
"Rafael J. Wysocki" <rafael@kernel.org>,
Viresh Kumar <viresh.kumar@linaro.org>
Cc: Perry Yuan <perry.yuan@amd.com>,
K Prateek Nayak <kprateek.nayak@amd.com>,
<linux-pm@vger.kernel.org>, <linux-doc@vger.kernel.org>,
<linux-kernel@vger.kernel.org>,
Mario Limonciello <superm1@kernel.org>
Subject: [PATCH v3 4/9] cpufreq/amd-pstate: Add dynamic EPP as an "energy_performance_preference" mode
Date: Mon, 27 Jul 2026 07:20:51 +0000 [thread overview]
Message-ID: <20260727072056.1248-5-kprateek.nayak@amd.com> (raw)
In-Reply-To: <20260727072056.1248-1-kprateek.nayak@amd.com>
Convert the global "dynamic_epp" toggle into a per-CPU
"energy_performance_preference" mode "dynamic" that allows toggling the
functionality of "dynamic_epp" at a per-CPU level.
Instead of being a system-wide toggle, users can opt into the
functionality of dynamic EPP on a per-CPU basis by switching to the
powersave governor and selecting the "dynamic" mode from the available
performance preferences.
Unlike the previous implementation that had to check for driver mode
before toggling on the functionality, block writes to certain sysfs
files, potentially disallow policy change, etc. the per-CPU toggle fits
naturally into the intended design and provides more granular control to
the user.
The dynamic_epp file is now redundant as the option to toggle it on is
controlled via energy_performance_preference, and the dynamic_epp file
will be removed in the subsequent commit.
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com>
---
changelog v2..v3:
o Collected tag from Mario. (Thanks a ton!)
o Fixed a typo in commit message. (Mario)
o Added a policy check to prevent toggling dynamic mode with PERFORMANCE
policy. (Sashiko)
---
drivers/cpufreq/amd-pstate.c | 59 +++++++++++++++++++++++++++++++-----
1 file changed, 51 insertions(+), 8 deletions(-)
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 5b10a0a0e6b6..fdf3106f6e07 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -106,6 +106,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 +115,7 @@ enum energy_perf_value_index {
EPP_INDEX_BALANCE_POWERSAVE,
EPP_INDEX_POWERSAVE,
EPP_INDEX_CUSTOM,
+ EPP_INDEX_DYNAMIC,
EPP_INDEX_MAX,
};
@@ -124,6 +126,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 +137,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);
@@ -1275,6 +1278,7 @@ EXPORT_SYMBOL_GPL(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;
@@ -1315,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;
}
@@ -1385,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)
@@ -1408,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
@@ -1423,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
@@ -1434,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;
@@ -1451,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) {
@@ -1471,6 +1499,9 @@ 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);
@@ -2031,6 +2062,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);
--
2.34.1
next prev parent reply other threads:[~2026-07-27 7:22 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 7:20 [PATCH v3 0/9] cpufreq/amd-pstate: BIOS min perf fixes and Dynamic EPP rework K Prateek Nayak
2026-07-27 7:20 ` [PATCH v3 1/9] cpufreq/amd-pstate: Set min_limit_freq based on bios_min_perf K Prateek Nayak
2026-07-27 7:20 ` [PATCH v3 2/9] cpufreq/amd-pstate: Remove the defensive check for bios_min_perf K Prateek Nayak
2026-07-27 7:20 ` [PATCH v3 3/9] cpufreq/amd-pstate: Extract platform profile to EPP conversion into a helper K Prateek Nayak
2026-07-27 7:20 ` K Prateek Nayak [this message]
2026-07-27 7:20 ` [PATCH v3 5/9] cpufreq/amd-pstate: Remove "amd_dynamic_epp" cmdline and "dynamic_epp" sysfs K Prateek Nayak
2026-07-27 7:20 ` [PATCH v3 6/9] Documentation/amd-pstate: Update dynamic_epp documentation with new behavior K Prateek Nayak
2026-07-27 7:20 ` [PATCH v3 7/9] cpufreq/amd-pstate: Reduce the scope of exported symbols K Prateek Nayak
2026-07-27 7:20 ` [PATCH v3 8/9] cpufreq/amd-pstate-ut: Add unit test for "dynamic" EPP mode K Prateek Nayak
2026-07-27 7:20 ` [PATCH v3 9/9] cpufreq/amd-pstate-ut: Add unit test for CPPC Performance Priority K Prateek Nayak
2026-07-28 0:47 ` [PATCH v3 0/9] cpufreq/amd-pstate: BIOS min perf fixes and Dynamic EPP rework Mario Limonciello
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260727072056.1248-5-kprateek.nayak@amd.com \
--to=kprateek.nayak@amd.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=mario.limonciello@amd.com \
--cc=perry.yuan@amd.com \
--cc=rafael@kernel.org \
--cc=ray.huang@amd.com \
--cc=superm1@kernel.org \
--cc=viresh.kumar@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®