public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/5] amd-pstate Dynamic EPP and raw EPP
@ 2026-01-06  5:14 Mario Limonciello (AMD)
  2026-01-06  5:14 ` [PATCH v5 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference Mario Limonciello (AMD)
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Mario Limonciello (AMD) @ 2026-01-06  5:14 UTC (permalink / raw)
  To: Gautham R . Shenoy
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK,
	Mario Limonciello (AMD)

Dynamic EPP allows the kernel to register amd-pstate as part of
a platform profile. It will change EPP modes matching the user's
preference to the platform profile sysfs files as well as power
adapter state.

Raw EPP allows userspace to write integers to
energy_performance_preference.

v4: https://lore.kernel.org/linux-pm/20250321022858.1538173-1-superm1@kernel.org/
Mario Limonciello (5):
  cpufreq/amd-pstate: Add dynamic energy performance preference
  cpufreq/amd-pstate: add kernel command line to override dynamic epp
  cpufreq/amd-pstate: Add support for platform profile class
  cpufreq/amd-pstate: Add support for raw EPP writes
  cpufreq/amd-pstate-ut: Add a unit test for raw EPP

 .../admin-guide/kernel-parameters.txt         |   7 +
 Documentation/admin-guide/pm/amd-pstate.rst   |  41 ++-
 drivers/cpufreq/Kconfig.x86                   |  13 +
 drivers/cpufreq/amd-pstate-ut.c               |  58 ++++
 drivers/cpufreq/amd-pstate.c                  | 283 ++++++++++++++++--
 drivers/cpufreq/amd-pstate.h                  |  16 +-
 6 files changed, 394 insertions(+), 24 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v5 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference
  2026-01-06  5:14 [PATCH v5 0/5] amd-pstate Dynamic EPP and raw EPP Mario Limonciello (AMD)
@ 2026-01-06  5:14 ` Mario Limonciello (AMD)
  2026-03-27  6:43   ` Gautham R. Shenoy
  2026-01-06  5:14 ` [PATCH v5 2/5] cpufreq/amd-pstate: add kernel command line to override dynamic epp Mario Limonciello (AMD)
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Mario Limonciello (AMD) @ 2026-01-06  5:14 UTC (permalink / raw)
  To: Gautham R . Shenoy
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

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>
---
v4->v5:
 * Rebase on 6.19-rc1
 * Fix initialization for static variable
 * Whitespace on if/else fix
v3->v4:
 * Handle Kconfig not being set
 * Fix dynamic epp default on server
v2-v3:
 * Fix typo in Kconfig
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                | 133 ++++++++++++++++++--
 drivers/cpufreq/amd-pstate.h                |   5 +-
 4 files changed, 159 insertions(+), 9 deletions(-)

diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index e1771f2225d5f..5aa9fb77a078c 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 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 c45bc98721d24..26a8552581c57 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;
 
 /*
@@ -1067,6 +1073,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 */
 
 /*
@@ -1161,14 +1234,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");
@@ -1176,6 +1254,8 @@ static ssize_t store_energy_performance_preference(
 	}
 
 	ret = amd_pstate_set_epp(policy, epp);
+	if (ret)
+		return ret;
 
 	return ret ? ret : count;
 }
@@ -1387,6 +1467,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);
 
@@ -1397,6 +1503,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,
@@ -1421,6 +1528,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
 };
 
@@ -1512,15 +1620,20 @@ 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) {
+		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+		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;
 
@@ -1542,6 +1655,8 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
 		/* Reset CPPC_REQ MSR to the BIOS value */
 		amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
 
+		if (cpudata->dynamic_epp)
+			amd_pstate_clear_dynamic_epp(policy);
 		kfree(cpudata);
 		policy->driver_data = NULL;
 	}
@@ -1579,6 +1694,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 powersave policy while dynamic epp is enabled */
+	if (policy->policy == CPUFREQ_POLICY_POWERSAVE && cpudata->dynamic_epp)
+		return -EBUSY;
+
 	cpudata->policy = policy->policy;
 
 	ret = amd_pstate_epp_update_limit(policy, true);
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index cb45fdca27a6c..7bfe5f8115623 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -106,7 +106,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


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v5 2/5] cpufreq/amd-pstate: add kernel command line to override dynamic epp
  2026-01-06  5:14 [PATCH v5 0/5] amd-pstate Dynamic EPP and raw EPP Mario Limonciello (AMD)
  2026-01-06  5:14 ` [PATCH v5 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference Mario Limonciello (AMD)
@ 2026-01-06  5:14 ` Mario Limonciello (AMD)
  2026-03-27  6:45   ` Gautham R. Shenoy
  2026-01-06  5:14 ` [PATCH v5 3/5] cpufreq/amd-pstate: Add support for platform profile class Mario Limonciello (AMD)
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Mario Limonciello (AMD) @ 2026-01-06  5:14 UTC (permalink / raw)
  To: Gautham R . Shenoy
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

From: Mario Limonciello <mario.limonciello@amd.com>

Add `amd_dynamic_epp=enable` and `amd_dynamic_epp=disable` to override
the kernel configuration option `CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP`
locally.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 Documentation/admin-guide/kernel-parameters.txt |  7 +++++++
 Documentation/admin-guide/pm/amd-pstate.rst     |  7 +++++++
 drivers/cpufreq/amd-pstate.c                    | 11 +++++++++++
 3 files changed, 25 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index a8d0afde7f85a..d7d547bbda430 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -490,6 +490,13 @@ Kernel parameters
 			disable
 			  Disable amd-pstate preferred core.
 
+	amd_dynamic_epp=
+			[X86]
+			disable
+			  Disable amd-pstate dynamic EPP.
+			enable
+			  Enable amd-pstate dynamic EPP.
+
 	amijoy.map=	[HW,JOY] Amiga joystick support
 			Map of devices attached to JOY0DAT and JOY1DAT
 			Format: <a>,<b>
diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index 5aa9fb77a078c..df4607b6a5f62 100644
--- a/Documentation/admin-guide/pm/amd-pstate.rst
+++ b/Documentation/admin-guide/pm/amd-pstate.rst
@@ -438,6 +438,13 @@ For systems that support ``amd-pstate`` preferred core, the core rankings will
 always be advertised by the platform. But OS can choose to ignore that via the
 kernel parameter ``amd_prefcore=disable``.
 
+``amd_dynamic_epp``
+
+When AMD pstate is in auto mode, dynamic EPP will control whether the kernel
+autonomously changes the EPP mode. The default is configured by
+``CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP`` but can be explicitly enabled with
+``amd_pstate_epp=enable`` or disabled with ``amd_pstate_epp=disable``.
+
 User Space Interface in ``sysfs`` - General
 ===========================================
 
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 26a8552581c57..7dd50b5825d78 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1992,8 +1992,19 @@ 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");
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v5 3/5] cpufreq/amd-pstate: Add support for platform profile class
  2026-01-06  5:14 [PATCH v5 0/5] amd-pstate Dynamic EPP and raw EPP Mario Limonciello (AMD)
  2026-01-06  5:14 ` [PATCH v5 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference Mario Limonciello (AMD)
  2026-01-06  5:14 ` [PATCH v5 2/5] cpufreq/amd-pstate: add kernel command line to override dynamic epp Mario Limonciello (AMD)
