From: "Gautham R. Shenoy" <gautham.shenoy@amd.com>
To: "Mario Limonciello (AMD)" <superm1@kernel.org>
Cc: Perry Yuan <perry.yuan@amd.com>,
"open list:X86 ARCHITECTURE (32-BIT AND 64-BIT)"
<linux-kernel@vger.kernel.org>,
"open list:CPU FREQUENCY SCALING FRAMEWORK"
<linux-pm@vger.kernel.org>
Subject: Re: [PATCH v8 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference
Date: Thu, 2 Apr 2026 14:34:03 +0530 [thread overview]
Message-ID: <ac4xAyTls5lcvOto@BLRRASHENOY1.amd.com> (raw)
In-Reply-To: <20260402050214.1238624-2-superm1@kernel.org>
Hello Mario,
On Thu, Apr 02, 2026 at 12:02:10AM -0500, Mario Limonciello (AMD) wrote:
> Dynamic energy performance preference changes the EPP profile based on
> whether the machine is running on AC or DC power.
>
> A notification chain from the power supply core is used to adjust EPP
> values on plug in or plug out events.
>
> When enabled, the driver exposes a sysfs toggle for dynamic EPP, blocks
> manual writes to energy_performance_preference, and keeps the policy in
> performance mode while it "owns" the EPP updates.
The commit message still says "..keeps the policy in performance mode
while it owns the EPP updates".
That is no longer true in this version, so this needs to be removed.
Other than that, the patch looks good to me.
Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
--
Thanks and Regards
gautham.
>
> For non-server systems:
> * the default EPP for AC mode is `performance`.
> * the default EPP for DC mode is `balance_performance`.
>
> For server systems dynamic EPP is mostly a no-op.
>
> Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
> ---
> v7->v8:
> * Handle failures to enable dynamic epp
> * Don't set policy to CPUFREQ_POLICY_PERFORMANCE in dymamic epp
> * Allow policy governor changes
> v6->v7:
> * Fix accidental casualty of floor perf from rebase (Gautham)
> * Adjust documentation (Gautham)
> ---
> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
> drivers/cpufreq/Kconfig.x86 | 12 ++
> drivers/cpufreq/amd-pstate.c | 128 +++++++++++++++++++-
> drivers/cpufreq/amd-pstate.h | 10 +-
> 4 files changed, 160 insertions(+), 8 deletions(-)
>
> diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
> index b43675b7f739b..bb1341763882b 100644
> --- a/Documentation/admin-guide/pm/amd-pstate.rst
> +++ b/Documentation/admin-guide/pm/amd-pstate.rst
> @@ -325,7 +325,7 @@ and user can change current preference according to energy or performance needs
> Please get all support profiles list from
> ``energy_performance_available_preferences`` attribute, all the profiles are
> 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
> +firmware, but if the dynamic EPP feature is enabled, driver will block writes.
> This attribute is read-write.
>
> ``boost``
> @@ -347,6 +347,22 @@ boost or `1` to enable it, for the respective CPU using the sysfs path
> Other performance and frequency values can be read back from
> ``/sys/devices/system/cpu/cpuX/acpi_cppc/``, see :ref:`cppc_sysfs`.
>
> +Dynamic energy performance profile
> +==================================
> +The amd-pstate driver supports dynamically selecting the energy performance
> +profile based on whether the machine is running on AC or DC power.
> +
> +Whether this behavior is enabled by default depends on the kernel
> +config option `CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP`. This behavior can also be overridden
> +at runtime by the sysfs file ``/sys/devices/system/cpu/cpufreq/policyX/dynamic_epp``.
> +
> +When set to enabled, the driver will select a different energy performance
> +profile when the machine is running on battery or AC power.
> +When set to disabled, the driver will not change the energy performance profile
> +based on the power source and will not react to user desired power state.
> +
> +Attempting to manually write to the ``energy_performance_preference`` sysfs
> +file will fail when ``dynamic_epp`` is enabled.
>
> ``amd-pstate`` vs ``acpi-cpufreq``
> ======================================
> diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
> index 2c5c228408bf2..cdaa8d858045a 100644
> --- a/drivers/cpufreq/Kconfig.x86
> +++ b/drivers/cpufreq/Kconfig.x86
> @@ -68,6 +68,18 @@ config X86_AMD_PSTATE_DEFAULT_MODE
> For details, take a look at:
> <file:Documentation/admin-guide/pm/amd-pstate.rst>.
>
> +config X86_AMD_PSTATE_DYNAMIC_EPP
> + bool "AMD Processor P-State dynamic EPP support"
> + depends on X86_AMD_PSTATE
> + default n
> + help
> + Allow the kernel to dynamically change the energy performance
> + value from events like ACPI platform profile and AC adapter plug
> + events.
> +
> + This feature can also be changed at runtime, this configuration
> + option only sets the kernel default value behavior.
> +
> config X86_AMD_PSTATE_UT
> tristate "selftest for AMD Processor P-State driver"
> depends on X86 && ACPI_PROCESSOR
> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
> index f207252eb5f5f..379e7dd442522 100644
> --- a/drivers/cpufreq/amd-pstate.c
> +++ b/drivers/cpufreq/amd-pstate.c
> @@ -36,6 +36,7 @@
> #include <linux/io.h>
> #include <linux/delay.h>
> #include <linux/uaccess.h>
> +#include <linux/power_supply.h>
> #include <linux/static_call.h>
> #include <linux/topology.h>
>
> @@ -86,6 +87,11 @@ 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;
> +#ifdef CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP
> +static bool dynamic_epp = CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP;
> +#else
> +static bool dynamic_epp;
> +#endif
> static struct quirk_entry *quirks;
>
> /*
> @@ -1155,6 +1161,73 @@ static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
> kfree(cpudata);
> }
>
> +static int amd_pstate_get_balanced_epp(struct cpufreq_policy *policy)
> +{
> + struct amd_cpudata *cpudata = policy->driver_data;
> +
> + if (power_supply_is_system_supplied())
> + return cpudata->epp_default_ac;
> + else
> + return cpudata->epp_default_dc;
> +}
> +
> +static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
> + unsigned long event, void *data)
> +{
> + struct amd_cpudata *cpudata = container_of(nb, struct amd_cpudata, power_nb);
> + struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu);
> + u8 epp;
> + int ret;
> +
> + if (event != PSY_EVENT_PROP_CHANGED)
> + return NOTIFY_OK;
> +
> + epp = amd_pstate_get_balanced_epp(policy);
> +
> + ret = amd_pstate_set_epp(policy, epp);
> + if (ret)
> + pr_warn("Failed to set CPU %d EPP %u: %d\n", cpudata->cpu, epp, ret);
> +
> + return NOTIFY_OK;
> +}
> +static void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy)
> +{
> + struct amd_cpudata *cpudata = policy->driver_data;
> +
> + if (cpudata->power_nb.notifier_call)
> + power_supply_unreg_notifier(&cpudata->power_nb);
> + cpudata->dynamic_epp = false;
> +}
> +
> +static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
> +{
> + struct amd_cpudata *cpudata = policy->driver_data;
> + int ret;
> + u8 epp;
> +
> + epp = amd_pstate_get_balanced_epp(policy);
> + ret = amd_pstate_set_epp(policy, epp);
> + if (ret)
> + return ret;
> +
> + /* only enable notifier if things will actually change */
> + if (cpudata->epp_default_ac != cpudata->epp_default_dc) {
> + cpudata->power_nb.notifier_call = amd_pstate_power_supply_notifier;
> + ret = power_supply_reg_notifier(&cpudata->power_nb);
> + if (ret)
> + goto cleanup;
> + }
> +
> + cpudata->dynamic_epp = true;
> +
> + return 0;
> +
> +cleanup:
> + amd_pstate_clear_dynamic_epp(policy);
> +
> + return ret;
> +}
> +
> /* Sysfs attributes */
>
> /*
> @@ -1244,14 +1317,19 @@ static ssize_t store_energy_performance_preference(
> ssize_t ret;
> u8 epp;
>
> + if (cpudata->dynamic_epp) {
> + pr_debug("EPP cannot be set when dynamic EPP is enabled\n");
> + return -EBUSY;
> + }
> +
> ret = sysfs_match_string(energy_perf_strings, buf);
> if (ret < 0)
> return -EINVAL;
>
> - if (!ret)
> - epp = cpudata->epp_default;
> - else
> + if (ret)
> epp = epp_values[ret];
> + else
> + epp = amd_pstate_get_balanced_epp(policy);
>
> if (epp > 0 && policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
> pr_debug("EPP cannot be set under performance policy\n");
> @@ -1259,6 +1337,8 @@ static ssize_t store_energy_performance_preference(
> }
>
> ret = amd_pstate_set_epp(policy, epp);
> + if (ret)
> + return ret;
>
> return ret ? ret : count;
> }
> @@ -1620,12 +1700,42 @@ 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;
> +
> + if (dynamic_epp == enabled)
> + return -EINVAL;
> +
> + /* 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
> };
>
> @@ -1715,13 +1825,17 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
> if (amd_pstate_acpi_pm_profile_server() ||
> amd_pstate_acpi_pm_profile_undefined()) {
> policy->policy = CPUFREQ_POLICY_PERFORMANCE;
> - cpudata->epp_default = amd_pstate_get_epp(cpudata);
> + cpudata->epp_default_ac = cpudata->epp_default_dc = amd_pstate_get_epp(cpudata);
> } else {
> policy->policy = CPUFREQ_POLICY_POWERSAVE;
> - cpudata->epp_default = AMD_CPPC_EPP_BALANCE_PERFORMANCE;
> + cpudata->epp_default_ac = AMD_CPPC_EPP_PERFORMANCE;
> + cpudata->epp_default_dc = AMD_CPPC_EPP_BALANCE_PERFORMANCE;
> }
>
> - ret = amd_pstate_set_epp(policy, cpudata->epp_default);
> + if (dynamic_epp)
> + ret = amd_pstate_set_dynamic_epp(policy);
> + else
> + ret = amd_pstate_set_epp(policy, amd_pstate_get_balanced_epp(policy));
> if (ret)
> goto free_cpudata1;
>
> @@ -1753,6 +1867,8 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
> amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
> amd_pstate_set_floor_perf(policy, cpudata->bios_floor_perf);
>
> + if (cpudata->dynamic_epp)
> + amd_pstate_clear_dynamic_epp(policy);
> kfree(cpudata);
> policy->driver_data = NULL;
> }
> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
> index 32b8b26ce388f..d929ae3163b3d 100644
> --- a/drivers/cpufreq/amd-pstate.h
> +++ b/drivers/cpufreq/amd-pstate.h
> @@ -85,6 +85,11 @@ struct amd_aperf_mperf {
> * AMD P-State driver supports preferred core featue.
> * @epp_cached: Cached CPPC energy-performance preference value
> * @policy: Cpufreq policy value
> + * @suspended: If CPU core if offlined
> + * @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
> + * @power_nb: Notifier block for power events
> *
> * 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.
> @@ -118,7 +123,10 @@ struct amd_cpudata {
> /* EPP feature related attributes*/
> u32 policy;
> bool suspended;
> - u8 epp_default;
> + u8 epp_default_ac;
> + u8 epp_default_dc;
> + bool dynamic_epp;
> + struct notifier_block power_nb;
> };
>
> /*
> --
> 2.43.0
>
next prev parent reply other threads:[~2026-04-02 9:04 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-02 5:02 [PATCH v8 0/5] amd-pstate Dynamic EPP and raw EPP Mario Limonciello (AMD)
2026-04-02 5:02 ` [PATCH v8 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference Mario Limonciello (AMD)
2026-04-02 9:04 ` Gautham R. Shenoy [this message]
2026-04-02 5:02 ` [PATCH v8 2/5] cpufreq/amd-pstate: add kernel command line to override dynamic epp Mario Limonciello (AMD)
2026-04-02 5:02 ` [PATCH v8 3/5] cpufreq/amd-pstate: Add support for platform profile class Mario Limonciello (AMD)
2026-04-02 5:02 ` [PATCH v8 4/5] cpufreq/amd-pstate: Add support for raw EPP writes Mario Limonciello (AMD)
2026-04-02 5:02 ` [PATCH v8 5/5] cpufreq/amd-pstate-ut: Add a unit test for raw EPP Mario Limonciello (AMD)
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=ac4xAyTls5lcvOto@BLRRASHENOY1.amd.com \
--to=gautham.shenoy@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=perry.yuan@amd.com \
--cc=superm1@kernel.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