From: Mario Limonciello <mario.limonciello@amd.com>
Dynamic energy performance preference will change 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.
For non-server systems:
* the default EPP for AC mode is `performance`.
* the default EPP for DC mode is `balance_performance`.
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
v1->v2:
* Change defaults to performance (AC) and balance_performance (DC)
* Default Kconfig to disabled for now
* Rebase on latest branch
---
Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
drivers/cpufreq/Kconfig.x86 | 12 ++
drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++--
drivers/cpufreq/amd-pstate.h | 5 +-
4 files changed, 155 insertions(+), 9 deletions(-)
diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index 412423c54f258..2e076650dc77c 100644
--- a/Documentation/admin-guide/pm/amd-pstate.rst
+++ b/Documentation/admin-guide/pm/amd-pstate.rst
@@ -289,7 +289,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``
@@ -311,6 +311,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 with 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 97c2d4f15d76e..c5ef92634ddf4 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 kenrel 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 e98ef41083ba1..f00fb4ba9f26e 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,7 @@ 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 = CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP;
static struct quirk_entry *quirks;
/*
@@ -1050,6 +1052,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) {
+ ret = power_supply_reg_notifier(&cpudata->power_nb);
+ if (ret)
+ goto cleanup;
+ cpudata->power_nb.notifier_call = amd_pstate_power_supply_notifier;
+ }
+
+ cpudata->dynamic_epp = true;
+
+ return 0;
+
+cleanup:
+ amd_pstate_clear_dynamic_epp(policy);
+
+ return ret;
+}
+
/* Sysfs attributes */
/*
@@ -1146,6 +1215,11 @@ 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 = sscanf(buf, "%20s", str_preference);
if (ret != 1)
return -EINVAL;
@@ -1154,10 +1228,10 @@ static ssize_t store_energy_performance_preference(
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");
@@ -1165,6 +1239,8 @@ static ssize_t store_energy_performance_preference(
}
ret = amd_pstate_set_epp(policy, epp);
+ if (ret)
+ return ret;
return ret ? ret : count;
}
@@ -1364,6 +1440,32 @@ 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);
+
+ return ret ? ret : count;
+}
+
cpufreq_freq_attr_ro(amd_pstate_max_freq);
cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
@@ -1374,6 +1476,7 @@ cpufreq_freq_attr_rw(energy_performance_preference);
cpufreq_freq_attr_ro(energy_performance_available_preferences);
static DEVICE_ATTR_RW(status);
static DEVICE_ATTR_RO(prefcore);
+static DEVICE_ATTR_RW(dynamic_epp);
static struct freq_attr *amd_pstate_attr[] = {
&amd_pstate_max_freq,
@@ -1398,6 +1501,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = {
static struct attribute *pstate_global_attributes[] = {
&dev_attr_status.attr,
&dev_attr_prefcore.attr,
+ &dev_attr_dynamic_epp.attr,
NULL
};
@@ -1490,10 +1594,11 @@ 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;
}
if (cpu_feature_enabled(X86_FEATURE_CPPC)) {
@@ -1502,9 +1607,13 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
return ret;
WRITE_ONCE(cpudata->cppc_req_cached, value);
}
- 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)
- return ret;
+ goto free_cpudata1;
current_pstate_driver->adjust_perf = NULL;
@@ -1521,6 +1630,8 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
struct amd_cpudata *cpudata = policy->driver_data;
if (cpudata) {
+ if (cpudata->dynamic_epp)
+ amd_pstate_clear_dynamic_epp(policy);
kfree(cpudata);
policy->driver_data = NULL;
}
@@ -1556,6 +1667,10 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
if (!policy->cpuinfo.max_freq)
return -ENODEV;
+ /* policy can't be changed to performance policy while dynamic epp is enabled */
+ if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && cpudata->dynamic_epp)
+ return -EBUSY;
+
cpudata->policy = policy->policy;
ret = amd_pstate_epp_update_limit(policy);
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index fbe1c08d3f061..6882876f895de 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -104,7 +104,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
On 3/4/2025 8:53 PM, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
>
> Dynamic energy performance preference will change 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.
>
> For non-server systems:
> * the default EPP for AC mode is `performance`.
> * the default EPP for DC mode is `balance_performance`.
>
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
> v1->v2:
> * Change defaults to performance (AC) and balance_performance (DC)
> * Default Kconfig to disabled for now
> * Rebase on latest branch
> ---
> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
> drivers/cpufreq/Kconfig.x86 | 12 ++
> drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++--
> drivers/cpufreq/amd-pstate.h | 5 +-
> 4 files changed, 155 insertions(+), 9 deletions(-)
>
[Snip]
> @@ -1556,6 +1667,10 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
> if (!policy->cpuinfo.max_freq)
> return -ENODEV;
>
> + /* policy can't be changed to performance policy while dynamic epp is enabled */
> + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && cpudata->dynamic_epp)
> + return -EBUSY;
We might need to tweak this condition, because if we enable "CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP" in config
and boot with "amd_pstate=active" it lands here (cpufreq_online()->amd_pstate_epp_set_policy()) driver init fails
as the default governor is performance.
> +
> cpudata->policy = policy->policy;
>
> ret = amd_pstate_epp_update_limit(policy);
> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
> index fbe1c08d3f061..6882876f895de 100644
> --- a/drivers/cpufreq/amd-pstate.h
> +++ b/drivers/cpufreq/amd-pstate.h
> @@ -104,7 +104,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;
> };
>
> /*
On 3/12/2025 07:16, Dhananjay Ugwekar wrote:
> On 3/4/2025 8:53 PM, Mario Limonciello wrote:
>> From: Mario Limonciello <mario.limonciello@amd.com>
>>
>> Dynamic energy performance preference will change 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.
>>
>> For non-server systems:
>> * the default EPP for AC mode is `performance`.
>> * the default EPP for DC mode is `balance_performance`.
>>
>> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
>> ---
>> v1->v2:
>> * Change defaults to performance (AC) and balance_performance (DC)
>> * Default Kconfig to disabled for now
>> * Rebase on latest branch
>> ---
>> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
>> drivers/cpufreq/Kconfig.x86 | 12 ++
>> drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++--
>> drivers/cpufreq/amd-pstate.h | 5 +-
>> 4 files changed, 155 insertions(+), 9 deletions(-)
>>
> [Snip]
>> @@ -1556,6 +1667,10 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
>> if (!policy->cpuinfo.max_freq)
>> return -ENODEV;
>>
>> + /* policy can't be changed to performance policy while dynamic epp is enabled */
>> + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && cpudata->dynamic_epp)
>> + return -EBUSY;
>
> We might need to tweak this condition, because if we enable "CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP" in config
> and boot with "amd_pstate=active" it lands here (cpufreq_online()->amd_pstate_epp_set_policy()) driver init fails
> as the default governor is performance.
>
The check is important to make sure that you can't go to performance
mode after init.
I think this is the way I would want to solve it.
Set policy to powersave before enabling dynamic epp for
amd_pstate_epp_cpu_init().
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 824756ac0010e..4a0f561d0e2d1 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1729,8 +1729,10 @@ static int amd_pstate_epp_cpu_init(struct
cpufreq_policy *policy)
WRITE_ONCE(cpudata->cppc_req_cached, value);
}
- if (dynamic_epp)
+ if (dynamic_epp) {
+ policy->policy = CPUFREQ_POLICY_POWERSAVE;
ret = amd_pstate_set_dynamic_epp(policy);
+ }
else
ret = amd_pstate_set_epp(policy,
amd_pstate_get_balanced_epp(policy));
if (ret)
Thoughts?
>> +
>> cpudata->policy = policy->policy;
>>
>> ret = amd_pstate_epp_update_limit(policy);
>> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
>> index fbe1c08d3f061..6882876f895de 100644
>> --- a/drivers/cpufreq/amd-pstate.h
>> +++ b/drivers/cpufreq/amd-pstate.h
>> @@ -104,7 +104,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;
>> };
>>
>> /*
>
On 3/19/2025 1:06 AM, Mario Limonciello wrote:
> On 3/12/2025 07:16, Dhananjay Ugwekar wrote:
>> On 3/4/2025 8:53 PM, Mario Limonciello wrote:
>>> From: Mario Limonciello <mario.limonciello@amd.com>
>>>
>>> Dynamic energy performance preference will change 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.
>>>
>>> For non-server systems:
>>> * the default EPP for AC mode is `performance`.
>>> * the default EPP for DC mode is `balance_performance`.
>>>
>>> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
>>> ---
>>> v1->v2:
>>> * Change defaults to performance (AC) and balance_performance (DC)
>>> * Default Kconfig to disabled for now
>>> * Rebase on latest branch
>>> ---
>>> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
>>> drivers/cpufreq/Kconfig.x86 | 12 ++
>>> drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++--
>>> drivers/cpufreq/amd-pstate.h | 5 +-
>>> 4 files changed, 155 insertions(+), 9 deletions(-)
>>>
>> [Snip]
>>> @@ -1556,6 +1667,10 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
>>> if (!policy->cpuinfo.max_freq)
>>> return -ENODEV;
>>> + /* policy can't be changed to performance policy while dynamic epp is enabled */
>>> + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && cpudata->dynamic_epp)
>>> + return -EBUSY;
>>
>> We might need to tweak this condition, because if we enable "CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP" in config
>> and boot with "amd_pstate=active" it lands here (cpufreq_online()->amd_pstate_epp_set_policy()) driver init fails
>> as the default governor is performance.
>>
>
> The check is important to make sure that you can't go to performance mode after init.
>
> I think this is the way I would want to solve it.
> Set policy to powersave before enabling dynamic epp for amd_pstate_epp_cpu_init().
>
> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
> index 824756ac0010e..4a0f561d0e2d1 100644
> --- a/drivers/cpufreq/amd-pstate.c
> +++ b/drivers/cpufreq/amd-pstate.c
> @@ -1729,8 +1729,10 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
> WRITE_ONCE(cpudata->cppc_req_cached, value);
> }
>
> - if (dynamic_epp)
> + if (dynamic_epp) {
> + policy->policy = CPUFREQ_POLICY_POWERSAVE;
> ret = amd_pstate_set_dynamic_epp(policy);
> + }
> else
> ret = amd_pstate_set_epp(policy, amd_pstate_get_balanced_epp(policy));
^^^^^^^^^^^^ (mentioned below)
> if (ret)
>
> Thoughts?
Yes, this looks good, because anyway there is no point in having performance governor and dynamic
epp set at the same time.
I found one related quirk though, we are setting performance governor for server platforms in
amd_pstate_epp_cpu_init() and then setting epp at the line highlighted above. We dont have a
check in *_set_epp() functions for performance governor. This could alter the performance governor
behavior if we set a "balanced" epp for it. I haven't tested this part yet.
Thanks,
Dhananjay
>
>>> +
>>> cpudata->policy = policy->policy;
>>> ret = amd_pstate_epp_update_limit(policy);
>>> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
>>> index fbe1c08d3f061..6882876f895de 100644
>>> --- a/drivers/cpufreq/amd-pstate.h
>>> +++ b/drivers/cpufreq/amd-pstate.h
>>> @@ -104,7 +104,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;
>>> };
>>> /*
>>
>
On 3/18/2025 22:43, Dhananjay Ugwekar wrote:
> On 3/19/2025 1:06 AM, Mario Limonciello wrote:
>> On 3/12/2025 07:16, Dhananjay Ugwekar wrote:
>>> On 3/4/2025 8:53 PM, Mario Limonciello wrote:
>>>> From: Mario Limonciello <mario.limonciello@amd.com>
>>>>
>>>> Dynamic energy performance preference will change 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.
>>>>
>>>> For non-server systems:
>>>> * the default EPP for AC mode is `performance`.
>>>> * the default EPP for DC mode is `balance_performance`.
>>>>
>>>> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
>>>> ---
>>>> v1->v2:
>>>> * Change defaults to performance (AC) and balance_performance (DC)
>>>> * Default Kconfig to disabled for now
>>>> * Rebase on latest branch
>>>> ---
>>>> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
>>>> drivers/cpufreq/Kconfig.x86 | 12 ++
>>>> drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++--
>>>> drivers/cpufreq/amd-pstate.h | 5 +-
>>>> 4 files changed, 155 insertions(+), 9 deletions(-)
>>>>
>>> [Snip]
>>>> @@ -1556,6 +1667,10 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
>>>> if (!policy->cpuinfo.max_freq)
>>>> return -ENODEV;
>>>> + /* policy can't be changed to performance policy while dynamic epp is enabled */
>>>> + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && cpudata->dynamic_epp)
>>>> + return -EBUSY;
>>>
>>> We might need to tweak this condition, because if we enable "CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP" in config
>>> and boot with "amd_pstate=active" it lands here (cpufreq_online()->amd_pstate_epp_set_policy()) driver init fails
>>> as the default governor is performance.
>>>
>>
>> The check is important to make sure that you can't go to performance mode after init.
>>
>> I think this is the way I would want to solve it.
>> Set policy to powersave before enabling dynamic epp for amd_pstate_epp_cpu_init().
>>
>> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
>> index 824756ac0010e..4a0f561d0e2d1 100644
>> --- a/drivers/cpufreq/amd-pstate.c
>> +++ b/drivers/cpufreq/amd-pstate.c
>> @@ -1729,8 +1729,10 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
>> WRITE_ONCE(cpudata->cppc_req_cached, value);
>> }
>>
>> - if (dynamic_epp)
>> + if (dynamic_epp) {
>> + policy->policy = CPUFREQ_POLICY_POWERSAVE;
>> ret = amd_pstate_set_dynamic_epp(policy);
>> + }
>> else
>> ret = amd_pstate_set_epp(policy, amd_pstate_get_balanced_epp(policy));
> ^^^^^^^^^^^^ (mentioned below)
>> if (ret)
>>
>> Thoughts?
>
> Yes, this looks good, because anyway there is no point in having performance governor and dynamic
> epp set at the same time.
>
> I found one related quirk though, we are setting performance governor for server platforms in
> amd_pstate_epp_cpu_init() and then setting epp at the line highlighted above. We dont have a
> check in *_set_epp() functions for performance governor. This could alter the performance governor
> behavior if we set a "balanced" epp for it. I haven't tested this part yet.
In that case we probably want the "default" ACPI platform profile to be
"performance" when on a server instead of balanced.
>
> Thanks,
> Dhananjay
>
>>
>>>> +
>>>> cpudata->policy = policy->policy;
>>>> ret = amd_pstate_epp_update_limit(policy);
>>>> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
>>>> index fbe1c08d3f061..6882876f895de 100644
>>>> --- a/drivers/cpufreq/amd-pstate.h
>>>> +++ b/drivers/cpufreq/amd-pstate.h
>>>> @@ -104,7 +104,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;
>>>> };
>>>> /*
>>>
>>
>
On 3/19/2025 11:50, Mario Limonciello wrote:
> On 3/18/2025 22:43, Dhananjay Ugwekar wrote:
>> On 3/19/2025 1:06 AM, Mario Limonciello wrote:
>>> On 3/12/2025 07:16, Dhananjay Ugwekar wrote:
>>>> On 3/4/2025 8:53 PM, Mario Limonciello wrote:
>>>>> From: Mario Limonciello <mario.limonciello@amd.com>
>>>>>
>>>>> Dynamic energy performance preference will change 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.
>>>>>
>>>>> For non-server systems:
>>>>> * the default EPP for AC mode is `performance`.
>>>>> * the default EPP for DC mode is `balance_performance`.
>>>>>
>>>>> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
>>>>> ---
>>>>> v1->v2:
>>>>> * Change defaults to performance (AC) and balance_performance (DC)
>>>>> * Default Kconfig to disabled for now
>>>>> * Rebase on latest branch
>>>>> ---
>>>>> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
>>>>> drivers/cpufreq/Kconfig.x86 | 12 ++
>>>>> drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++
>>>>> ++++--
>>>>> drivers/cpufreq/amd-pstate.h | 5 +-
>>>>> 4 files changed, 155 insertions(+), 9 deletions(-)
>>>>>
>>>> [Snip]
>>>>> @@ -1556,6 +1667,10 @@ static int amd_pstate_epp_set_policy(struct
>>>>> cpufreq_policy *policy)
>>>>> if (!policy->cpuinfo.max_freq)
>>>>> return -ENODEV;
>>>>> + /* policy can't be changed to performance policy while
>>>>> dynamic epp is enabled */
>>>>> + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE && cpudata-
>>>>> >dynamic_epp)
>>>>> + return -EBUSY;
>>>>
>>>> We might need to tweak this condition, because if we enable
>>>> "CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP" in config
>>>> and boot with "amd_pstate=active" it lands here (cpufreq_online()-
>>>> >amd_pstate_epp_set_policy()) driver init fails
>>>> as the default governor is performance.
>>>>
>>>
>>> The check is important to make sure that you can't go to performance
>>> mode after init.
>>>
>>> I think this is the way I would want to solve it.
>>> Set policy to powersave before enabling dynamic epp for
>>> amd_pstate_epp_cpu_init().
>>>
>>> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
>>> index 824756ac0010e..4a0f561d0e2d1 100644
>>> --- a/drivers/cpufreq/amd-pstate.c
>>> +++ b/drivers/cpufreq/amd-pstate.c
>>> @@ -1729,8 +1729,10 @@ static int amd_pstate_epp_cpu_init(struct
>>> cpufreq_policy *policy)
>>> WRITE_ONCE(cpudata->cppc_req_cached, value);
>>> }
>>>
>>> - if (dynamic_epp)
>>> + if (dynamic_epp) {
>>> + policy->policy = CPUFREQ_POLICY_POWERSAVE;
>>> ret = amd_pstate_set_dynamic_epp(policy);
>>> + }
>>> else
>>> ret = amd_pstate_set_epp(policy,
>>> amd_pstate_get_balanced_epp(policy));
>> ^^^^^^^^^^^^ (mentioned below)
>>> if (ret)
>>>
>>> Thoughts?
>>
>> Yes, this looks good, because anyway there is no point in having
>> performance governor and dynamic
>> epp set at the same time.
>>
>> I found one related quirk though, we are setting performance governor
>> for server platforms in
>> amd_pstate_epp_cpu_init() and then setting epp at the line highlighted
>> above. We dont have a
>> check in *_set_epp() functions for performance governor. This could
>> alter the performance governor
>> behavior if we set a "balanced" epp for it. I haven't tested this part
>> yet.
>
> In that case we probably want the "default" ACPI platform profile to be
> "performance" when on a server instead of balanced.
Actually this is already done:
cpudata->current_profile = PLATFORM_PROFILE_PERFORMANCE;
I'll post an updated patch series for you to test.
>
>>
>> Thanks,
>> Dhananjay
>>
>>>
>>>>> +
>>>>> cpudata->policy = policy->policy;
>>>>> ret = amd_pstate_epp_update_limit(policy);
>>>>> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-
>>>>> pstate.h
>>>>> index fbe1c08d3f061..6882876f895de 100644
>>>>> --- a/drivers/cpufreq/amd-pstate.h
>>>>> +++ b/drivers/cpufreq/amd-pstate.h
>>>>> @@ -104,7 +104,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;
>>>>> };
>>>>> /*
>>>>
>>>
>>
>
On 3/4/2025 8:53 PM, Mario Limonciello wrote: > From: Mario Limonciello <mario.limonciello@amd.com> > > Dynamic energy performance preference will change 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. > > For non-server systems: > * the default EPP for AC mode is `performance`. > * the default EPP for DC mode is `balance_performance`. > > Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> > --- > v1->v2: > * Change defaults to performance (AC) and balance_performance (DC) > * Default Kconfig to disabled for now > * Rebase on latest branch > --- > Documentation/admin-guide/pm/amd-pstate.rst | 18 ++- > drivers/cpufreq/Kconfig.x86 | 12 ++ > drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++-- > drivers/cpufreq/amd-pstate.h | 5 +- > 4 files changed, 155 insertions(+), 9 deletions(-) > [Snip] > diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c > index e98ef41083ba1..f00fb4ba9f26e 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,7 @@ 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 = CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP; Is there an #ifdef needed here? I see build error when X86_AMD_PSTATE_DYNAMIC_EPP is not set in config
On 3/11/2025 01:34, Dhananjay Ugwekar wrote: > On 3/4/2025 8:53 PM, Mario Limonciello wrote: >> From: Mario Limonciello <mario.limonciello@amd.com> >> >> Dynamic energy performance preference will change 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. >> >> For non-server systems: >> * the default EPP for AC mode is `performance`. >> * the default EPP for DC mode is `balance_performance`. >> >> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> >> --- >> v1->v2: >> * Change defaults to performance (AC) and balance_performance (DC) >> * Default Kconfig to disabled for now >> * Rebase on latest branch >> --- >> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++- >> drivers/cpufreq/Kconfig.x86 | 12 ++ >> drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++-- >> drivers/cpufreq/amd-pstate.h | 5 +- >> 4 files changed, 155 insertions(+), 9 deletions(-) >> > [Snip] >> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c >> index e98ef41083ba1..f00fb4ba9f26e 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,7 @@ 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 = CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP; > > Is there an #ifdef needed here? I see build error when X86_AMD_PSTATE_DYNAMIC_EPP is not set in config > Ah yeah, I see the same too when I check that config. Not sure why build robot didn't catch this. Will add this for next version. diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index dcf6e36d693f8..824756ac0010e 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -87,7 +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 = false; +#endif static struct quirk_entry *quirks; /*
Hello Mario,
On Tue, Mar 04, 2025 at 09:23:23AM -0600, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
>
> Dynamic energy performance preference will change 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.
>
> For non-server systems:
> * the default EPP for AC mode is `performance`.
> * the default EPP for DC mode is `balance_performance`.
>
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
> v1->v2:
> * Change defaults to performance (AC) and balance_performance (DC)
> * Default Kconfig to disabled for now
> * Rebase on latest branch
> ---
> Documentation/admin-guide/pm/amd-pstate.rst | 18 ++-
> drivers/cpufreq/Kconfig.x86 | 12 ++
> drivers/cpufreq/amd-pstate.c | 129 ++++++++++++++++++--
> drivers/cpufreq/amd-pstate.h | 5 +-
> 4 files changed, 155 insertions(+), 9 deletions(-)
>
> diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
> index 412423c54f258..2e076650dc77c 100644
> --- a/Documentation/admin-guide/pm/amd-pstate.rst
> +++ b/Documentation/admin-guide/pm/amd-pstate.rst
[...snip..]
> @@ -311,6 +311,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 with 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 97c2d4f15d76e..c5ef92634ddf4 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 kenrel to dynamically change the energy performance
^^^^^^
kernel
> + 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 e98ef41083ba1..f00fb4ba9f26e 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,7 @@ 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 = CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP;
> static struct quirk_entry *quirks;
>
> /*
> @@ -1050,6 +1052,73 @@ static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
> kfree(cpudata);
> }
>
> +static int amd_pstate_get_balanced_epp(struct cpufreq_policy *policy)
Can we rename this function as amd_pstate_get_dynamic_epp() ?
Because the values being returned may not be
balance_performance/balance_power.
> +{
> + 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) {
> + ret = power_supply_reg_notifier(&cpudata->power_nb);
> + if (ret)
> + goto cleanup;
> + cpudata->power_nb.notifier_call = amd_pstate_power_supply_notifier;
> + }
> +
> + cpudata->dynamic_epp = true;
> +
> + return 0;
> +
> +cleanup:
> + amd_pstate_clear_dynamic_epp(policy);
> +
> + return ret;
> +}
> +
> /* Sysfs attributes */
>
> /*
> @@ -1146,6 +1215,11 @@ 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 = sscanf(buf, "%20s", str_preference);
> if (ret != 1)
> return -EINVAL;
> @@ -1154,10 +1228,10 @@ static ssize_t store_energy_performance_preference(
> 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");
> @@ -1165,6 +1239,8 @@ static ssize_t store_energy_performance_preference(
> }
>
> ret = amd_pstate_set_epp(policy, epp);
> + if (ret)
> + return ret;
Isn't this unecessary given that the next line is doing exactly this ?
>
> return ret ? ret : count;
> }
Rest of the patch looks good to me.
--
Thanks and Regards
gautham.
© 2016 - 2026 Red Hat, Inc.