@ 2026-01-06  5:14 ` Mario Limonciello (AMD)
  2026-03-27  6:58   ` Gautham R. Shenoy
  2026-01-06  5:14 ` [PATCH v5 4/5] cpufreq/amd-pstate: Add support for raw EPP writes Mario Limonciello (AMD)
  2026-01-06  5:14 ` [PATCH v5 5/5] cpufreq/amd-pstate-ut: Add a unit test for raw EPP Mario Limonciello (AMD)
  4 siblings, 1 reply; 11+ messages in thread
From: Mario Limonciello (AMD) @ 2026-01-06  5:14 UTC (permalink / raw)
  To: Gautham R . Shenoy
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

From: Mario Limonciello <mario.limonciello@amd.com>

The platform profile core allows multiple drivers and devices to
register platform profile support.

When the legacy platform profile interface is used all drivers will
adjust the platform profile as well.

Add support for registering every CPU with the platform profile handler
when dynamic EPP is enabled.

The end result will be that changing the platform profile will modify
EPP accordingly.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 Documentation/admin-guide/pm/amd-pstate.rst |   4 +-
 drivers/cpufreq/Kconfig.x86                 |   1 +
 drivers/cpufreq/amd-pstate.c                | 144 +++++++++++++++++---
 drivers/cpufreq/amd-pstate.h                |  10 ++
 4 files changed, 141 insertions(+), 18 deletions(-)

diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index df4607b6a5f62..a6745f2358e61 100644
--- a/Documentation/admin-guide/pm/amd-pstate.rst
+++ b/Documentation/admin-guide/pm/amd-pstate.rst
@@ -321,7 +321,9 @@ Whether this behavior is enabled by default with the kernel config option
 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.
+profile when the machine is running on battery or AC power. The driver will
+also register with the platform profile handler to receive notifications of
+user desired power state and react to those.
 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.
 
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index cdaa8d858045a..a0dbb9808ae99 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -40,6 +40,7 @@ config X86_AMD_PSTATE
 	select ACPI_PROCESSOR
 	select ACPI_CPPC_LIB if X86_64
 	select CPU_FREQ_GOV_SCHEDUTIL if SMP
+	select ACPI_PLATFORM_PROFILE
 	help
 	  This driver adds a CPUFreq driver which utilizes a fine grain
 	  processor performance frequency control range instead of legacy
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 7dd50b5825d78..e1ccbbdd56d42 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -109,6 +109,7 @@ static struct quirk_entry *quirks;
  *	2		balance_performance
  *	3		balance_power
  *	4		power
+ *	5		custom (for raw EPP values)
  */
 enum energy_perf_value_index {
 	EPP_INDEX_DEFAULT = 0,
@@ -116,6 +117,7 @@ enum energy_perf_value_index {
 	EPP_INDEX_BALANCE_PERFORMANCE,
 	EPP_INDEX_BALANCE_POWERSAVE,
 	EPP_INDEX_POWERSAVE,
+	EPP_INDEX_CUSTOM,
 	EPP_INDEX_MAX,
 };
 
@@ -125,6 +127,7 @@ static const char * const energy_perf_strings[] = {
 	[EPP_INDEX_BALANCE_PERFORMANCE] = "balance_performance",
 	[EPP_INDEX_BALANCE_POWERSAVE] = "balance_power",
 	[EPP_INDEX_POWERSAVE] = "power",
+	[EPP_INDEX_CUSTOM] = "custom",
 };
 static_assert(ARRAY_SIZE(energy_perf_strings) == EPP_INDEX_MAX);
 
@@ -135,7 +138,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);
+static_assert(ARRAY_SIZE(epp_values) == EPP_INDEX_MAX - 1);
 
 typedef int (*cppc_mode_transition_fn)(int);
 
@@ -1094,6 +1097,10 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
 	if (event != PSY_EVENT_PROP_CHANGED)
 		return NOTIFY_OK;
 
+	/* dynamic actions are only applied while platform profile is in balanced */
+	if (cpudata->current_profile != PLATFORM_PROFILE_BALANCED)
+		return 0;
+
 	epp = amd_pstate_get_balanced_epp(policy);
 
 	ret = amd_pstate_set_epp(policy, epp);
@@ -1102,14 +1109,84 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
 
 	return NOTIFY_OK;
 }
-static void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy)
+
+static int amd_pstate_profile_probe(void *drvdata, unsigned long *choices)
+{
+	set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
+	set_bit(PLATFORM_PROFILE_BALANCED, choices);
+	set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
+
+	return 0;
+}
+
+static int amd_pstate_profile_get(struct device *dev,
+				  enum platform_profile_option *profile)
+{
+	struct amd_cpudata *cpudata = dev_get_drvdata(dev);
+
+	*profile = cpudata->current_profile;
+
+	return 0;
+}
+
+static int amd_pstate_profile_set(struct device *dev,
+				  enum platform_profile_option profile)
+{
+	struct amd_cpudata *cpudata = dev_get_drvdata(dev);
+	struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu);
+	int ret;
+
+	switch (profile) {
+	case PLATFORM_PROFILE_LOW_POWER:
+		if (cpudata->policy != CPUFREQ_POLICY_POWERSAVE)
+			cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
+		ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_POWERSAVE);
+		if (ret)
+			return ret;
+		break;
+	case PLATFORM_PROFILE_BALANCED:
+		if (cpudata->policy != CPUFREQ_POLICY_POWERSAVE)
+			cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
+		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;
+	}
+
+	cpudata->current_profile = profile;
+
+	return 0;
+}
+
+static const struct platform_profile_ops amd_pstate_profile_ops = {
+	.probe = amd_pstate_profile_probe,
+	.profile_set = amd_pstate_profile_set,
+	.profile_get = amd_pstate_profile_get,
+};
+
+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);
+	if (cpudata->ppdev) {
+		platform_profile_remove(cpudata->ppdev);
+		cpudata->ppdev = NULL;
+	}
+	kfree(cpudata->profile_name);
 	cpudata->dynamic_epp = false;
 }
+EXPORT_SYMBOL_GPL(amd_pstate_clear_dynamic_epp);
 
 static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
 {
@@ -1117,11 +1194,35 @@ static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
 	int ret;
 	u8 epp;
 
-	epp = amd_pstate_get_balanced_epp(policy);
+	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_set_epp(policy, epp);
 	if (ret)
 		return ret;
 
+	cpudata->profile_name = kasprintf(GFP_KERNEL, "amd-pstate-epp-cpu%d", cpudata->cpu);
+
+	cpudata->ppdev = platform_profile_register(get_cpu_device(policy->cpu),
+						   cpudata->profile_name,
+						   policy->driver_data,
+						   &amd_pstate_profile_ops);
+	if (IS_ERR(cpudata->ppdev)) {
+		ret = PTR_ERR(cpudata->ppdev);
+		goto cleanup;
+	}
+
 	/* 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);
@@ -1227,8 +1328,8 @@ static ssize_t show_energy_performance_available_preferences(
 	return offset;
 }
 
-static ssize_t store_energy_performance_preference(
-		struct cpufreq_policy *policy, const char *buf, size_t count)
+ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
+					    const char *buf, size_t count)
 {
 	struct amd_cpudata *cpudata = policy->driver_data;
 	ssize_t ret;
@@ -1239,16 +1340,22 @@ static ssize_t store_energy_performance_preference(
 		return -EBUSY;
 	}
 
-	ret = sysfs_match_string(energy_perf_strings, buf);
-	if (ret < 0)
-		return -EINVAL;
-
-	if (ret)
-		epp = epp_values[ret];
-	else
-		epp = amd_pstate_get_balanced_epp(policy);
+	/*
+	 * if the value matches a number, use that, otherwise see if
+	 * matches an index in the energy_perf_strings array
+	 */
+	ret = kstrtou8(buf, 0, &epp);
+	if (ret) {
+		ret = sysfs_match_string(energy_perf_strings, buf);
+		if (ret < 0 || ret == EPP_INDEX_CUSTOM)
+			return -EINVAL;
+		if (ret)
+			epp = epp_values[ret];
+		else
+			epp = amd_pstate_get_balanced_epp(policy);
+	}
 
-	if (epp > 0 && policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
+	if (epp > 0 && cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
 		pr_debug("EPP cannot be set under performance policy\n");
 		return -EBUSY;
 	}
@@ -1259,9 +1366,9 @@ static ssize_t store_energy_performance_preference(
 
 	return ret ? ret : count;
 }
+EXPORT_SYMBOL_GPL(store_energy_performance_preference);
 
-static ssize_t show_energy_performance_preference(
-				struct cpufreq_policy *policy, char *buf)
+ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf)
 {
 	struct amd_cpudata *cpudata = policy->driver_data;
 	u8 preference, epp;
@@ -1282,11 +1389,12 @@ static ssize_t show_energy_performance_preference(
 		preference = EPP_INDEX_POWERSAVE;
 		break;
 	default:
-		return -EINVAL;
+		return sysfs_emit(buf, "%u\n", epp);
 	}
 
 	return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
 }
+EXPORT_SYMBOL_GPL(show_energy_performance_preference);
 
 static void amd_pstate_driver_cleanup(void)
 {
@@ -1621,10 +1729,12 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
 	    amd_pstate_acpi_pm_profile_undefined()) {
 		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
 		cpudata->epp_default_ac = cpudata->epp_default_dc = amd_pstate_get_epp(cpudata);
+		cpudata->current_profile = PLATFORM_PROFILE_PERFORMANCE;
 	} else {
 		policy->policy = CPUFREQ_POLICY_POWERSAVE;
 		cpudata->epp_default_ac = AMD_CPPC_EPP_PERFORMANCE;
 		cpudata->epp_default_dc = AMD_CPPC_EPP_BALANCE_PERFORMANCE;
+		cpudata->current_profile = PLATFORM_PROFILE_BALANCED;
 	}
 
 	if (dynamic_epp) {
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index 7bfe5f8115623..9839c7c6558f4 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -9,6 +9,7 @@
 #define _LINUX_AMD_PSTATE_H
 
 #include <linux/pm_qos.h>
+#include <linux/platform_profile.h>
 
 /*********************************************************************
  *                        AMD P-state INTERFACE                       *
@@ -110,6 +111,11 @@ struct amd_cpudata {
 	u8	epp_default_dc;
 	bool	dynamic_epp;
 	struct notifier_block power_nb;
+
+	/* platform profile */
+	enum platform_profile_option current_profile;
+	struct device *ppdev;
+	char *profile_name;
 };
 
 /*
@@ -126,5 +132,9 @@ enum amd_pstate_mode {
 const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode);
 int amd_pstate_get_status(void);
 int amd_pstate_update_status(const char *buf, size_t size);
+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);
 
 #endif /* _LINUX_AMD_PSTATE_H */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v5 4/5] cpufreq/amd-pstate: Add support for raw EPP writes
  2026-01-06  5:14 [PATCH v5 0/5] amd-pstate Dynamic EPP and raw EPP Mario Limonciello (AMD)
                   ` (2 preceding siblings ...)
  2026-01-06  5:14 ` [PATCH v5 3/5] cpufreq/amd-pstate: Add support for platform profile class Mario Limonciello (AMD)
@ 2026-01-06  5:14 ` Mario Limonciello (AMD)
  2026-03-27  8:41   ` Gautham R. Shenoy
  2026-01-06  5:14 ` [PATCH v5 5/5] cpufreq/amd-pstate-ut: Add a unit test for raw EPP Mario Limonciello (AMD)
  4 siblings, 1 reply; 11+ messages in thread
From: Mario Limonciello (AMD) @ 2026-01-06  5:14 UTC (permalink / raw)
  To: Gautham R . Shenoy
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

From: Mario Limonciello <mario.limonciello@amd.com>

The energy performance preference field of the CPPC request MSR
supports values from 0 to 255, but the strings only offer 4 values.

The other values are useful for tuning the performance of some
workloads.

Add support for writing the raw energy performance preference value
to the sysfs file.  If the last value written was an integer then
an integer will be returned.  If the last value written was a string
then a string will be returned.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 Documentation/admin-guide/pm/amd-pstate.rst | 16 +++++++++++-----
 drivers/cpufreq/amd-pstate.c                | 11 +++++++++--
 drivers/cpufreq/amd-pstate.h                |  1 +
 3 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index a6745f2358e61..674e76ff9293e 100644
--- a/Documentation/admin-guide/pm/amd-pstate.rst
+++ b/Documentation/admin-guide/pm/amd-pstate.rst
@@ -280,16 +280,22 @@ A list of all the supported EPP preferences that could be used for
 These profiles represent different hints that are provided
 to the low-level firmware about the user's desired energy vs efficiency
 tradeoff.  ``default`` represents the epp value is set by platform
-firmware. This attribute is read-only.
+firmware. ``custom`` designates that integer values 0-255 may be written
+as well.  This attribute is read-only.
 
 ``energy_performance_preference``
 
 The current energy performance preference can be read from this attribute.
 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, but if the dynamic EPP feature is enabled, driver will block writes.
+Coarse named profiles are available in the attribute
+``energy_performance_available_preferences``.
+Users can also write individual integer values between 0 to 255.
+When EPP feature is enabled by platform firmware but if the dynamic EPP feature is
+enabled, driver will ignore the written value. Lower epp values shift the bias
+towards improved performance while a higher epp value shifts the bias towards
+power-savings. The exact impact can change from one platform to the other.
+If a valid integer was last written, then a number will be returned on future reads.
+If a valid string was last written then a string will be returned on future reads.
 This attribute is read-write.
 
 ``boost``
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index e1ccbbdd56d42..14347baf3cefb 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -1333,6 +1333,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
 {
 	struct amd_cpudata *cpudata = policy->driver_data;
 	ssize_t ret;
+	bool raw_epp = FALSE;
 	u8 epp;
 
 	if (cpudata->dynamic_epp) {
@@ -1345,6 +1346,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
 	 * matches an index in the energy_perf_strings array
 	 */
 	ret = kstrtou8(buf, 0, &epp);
+	raw_epp = !ret;
 	if (ret) {
 		ret = sysfs_match_string(energy_perf_strings, buf);
 		if (ret < 0 || ret == EPP_INDEX_CUSTOM)
@@ -1364,7 +1366,9 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
 	if (ret)
 		return ret;
 
-	return ret ? ret : count;
+	cpudata->raw_epp = raw_epp;
+
+	return count;
 }
 EXPORT_SYMBOL_GPL(store_energy_performance_preference);
 
@@ -1375,6 +1379,9 @@ 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)
+		return sysfs_emit(buf, "%u\n", epp);
+
 	switch (epp) {
 	case AMD_CPPC_EPP_PERFORMANCE:
 		preference = EPP_INDEX_PERFORMANCE;
@@ -1389,7 +1396,7 @@ ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *
 		preference = EPP_INDEX_POWERSAVE;
 		break;
 	default:
-		return sysfs_emit(buf, "%u\n", epp);
+		return -EINVAL;
 	}
 
 	return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
index 9839c7c6558f4..38b575b8ad959 100644
--- a/drivers/cpufreq/amd-pstate.h
+++ b/drivers/cpufreq/amd-pstate.h
@@ -110,6 +110,7 @@ struct amd_cpudata {
 	u8	epp_default_ac;
 	u8	epp_default_dc;
 	bool	dynamic_epp;
+	bool	raw_epp;
 	struct notifier_block power_nb;
 
 	/* platform profile */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v5 5/5] cpufreq/amd-pstate-ut: Add a unit test for raw EPP
  2026-01-06  5:14 [PATCH v5 0/5] amd-pstate Dynamic EPP and raw EPP Mario Limonciello (AMD)
                   ` (3 preceding siblings ...)
  2026-01-06  5:14 ` [PATCH v5 4/5] cpufreq/amd-pstate: Add support for raw EPP writes Mario Limonciello (AMD)
@ 2026-01-06  5:14 ` Mario Limonciello (AMD)
  2026-03-27  8:59   ` Gautham R. Shenoy
  4 siblings, 1 reply; 11+ messages in thread
From: Mario Limonciello (AMD) @ 2026-01-06  5:14 UTC (permalink / raw)
  To: Gautham R . Shenoy
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

From: Mario Limonciello <mario.limonciello@amd.com>

Ensure that all supported raw EPP values work properly.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 drivers/cpufreq/amd-pstate-ut.c | 58 +++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c
index 447b9aa5ce40b..d51233b753db6 100644
--- a/drivers/cpufreq/amd-pstate-ut.c
+++ b/drivers/cpufreq/amd-pstate-ut.c
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/cleanup.h>
 
@@ -35,6 +36,7 @@
 
 #include "amd-pstate.h"
 
+DEFINE_FREE(cleanup_page, void *, if (_T) free_page((unsigned long)_T))
 
 struct amd_pstate_ut_struct {
 	const char *name;
@@ -48,6 +50,7 @@ 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_epp(u32 index);
 static int amd_pstate_ut_check_driver(u32 index);
 
 static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
@@ -55,6 +58,7 @@ static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
 	{"amd_pstate_ut_check_enabled",    amd_pstate_ut_check_enabled    },
 	{"amd_pstate_ut_check_perf",       amd_pstate_ut_check_perf       },
 	{"amd_pstate_ut_check_freq",       amd_pstate_ut_check_freq       },
+	{"amd_pstate_ut_epp",              amd_pstate_ut_epp              },
 	{"amd_pstate_ut_check_driver",	   amd_pstate_ut_check_driver     }
 };
 
@@ -241,6 +245,60 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
 	return amd_pstate_update_status(mode_str, strlen(mode_str));
 }
 
+static int amd_pstate_ut_epp(u32 index)
+{
+	struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
+	void *buf __free(cleanup_page) = NULL;
+	struct amd_cpudata *cpudata;
+	int ret, cpu = 0;
+	u16 epp;
+
+	policy = cpufreq_cpu_get(cpu);
+	if (!policy)
+		return -ENODEV;
+
+	cpudata = policy->driver_data;
+
+	/* disable dynamic EPP before running test */
+	if (cpudata->dynamic_epp) {
+		pr_debug("Dynamic EPP is enabled, disabling it\n");
+		amd_pstate_clear_dynamic_epp(policy);
+	}
+
+	buf = (void *)__get_free_page(GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE);
+	if (ret)
+		return ret;
+
+	for (epp = 0; epp <= U8_MAX; epp++) {
+		u8 val;
+
+		/* write all EPP values */
+		memset(buf, 0, sizeof(*buf));
+		snprintf(buf, PAGE_SIZE, "%d", epp);
+		ret = store_energy_performance_preference(policy, buf, sizeof(*buf));
+		if (ret < 0)
+			return ret;
+
+		/* check if the EPP value reads back correctly for raw numbers */
+		memset(buf, 0, sizeof(*buf));
+		ret = show_energy_performance_preference(policy, buf);
+		if (ret < 0)
+			return ret;
+		strreplace(buf, '\n', '\0');
+		ret = kstrtou8(buf, 0, &val);
+		if (!ret && epp != val) {
+			pr_err("Raw EPP value mismatch: %d != %d\n", epp, val);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int amd_pstate_ut_check_driver(u32 index)
 {
 	enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference
  2026-01-06  5:14 ` [PATCH v5 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference Mario Limonciello (AMD)
@ 2026-03-27  6:43   ` Gautham R. Shenoy
  0 siblings, 0 replies; 11+ messages in thread
From: Gautham R. Shenoy @ 2026-03-27  6:43 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

Hello Mario,


On Mon, Jan 05, 2026 at 11:14:37PM -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`.

In addition to these, the commit also adds a sysfs toggle, blocks
manual EPP, forces PERFORMANCE policy.

Might be good to mention these in the commit log.

> 
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>

[..snip..]


> +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;
> +}


Can the notifier_call assignment and registration be reordered?

The cpudata struct is allocated with kzalloc, so
power_nb.notifier_call is NULL when power_supply_reg_notifier() is
called.  power_supply_reg_notifier() calls
blocking_notifier_chain_register(), which adds the notifier block to
the chain and then releases the rwsem.

If power_supply_changed_work() fires between the registration and the
assignment, the notification path reaches notifier_call_chain():

kernel/notifier.c:notifier_call_chain() {
    ...
    ret = nb->notifier_call(nb, val, v);
    ...
}

At this point notifier_call is still NULL, resulting in a NULL pointer
dereference.  Setting notifier_call before calling
power_supply_reg_notifier() would close this window.



> +
>  /* Sysfs attributes */
>  

[..snip..]

>  
>  static struct freq_attr *amd_pstate_attr[] = {
>  	&amd_pstate_max_freq,
> @@ -1421,6 +1528,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
>  };
>  
> @@ -1512,15 +1620,20 @@ 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);

I wonder if we can set dynamic_epp to false for Server platforms.

The reason being that there are Server users who switch to the
powersave governor via a systemd startup script to set the right EPP.

With dynamic_epp = true, this is no longer possible. The user has to
first disable dynamic_epp and then switch to the powersave govenor.

Or perhaps you have a commandline override to disable dynamic_epp at boot time ?


-- 
Thanks and Regards
gautham.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 2/5] cpufreq/amd-pstate: add kernel command line to override dynamic epp
  2026-01-06  5:14 ` [PATCH v5 2/5] cpufreq/amd-pstate: add kernel command line to override dynamic epp Mario Limonciello (AMD)
@ 2026-03-27  6:45   ` Gautham R. Shenoy
  0 siblings, 0 replies; 11+ messages in thread
From: Gautham R. Shenoy @ 2026-03-27  6:45 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

On Mon, Jan 05, 2026 at 11:14:38PM -0600, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
> 
> Add `amd_dynamic_epp=enable` and `amd_dynamic_epp=disable` to override
> the kernel configuration option `CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP`
> locally.
> 
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
>  Documentation/admin-guide/kernel-parameters.txt |  7 +++++++
>  Documentation/admin-guide/pm/amd-pstate.rst     |  7 +++++++
>  drivers/cpufreq/amd-pstate.c                    | 11 +++++++++++
>  3 files changed, 25 insertions(+)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index a8d0afde7f85a..d7d547bbda430 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -490,6 +490,13 @@ Kernel parameters
>  			disable
>  			  Disable amd-pstate preferred core.
>  
> +	amd_dynamic_epp=
> +			[X86]
> +			disable
> +			  Disable amd-pstate dynamic EPP.
> +			enable
> +			  Enable amd-pstate dynamic EPP.
> +
>  	amijoy.map=	[HW,JOY] Amiga joystick support
>  			Map of devices attached to JOY0DAT and JOY1DAT
>  			Format: <a>,<b>
> diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
> index 5aa9fb77a078c..df4607b6a5f62 100644
> --- a/Documentation/admin-guide/pm/amd-pstate.rst
> +++ b/Documentation/admin-guide/pm/amd-pstate.rst
> @@ -438,6 +438,13 @@ For systems that support ``amd-pstate`` preferred core, the core rankings will
>  always be advertised by the platform. But OS can choose to ignore that via the
>  kernel parameter ``amd_prefcore=disable``.
>  
> +``amd_dynamic_epp``
> +
> +When AMD pstate is in auto mode, dynamic EPP will control whether the kernel
> +autonomously changes the EPP mode. The default is configured by
> +``CONFIG_X86_AMD_PSTATE_DYNAMIC_EPP`` but can be explicitly enabled with
> +``amd_pstate_epp=enable`` or disabled with ``amd_pstate_epp=disable``.

Do you mean amd_dynamic_epp instead of amd_pstate_epp here ?

The code and kernel-parameters.txt both use
amd_dynamic_epp, not amd_pstate_epp:

drivers/cpufreq/amd-pstate.c:
    early_param("amd_dynamic_epp", amd_dynamic_epp_param);

Documentation/admin-guide/kernel-parameters.txt:
    amd_dynamic_epp=
    
> +
>  User Space Interface in ``sysfs`` - General
>  ===========================================
>  
> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
> index 26a8552581c57..7dd50b5825d78 100644
> --- a/drivers/cpufreq/amd-pstate.c
> +++ b/drivers/cpufreq/amd-pstate.c
> @@ -1992,8 +1992,19 @@ 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");
> 
> -- 
> 2.43.0
> 

-- 
Thanks and Regards
gautham.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 3/5] cpufreq/amd-pstate: Add support for platform profile class
  2026-01-06  5:14 ` [PATCH v5 3/5] cpufreq/amd-pstate: Add support for platform profile class Mario Limonciello (AMD)
@ 2026-03-27  6:58   ` Gautham R. Shenoy
  0 siblings, 0 replies; 11+ messages in thread
From: Gautham R. Shenoy @ 2026-03-27  6:58 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

On Mon, Jan 05, 2026 at 11:14:39PM -0600, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
> 
> The platform profile core allows multiple drivers and devices to
> register platform profile support.
> 
> When the legacy platform profile interface is used all drivers will
> adjust the platform profile as well.
> 
> Add support for registering every CPU with the platform profile handler
> when dynamic EPP is enabled.
> 
> The end result will be that changing the platform profile will modify
> EPP accordingly.

The commit message only describes the platform profile integration.

However, the patch also does the following other things

 * introduces raw integer EPP parsing via in store_energy_performance_preference()
 
 * adds EPP_INDEX_CUSTOM
 
 * exports store_energy_performance_preference(),
   show_energy_performance_preference(), and
   amd_pstate_clear_dynamic_epp()

 * changes the performance policy check from policy->policy to
   cpudata->policy.


These are separate functional changes that aren't mentioned in the
changelog.

Or perhaps split the suport for raw epp as a separate patch, and the
policy check from policy->policy to use cpudata->policy as a separate
check.

-- 
Thanks and Regards
gautham.

> 
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
>  Documentation/admin-guide/pm/amd-pstate.rst |   4 +-
>  drivers/cpufreq/Kconfig.x86                 |   1 +
>  drivers/cpufreq/amd-pstate.c                | 144 +++++++++++++++++---
>  drivers/cpufreq/amd-pstate.h                |  10 ++
>  4 files changed, 141 insertions(+), 18 deletions(-)
> 
> diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
> index df4607b6a5f62..a6745f2358e61 100644
> --- a/Documentation/admin-guide/pm/amd-pstate.rst
> +++ b/Documentation/admin-guide/pm/amd-pstate.rst
> @@ -321,7 +321,9 @@ Whether this behavior is enabled by default with the kernel config option
>  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.
> +profile when the machine is running on battery or AC power. The driver will
> +also register with the platform profile handler to receive notifications of
> +user desired power state and react to those.
>  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.
>  
> diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
> index cdaa8d858045a..a0dbb9808ae99 100644
> --- a/drivers/cpufreq/Kconfig.x86
> +++ b/drivers/cpufreq/Kconfig.x86
> @@ -40,6 +40,7 @@ config X86_AMD_PSTATE
>  	select ACPI_PROCESSOR
>  	select ACPI_CPPC_LIB if X86_64
>  	select CPU_FREQ_GOV_SCHEDUTIL if SMP
> +	select ACPI_PLATFORM_PROFILE
>  	help
>  	  This driver adds a CPUFreq driver which utilizes a fine grain
>  	  processor performance frequency control range instead of legacy
> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
> index 7dd50b5825d78..e1ccbbdd56d42 100644
> --- a/drivers/cpufreq/amd-pstate.c
> +++ b/drivers/cpufreq/amd-pstate.c
> @@ -109,6 +109,7 @@ static struct quirk_entry *quirks;
>   *	2		balance_performance
>   *	3		balance_power
>   *	4		power
> + *	5		custom (for raw EPP values)
>   */
>  enum energy_perf_value_index {
>  	EPP_INDEX_DEFAULT = 0,
> @@ -116,6 +117,7 @@ enum energy_perf_value_index {
>  	EPP_INDEX_BALANCE_PERFORMANCE,
>  	EPP_INDEX_BALANCE_POWERSAVE,
>  	EPP_INDEX_POWERSAVE,
> +	EPP_INDEX_CUSTOM,
>  	EPP_INDEX_MAX,
>  };
>  
> @@ -125,6 +127,7 @@ static const char * const energy_perf_strings[] = {
>  	[EPP_INDEX_BALANCE_PERFORMANCE] = "balance_performance",
>  	[EPP_INDEX_BALANCE_POWERSAVE] = "balance_power",
>  	[EPP_INDEX_POWERSAVE] = "power",
> +	[EPP_INDEX_CUSTOM] = "custom",
>  };
>  static_assert(ARRAY_SIZE(energy_perf_strings) == EPP_INDEX_MAX);
>  
> @@ -135,7 +138,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);
> +static_assert(ARRAY_SIZE(epp_values) == EPP_INDEX_MAX - 1);
>  
>  typedef int (*cppc_mode_transition_fn)(int);
>  
> @@ -1094,6 +1097,10 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
>  	if (event != PSY_EVENT_PROP_CHANGED)
>  		return NOTIFY_OK;
>  
> +	/* dynamic actions are only applied while platform profile is in balanced */
> +	if (cpudata->current_profile != PLATFORM_PROFILE_BALANCED)
> +		return 0;
> +
>  	epp = amd_pstate_get_balanced_epp(policy);
>  
>  	ret = amd_pstate_set_epp(policy, epp);
> @@ -1102,14 +1109,84 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
>  
>  	return NOTIFY_OK;
>  }
> -static void amd_pstate_clear_dynamic_epp(struct cpufreq_policy *policy)
> +
> +static int amd_pstate_profile_probe(void *drvdata, unsigned long *choices)
> +{
> +	set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
> +	set_bit(PLATFORM_PROFILE_BALANCED, choices);
> +	set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
> +
> +	return 0;
> +}
> +
> +static int amd_pstate_profile_get(struct device *dev,
> +				  enum platform_profile_option *profile)
> +{
> +	struct amd_cpudata *cpudata = dev_get_drvdata(dev);
> +
> +	*profile = cpudata->current_profile;
> +
> +	return 0;
> +}
> +
> +static int amd_pstate_profile_set(struct device *dev,
> +				  enum platform_profile_option profile)
> +{
> +	struct amd_cpudata *cpudata = dev_get_drvdata(dev);
> +	struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpudata->cpu);
> +	int ret;
> +
> +	switch (profile) {
> +	case PLATFORM_PROFILE_LOW_POWER:
> +		if (cpudata->policy != CPUFREQ_POLICY_POWERSAVE)
> +			cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
> +		ret = amd_pstate_set_epp(policy, AMD_CPPC_EPP_POWERSAVE);
> +		if (ret)
> +			return ret;
> +		break;
> +	case PLATFORM_PROFILE_BALANCED:
> +		if (cpudata->policy != CPUFREQ_POLICY_POWERSAVE)
> +			cpudata->policy = CPUFREQ_POLICY_POWERSAVE;
> +		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;
> +	}
> +
> +	cpudata->current_profile = profile;
> +
> +	return 0;
> +}
> +
> +static const struct platform_profile_ops amd_pstate_profile_ops = {
> +	.probe = amd_pstate_profile_probe,
> +	.profile_set = amd_pstate_profile_set,
> +	.profile_get = amd_pstate_profile_get,
> +};
> +
> +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);
> +	if (cpudata->ppdev) {
> +		platform_profile_remove(cpudata->ppdev);
> +		cpudata->ppdev = NULL;
> +	}
> +	kfree(cpudata->profile_name);
>  	cpudata->dynamic_epp = false;
>  }
> +EXPORT_SYMBOL_GPL(amd_pstate_clear_dynamic_epp);
>  
>  static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
>  {
> @@ -1117,11 +1194,35 @@ static int amd_pstate_set_dynamic_epp(struct cpufreq_policy *policy)
>  	int ret;
>  	u8 epp;
>  
> -	epp = amd_pstate_get_balanced_epp(policy);
> +	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_set_epp(policy, epp);
>  	if (ret)
>  		return ret;
>  
> +	cpudata->profile_name = kasprintf(GFP_KERNEL, "amd-pstate-epp-cpu%d", cpudata->cpu);
> +
> +	cpudata->ppdev = platform_profile_register(get_cpu_device(policy->cpu),
> +						   cpudata->profile_name,
> +						   policy->driver_data,
> +						   &amd_pstate_profile_ops);
> +	if (IS_ERR(cpudata->ppdev)) {
> +		ret = PTR_ERR(cpudata->ppdev);
> +		goto cleanup;
> +	}
> +
>  	/* 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);
> @@ -1227,8 +1328,8 @@ static ssize_t show_energy_performance_available_preferences(
>  	return offset;
>  }
>  
> -static ssize_t store_energy_performance_preference(
> -		struct cpufreq_policy *policy, const char *buf, size_t count)
> +ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
> +					    const char *buf, size_t count)
>  {
>  	struct amd_cpudata *cpudata = policy->driver_data;
>  	ssize_t ret;
> @@ -1239,16 +1340,22 @@ static ssize_t store_energy_performance_preference(
>  		return -EBUSY;
>  	}
>  
> -	ret = sysfs_match_string(energy_perf_strings, buf);
> -	if (ret < 0)
> -		return -EINVAL;
> -
> -	if (ret)
> -		epp = epp_values[ret];
> -	else
> -		epp = amd_pstate_get_balanced_epp(policy);
> +	/*
> +	 * if the value matches a number, use that, otherwise see if
> +	 * matches an index in the energy_perf_strings array
> +	 */
> +	ret = kstrtou8(buf, 0, &epp);
> +	if (ret) {
> +		ret = sysfs_match_string(energy_perf_strings, buf);
> +		if (ret < 0 || ret == EPP_INDEX_CUSTOM)
> +			return -EINVAL;
> +		if (ret)
> +			epp = epp_values[ret];
> +		else
> +			epp = amd_pstate_get_balanced_epp(policy);
> +	}
>  
> -	if (epp > 0 && policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
> +	if (epp > 0 && cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
>  		pr_debug("EPP cannot be set under performance policy\n");
>  		return -EBUSY;
>  	}
> @@ -1259,9 +1366,9 @@ static ssize_t store_energy_performance_preference(
>  
>  	return ret ? ret : count;
>  }
> +EXPORT_SYMBOL_GPL(store_energy_performance_preference);
>  
> -static ssize_t show_energy_performance_preference(
> -				struct cpufreq_policy *policy, char *buf)
> +ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf)
>  {
>  	struct amd_cpudata *cpudata = policy->driver_data;
>  	u8 preference, epp;
> @@ -1282,11 +1389,12 @@ static ssize_t show_energy_performance_preference(
>  		preference = EPP_INDEX_POWERSAVE;
>  		break;
>  	default:
> -		return -EINVAL;
> +		return sysfs_emit(buf, "%u\n", epp);
>  	}
>  
>  	return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
>  }
> +EXPORT_SYMBOL_GPL(show_energy_performance_preference);
>  
>  static void amd_pstate_driver_cleanup(void)
>  {
> @@ -1621,10 +1729,12 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
>  	    amd_pstate_acpi_pm_profile_undefined()) {
>  		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
>  		cpudata->epp_default_ac = cpudata->epp_default_dc = amd_pstate_get_epp(cpudata);
> +		cpudata->current_profile = PLATFORM_PROFILE_PERFORMANCE;
>  	} else {
>  		policy->policy = CPUFREQ_POLICY_POWERSAVE;
>  		cpudata->epp_default_ac = AMD_CPPC_EPP_PERFORMANCE;
>  		cpudata->epp_default_dc = AMD_CPPC_EPP_BALANCE_PERFORMANCE;
> +		cpudata->current_profile = PLATFORM_PROFILE_BALANCED;
>  	}
>  
>  	if (dynamic_epp) {
> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
> index 7bfe5f8115623..9839c7c6558f4 100644
> --- a/drivers/cpufreq/amd-pstate.h
> +++ b/drivers/cpufreq/amd-pstate.h
> @@ -9,6 +9,7 @@
>  #define _LINUX_AMD_PSTATE_H
>  
>  #include <linux/pm_qos.h>
> +#include <linux/platform_profile.h>
>  
>  /*********************************************************************
>   *                        AMD P-state INTERFACE                       *
> @@ -110,6 +111,11 @@ struct amd_cpudata {
>  	u8	epp_default_dc;
>  	bool	dynamic_epp;
>  	struct notifier_block power_nb;
> +
> +	/* platform profile */
> +	enum platform_profile_option current_profile;
> +	struct device *ppdev;
> +	char *profile_name;
>  };
>  
>  /*
> @@ -126,5 +132,9 @@ enum amd_pstate_mode {
>  const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode);
>  int amd_pstate_get_status(void);
>  int amd_pstate_update_status(const char *buf, size_t size);
> +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);
>  
>  #endif /* _LINUX_AMD_PSTATE_H */
> 
> -- 
> 2.43.0
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 4/5] cpufreq/amd-pstate: Add support for raw EPP writes
  2026-01-06  5:14 ` [PATCH v5 4/5] cpufreq/amd-pstate: Add support for raw EPP writes Mario Limonciello (AMD)
@ 2026-03-27  8:41   ` Gautham R. Shenoy
  0 siblings, 0 replies; 11+ messages in thread
From: Gautham R. Shenoy @ 2026-03-27  8:41 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

On Mon, Jan 05, 2026 at 11:14:40PM -0600, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
> 
> The energy performance preference field of the CPPC request MSR
> supports values from 0 to 255, but the strings only offer 4 values.
> 
> The other values are useful for tuning the performance of some
> workloads.
> 
> Add support for writing the raw energy performance preference value
> to the sysfs file.  If the last value written was an integer then
> an integer will be returned.  If the last value written was a string
> then a string will be returned.


Support for raw EPP values was present in the previous patch
itself. It appears that some hunks from the previous patch belong
here.


> 
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
>  Documentation/admin-guide/pm/amd-pstate.rst | 16 +++++++++++-----
>  drivers/cpufreq/amd-pstate.c                | 11 +++++++++--
>  drivers/cpufreq/amd-pstate.h                |  1 +
>  3 files changed, 21 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
> index a6745f2358e61..674e76ff9293e 100644
> --- a/Documentation/admin-guide/pm/amd-pstate.rst
> +++ b/Documentation/admin-guide/pm/amd-pstate.rst
> @@ -280,16 +280,22 @@ A list of all the supported EPP preferences that could be used for
>  These profiles represent different hints that are provided
>  to the low-level firmware about the user's desired energy vs efficiency
>  tradeoff.  ``default`` represents the epp value is set by platform
> -firmware. This attribute is read-only.
> +firmware. ``custom`` designates that integer values 0-255 may be written
> +as well.  This attribute is read-only.
>  
>  ``energy_performance_preference``
>  
>  The current energy performance preference can be read from this attribute.
>  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, but if the dynamic EPP feature is enabled, driver will block writes.
> +Coarse named profiles are available in the attribute
> +``energy_performance_available_preferences``.
> +Users can also write individual integer values between 0 to 255.
> +When EPP feature is enabled by platform firmware but if the dynamic EPP feature is
> +enabled, driver will ignore the written value. Lower epp values shift the bias
> +towards improved performance while a higher epp value shifts the bias towards
> +power-savings. The exact impact can change from one platform to the other.
> +If a valid integer was last written, then a number will be returned on future reads.
> +If a valid string was last written then a string will be returned on future reads.
>  This attribute is read-write.
>  
>  ``boost``
> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
> index e1ccbbdd56d42..14347baf3cefb 100644
> --- a/drivers/cpufreq/amd-pstate.c
> +++ b/drivers/cpufreq/amd-pstate.c
> @@ -1333,6 +1333,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
>  {
>  	struct amd_cpudata *cpudata = policy->driver_data;
>  	ssize_t ret;
> +	bool raw_epp = FALSE;

s/FALSE/false ?

false is already defined in <linux/types.h> and rest of the file uses
it.



>  	u8 epp;
>  
>  	if (cpudata->dynamic_epp) {
> @@ -1345,6 +1346,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
>  	 * matches an index in the energy_perf_strings array
>  	 */
>  	ret = kstrtou8(buf, 0, &epp);
> +	raw_epp = !ret;
>  	if (ret) {
>  		ret = sysfs_match_string(energy_perf_strings, buf);
>  		if (ret < 0 || ret == EPP_INDEX_CUSTOM)
> @@ -1364,7 +1366,9 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
>  	if (ret)
>  		return ret;
>  
> -	return ret ? ret : count;
> +	cpudata->raw_epp = raw_epp;
> +
> +	return count;
>  }
>  EXPORT_SYMBOL_GPL(store_energy_performance_preference);
>  
> @@ -1375,6 +1379,9 @@ 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)
> +		return sysfs_emit(buf, "%u\n", epp);
> +
>  	switch (epp) {
>  	case AMD_CPPC_EPP_PERFORMANCE:
>  		preference = EPP_INDEX_PERFORMANCE;
> @@ -1389,7 +1396,7 @@ ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *
>  		preference = EPP_INDEX_POWERSAVE;
>  		break;
>  	default:
> -		return sysfs_emit(buf, "%u\n", epp);
> +		return -EINVAL;
>  	}
>  
>  	return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
> diff --git a/drivers/cpufreq/amd-pstate.h b/drivers/cpufreq/amd-pstate.h
> index 9839c7c6558f4..38b575b8ad959 100644
> --- a/drivers/cpufreq/amd-pstate.h
> +++ b/drivers/cpufreq/amd-pstate.h
> @@ -110,6 +110,7 @@ struct amd_cpudata {
>  	u8	epp_default_ac;
>  	u8	epp_default_dc;
>  	bool	dynamic_epp;
> +	bool	raw_epp;
>  	struct notifier_block power_nb;

Looks good otherwise.

-- 
Thanks and Regards
gautham.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v5 5/5] cpufreq/amd-pstate-ut: Add a unit test for raw EPP
  2026-01-06  5:14 ` [PATCH v5 5/5] cpufreq/amd-pstate-ut: Add a unit test for raw EPP Mario Limonciello (AMD)
@ 2026-03-27  8:59   ` Gautham R. Shenoy
  0 siblings, 0 replies; 11+ messages in thread
From: Gautham R. Shenoy @ 2026-03-27  8:59 UTC (permalink / raw)
  To: Mario Limonciello
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Mario Limonciello

Hello Mario,

On Mon, Jan 05, 2026 at 11:14:41PM -0600, Mario Limonciello wrote:
> From: Mario Limonciello <mario.limonciello@amd.com>
> 
> Ensure that all supported raw EPP values work properly.
> 
> Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
>  drivers/cpufreq/amd-pstate-ut.c | 58 +++++++++++++++++++++++++++++++++
>  1 file changed, 58 insertions(+)
> 
> diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c
> index 447b9aa5ce40b..d51233b753db6 100644
> --- a/drivers/cpufreq/amd-pstate-ut.c
> +++ b/drivers/cpufreq/amd-pstate-ut.c
> @@ -26,6 +26,7 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/moduleparam.h>
> +#include <linux/mm.h>
>  #include <linux/fs.h>
>  #include <linux/cleanup.h>
>  
> @@ -35,6 +36,7 @@
>  
>  #include "amd-pstate.h"
>  
> +DEFINE_FREE(cleanup_page, void *, if (_T) free_page((unsigned long)_T))
>  
>  struct amd_pstate_ut_struct {
>  	const char *name;
> @@ -48,6 +50,7 @@ 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_epp(u32 index);
>  static int amd_pstate_ut_check_driver(u32 index);
>  
>  static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
> @@ -55,6 +58,7 @@ static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
>  	{"amd_pstate_ut_check_enabled",    amd_pstate_ut_check_enabled    },
>  	{"amd_pstate_ut_check_perf",       amd_pstate_ut_check_perf       },
>  	{"amd_pstate_ut_check_freq",       amd_pstate_ut_check_freq       },
> +	{"amd_pstate_ut_epp",              amd_pstate_ut_epp              },
>  	{"amd_pstate_ut_check_driver",	   amd_pstate_ut_check_driver     }
>  };
>  
> @@ -241,6 +245,60 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
>  	return amd_pstate_update_status(mode_str, strlen(mode_str));
>  }
>  
> +static int amd_pstate_ut_epp(u32 index)
> +{
> +	struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
> +	void *buf __free(cleanup_page) = NULL;
> +	struct amd_cpudata *cpudata;
> +	int ret, cpu = 0;
> +	u16 epp;
> +
> +	policy = cpufreq_cpu_get(cpu);
> +	if (!policy)
> +		return -ENODEV;
> +
> +	cpudata = policy->driver_data;
> +
> +	/* disable dynamic EPP before running test */
> +	if (cpudata->dynamic_epp) {
> +		pr_debug("Dynamic EPP is enabled, disabling it\n");
> +		amd_pstate_clear_dynamic_epp(policy);
> +	}
> +
> +	buf = (void *)__get_free_page(GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE);
> +	if (ret)
> +		return ret;
> +
> +	for (epp = 0; epp <= U8_MAX; epp++) {
> +		u8 val;
> +
> +		/* write all EPP values */
> +		memset(buf, 0, sizeof(*buf));
> +		snprintf(buf, PAGE_SIZE, "%d", epp);
> +		ret = store_energy_performance_preference(policy, buf, sizeof(*buf));
> +		if (ret < 0)
> +			return ret;
> +
> +		/* check if the EPP value reads back correctly for raw numbers */
> +		memset(buf, 0, sizeof(*buf));
> +		ret = show_energy_performance_preference(policy, buf);
> +		if (ret < 0)
> +			return ret;
> +		strreplace(buf, '\n', '\0');
> +		ret = kstrtou8(buf, 0, &val);
> +		if (!ret && epp != val) {
> +			pr_err("Raw EPP value mismatch: %d != %d\n", epp, val);
> +			return -EINVAL;
> +		}

The loop validates that writing a raw integer reads back as an
integer, but the commit message for Patch 4 ("Add support for raw
EPP writes") promises:

    "If the last value written was an integer then an integer will
     be returned.  If the last value written was a string then a
     string will be returned."

The string-to-string direction is not tested.  After the raw integer
loop, raw_epp is left as true.  Writing "performance" should flip
raw_epp to false and reading back should return the string
"performance", not the integer "0".  The same applies to
"balance_performance", "balance_power", and "power".

This would also exercise the transition from raw_epp=true to
raw_epp=false, which is where a regression would most likely appear.

> +	}

Also, the test forces AMD_PSTATE_ACTIVE mode here but never saves or
restores the original mode.  It also disables dynamic EPP above
without re-enabling it.

Shouldn't amd_pstate_ut_epp() save the mode and dynamic_epp state at
the start and restore both before returning like the other tests, for
e.g., amd_pstate_ut_check_driver() do?

> +
> +	return 0;
> +}
> +
>  static int amd_pstate_ut_check_driver(u32 index)
>  {
>  	enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
> 
> -- 
> 2.43.0
> 

-- 
Thanks and Regards
gautham.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-03-27  8:59 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-06  5:14 [PATCH v5 0/5] amd-pstate Dynamic EPP and raw EPP Mario Limonciello (AMD)
2026-01-06  5:14 ` [PATCH v5 1/5] cpufreq/amd-pstate: Add dynamic energy performance preference Mario Limonciello (AMD)
2026-03-27  6:43   ` Gautham R. Shenoy
2026-01-06  5:14 ` [PATCH v5 2/5] cpufreq/amd-pstate: add kernel command line to override dynamic epp Mario Limonciello (AMD)
2026-03-27  6:45   ` Gautham R. Shenoy
2026-01-06  5:14 ` [PATCH v5 3/5] cpufreq/amd-pstate: Add support for platform profile class Mario Limonciello (AMD)
2026-03-27  6:58   ` Gautham R. Shenoy
2026-01-06  5:14 ` [PATCH v5 4/5] cpufreq/amd-pstate: Add support for raw EPP writes Mario Limonciello (AMD)
2026-03-27  8:41   ` Gautham R. Shenoy
2026-01-06  5:14 ` [PATCH v5 5/5] cpufreq/amd-pstate-ut: Add a unit test for raw EPP Mario Limonciello (AMD)
2026-03-27  8:59   ` Gautham R. Shenoy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox