Linux Power Management development
 help / color / mirror / Atom feed
* [PATCH 0/2] Add support for Zen 6 client EPP tunings
@ 2026-08-31  5:46 Mario Limonciello (AMD)
  2026-08-31  5:46 ` [PATCH 1/2] cpufreq/amd-pstate: Add per SoC and per core type EPP tuning values Mario Limonciello (AMD)
  2026-08-31  5:46 ` [PATCH 2/2] cpufreq/amd-pstate: Add EPP tunings for Zen6 client platforms Mario Limonciello (AMD)
  0 siblings, 2 replies; 3+ messages in thread
From: Mario Limonciello (AMD) @ 2026-08-31  5:46 UTC (permalink / raw)
  To: K Prateek Nayak
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Vishal Badole,
	Richard Gong, Mario Limonciello

From: Mario Limonciello <superm1@kernel.org>

Zen6 client platform firmware uses EPP values differently than previous
platforms. To optimize performance and power consumption tunings are
applied that match platform characteristics.

Mario Limonciello (AMD) (2):
  cpufreq/amd-pstate: Add per SoC and per core type EPP tuning values
  cpufreq/amd-pstate: Add EPP tunings for Zen6 client platforms

 drivers/cpufreq/amd-pstate.c | 223 +++++++++++++++++++++++++++++------
 1 file changed, 186 insertions(+), 37 deletions(-)

-- 
2.53.0


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

* [PATCH 1/2] cpufreq/amd-pstate: Add per SoC and per core type EPP tuning values
  2026-08-31  5:46 [PATCH 0/2] Add support for Zen 6 client EPP tunings Mario Limonciello (AMD)
@ 2026-08-31  5:46 ` Mario Limonciello (AMD)
  2026-08-31  5:46 ` [PATCH 2/2] cpufreq/amd-pstate: Add EPP tunings for Zen6 client platforms Mario Limonciello (AMD)
  1 sibling, 0 replies; 3+ messages in thread
From: Mario Limonciello (AMD) @ 2026-08-31  5:46 UTC (permalink / raw)
  To: K Prateek Nayak
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Vishal Badole,
	Richard Gong, Mario Limonciello (AMD)

On newer SoCs the behavior of the platform has changed, and using
the same EPP values for everything will yield worse results than expected.

Add a x86_cpu_id match table that allows setting policies on a
per-SoC/per-core type basis.  If a SoC is missing, fallback to legacy
values that are used.

Changes also:
- Change epp_values array and amd_pstate_cpu_epp_values() from unsigned
  int to u8
- Add static_assert to ensure epp_values has rows for all CPU types
- Fix show_energy_performance_preference() loop to exclude uninitialized
  EPP_INDEX_CUSTOM and EPP_INDEX_DYNAMIC slots
- Add debug print statements
- Remove amd_pstate_get_epp_from_platform_profile and inline the logic
- Fix cleanup path in amd_pstate_set_dynamic_epp
- Change show_energy_performance_preference to use for loop with preference
  tracking
- Add debug prints in amd_pstate_init_epp_values

Behavioral change: show_energy_performance_preference() now returns a
numeric EPP value via sysfs when the cached EPP does not match any named
preference, instead of returning -EINVAL as before. This provides
visibility into custom EPP values set by hardware or BIOS.

No new platforms are added in this commit.

Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
---
 drivers/cpufreq/amd-pstate.c | 197 ++++++++++++++++++++++++++++-------
 1 file changed, 160 insertions(+), 37 deletions(-)

diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index d4ff8b228f86f..efac68f5e7658 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -55,10 +55,10 @@
 #define AMD_PSTATE_TRANSITION_DELAY	1000
 #define AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY 600
 
-#define AMD_CPPC_EPP_PERFORMANCE		0x00
-#define AMD_CPPC_EPP_BALANCE_PERFORMANCE	0x80
-#define AMD_CPPC_EPP_BALANCE_POWERSAVE		0xBF
-#define AMD_CPPC_EPP_POWERSAVE			0xFF
+#define AMD_CPPC_EPP_LEGACY_PERFORMANCE			0x00
+#define AMD_CPPC_EPP_LEGACY_BALANCE_PERFORMANCE		0x80
+#define AMD_CPPC_EPP_LEGACY_BALANCE_POWERSAVE		0xBF
+#define AMD_CPPC_EPP_LEGACY_POWERSAVE			0xFF
 
 static const char * const amd_pstate_mode_string[] = {
 	[AMD_PSTATE_UNDEFINED]   = "undefined",
@@ -129,14 +129,102 @@ static const char * const energy_perf_strings[] = {
 };
 static_assert(ARRAY_SIZE(energy_perf_strings) == EPP_INDEX_MAX);
 
-static unsigned int epp_values[] = {
-	[EPP_INDEX_DEFAULT] = 0,
-	[EPP_INDEX_PERFORMANCE] = AMD_CPPC_EPP_PERFORMANCE,
-	[EPP_INDEX_BALANCE_PERFORMANCE] = AMD_CPPC_EPP_BALANCE_PERFORMANCE,
-	[EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_BALANCE_POWERSAVE,
-	[EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_POWERSAVE,
+/*
+ * The numeric EPP value programmed for each named preference. First dimension
+ * is CPU type (TOPO_CPU_TYPE_ANY for non-hybrid, TOPO_CPU_TYPE_PERFORMANCE/
+ * EFFICIENCY/LOW_POWER for hybrid). The initializer holds the legacy values
+ * used as the fallback on any platform not listed in amd_pstate_epp_soc_ids[];
+ * amd_pstate_init_epp_values() overwrites slots at boot when the running SoC
+ * has a per-SoC (and potentially per-CPU-type) override.
+ */
+static u8 epp_values[][EPP_INDEX_MAX] = {
+	[TOPO_CPU_TYPE_ANY] = {
+		[EPP_INDEX_DEFAULT] = 0,
+		[EPP_INDEX_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_PERFORMANCE,
+		[EPP_INDEX_BALANCE_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_BALANCE_PERFORMANCE,
+		[EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_LEGACY_BALANCE_POWERSAVE,
+		[EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_LEGACY_POWERSAVE,
+	},
+	[TOPO_CPU_TYPE_PERFORMANCE] = {
+		[EPP_INDEX_DEFAULT] = 0,
+		[EPP_INDEX_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_PERFORMANCE,
+		[EPP_INDEX_BALANCE_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_BALANCE_PERFORMANCE,
+		[EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_LEGACY_BALANCE_POWERSAVE,
+		[EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_LEGACY_POWERSAVE,
+	},
+	[TOPO_CPU_TYPE_EFFICIENCY] = {
+		[EPP_INDEX_DEFAULT] = 0,
+		[EPP_INDEX_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_PERFORMANCE,
+		[EPP_INDEX_BALANCE_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_BALANCE_PERFORMANCE,
+		[EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_LEGACY_BALANCE_POWERSAVE,
+		[EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_LEGACY_POWERSAVE,
+	},
+	[TOPO_CPU_TYPE_LOW_POWER] = {
+		[EPP_INDEX_DEFAULT] = 0,
+		[EPP_INDEX_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_PERFORMANCE,
+		[EPP_INDEX_BALANCE_PERFORMANCE] = AMD_CPPC_EPP_LEGACY_BALANCE_PERFORMANCE,
+		[EPP_INDEX_BALANCE_POWERSAVE] = AMD_CPPC_EPP_LEGACY_BALANCE_POWERSAVE,
+		[EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_LEGACY_POWERSAVE,
+	},
+};
+static_assert(ARRAY_SIZE(epp_values) == TOPO_CPU_TYPE_LOW_POWER + 1,
+	      "epp_values must have entries for all CPU types up to TOPO_CPU_TYPE_LOW_POWER");
+
+/*
+ * Get the EPP value row for a given CPU, accounting for hybrid CPU types.
+ * Non-hybrid systems use TOPO_CPU_TYPE_ANY; hybrid systems use the CPU's
+ * actual type (PERFORMANCE/EFFICIENCY/LOW_POWER).
+ */
+static inline u8 *amd_pstate_cpu_epp_values(int cpu)
+{
+	enum x86_topology_cpu_type type = cpu_data(cpu).topo.cpu_type;
+
+	if (type == TOPO_CPU_TYPE_PERFORMANCE ||
+	    type == TOPO_CPU_TYPE_EFFICIENCY ||
+	    type == TOPO_CPU_TYPE_LOW_POWER)
+		return epp_values[type];
+
+	return epp_values[TOPO_CPU_TYPE_ANY];
+}
+
+/**
+ * struct amd_pstate_epp_values - EPP values for the four named preferences
+ * @performance:	value for the "performance" preference
+ * @balance_performance: value for the "balance_performance" preference
+ * @balance_power:	value for the "balance_power" preference
+ * @power:		value for the "power" preference
+ */
+struct amd_pstate_epp_values {
+	u8 performance;
+	u8 balance_performance;
+	u8 balance_power;
+	u8 power;
+};
+
+/**
+ * struct amd_pstate_epp_soc - per-CPU-type EPP overrides for hybrid systems
+ * @performance_core:	values for TOPO_CPU_TYPE_PERFORMANCE cores
+ * @efficiency_core:	values for TOPO_CPU_TYPE_EFFICIENCY cores
+ * @low_power_core:	values for TOPO_CPU_TYPE_LOW_POWER cores
+ *
+ * Referenced from amd_pstate_epp_soc_ids[] to give a hybrid platform its own
+ * numeric EPP values for the four named preferences, with distinct values per
+ * CPU type. Non-hybrid systems are not listed in the table and always use the
+ * legacy defaults.
+ */
+struct amd_pstate_epp_soc {
+	struct amd_pstate_epp_values performance_core;
+	struct amd_pstate_epp_values efficiency_core;
+	struct amd_pstate_epp_values low_power_core;
+};
+
+/*
+ * Per-CPU-type EPP overrides for hybrid systems. Only hybrid SoCs should be
+ * listed here; non-hybrid systems always use the legacy defaults.
+ */
+static const struct x86_cpu_id amd_pstate_epp_soc_ids[] __initconst = {
+	{}
 };
-static_assert(ARRAY_SIZE(epp_values) == EPP_INDEX_MAX - 2);
 
 typedef int (*cppc_mode_transition_fn)(int);
 
@@ -1195,13 +1283,16 @@ static int amd_pstate_power_supply_notifier(struct notifier_block *nb,
 static int amd_pstate_get_epp_from_platform_profile(struct cpufreq_policy *policy,
 						    enum platform_profile_option profile)
 {
+	struct amd_cpudata *cpudata = policy->driver_data;
+	u8 *values = amd_pstate_cpu_epp_values(cpudata->cpu);
+
 	switch (profile) {
 	case PLATFORM_PROFILE_PERFORMANCE:
-		return AMD_CPPC_EPP_PERFORMANCE;
+		return values[EPP_INDEX_PERFORMANCE];
 	case PLATFORM_PROFILE_BALANCED:
 		return amd_pstate_get_balanced_epp(policy);
 	case PLATFORM_PROFILE_LOW_POWER:
-		return AMD_CPPC_EPP_POWERSAVE;
+		return values[EPP_INDEX_POWERSAVE];
 	default:
 		break;
 	}
@@ -1411,6 +1502,7 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
 				    const char *buf, size_t count)
 {
 	struct amd_cpudata *cpudata = policy->driver_data;
+	u8 *values = amd_pstate_cpu_epp_values(policy->cpu);
 	ssize_t ret;
 	bool raw_epp = false;
 	u8 epp;
@@ -1445,12 +1537,13 @@ ssize_t store_energy_performance_preference(struct cpufreq_policy *policy,
 		}
 
 		if (ret)
-			epp = epp_values[ret];
+			epp = values[ret];
 		else
 			epp = cpudata->epp_default_dc;
 	}
 
-	if (epp > 0 && cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
+	if (epp > 0 && epp != values[EPP_INDEX_PERFORMANCE] &&
+	    cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) {
 		pr_debug("EPP cannot be set under performance policy\n");
 		return -EBUSY;
 	}
@@ -1475,34 +1568,31 @@ EXPORT_SYMBOL_FOR_PSTATE_UT(store_energy_performance_preference);
 ssize_t show_energy_performance_preference(struct cpufreq_policy *policy, char *buf)
 {
 	struct amd_cpudata *cpudata = policy->driver_data;
-	u8 preference, epp;
+	u8 *values = amd_pstate_cpu_epp_values(policy->cpu);
+	u8 epp;
+	int i;
 
 	epp = FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached);
 
 	if (!cpudata->dynamic_epp && cpudata->raw_epp)
 		return sysfs_emit(buf, "%u\n", epp);
 
-	switch (epp) {
-	case AMD_CPPC_EPP_PERFORMANCE:
-		preference = EPP_INDEX_PERFORMANCE;
-		break;
-	case AMD_CPPC_EPP_BALANCE_PERFORMANCE:
-		preference = EPP_INDEX_BALANCE_PERFORMANCE;
-		break;
-	case AMD_CPPC_EPP_BALANCE_POWERSAVE:
-		preference = EPP_INDEX_BALANCE_POWERSAVE;
-		break;
-	case AMD_CPPC_EPP_POWERSAVE:
-		preference = EPP_INDEX_POWERSAVE;
-		break;
-	default:
-		return -EINVAL;
-	}
+	/*
+	 * Map the cached EPP value back to a named preference. Skip the
+	 * "default" slot (index 0) so an EPP of 0 reports as "performance".
+	 * Stop at POWERSAVE; CUSTOM and DYNAMIC are not initialized in epp_values.
+	 */
+	for (i = EPP_INDEX_PERFORMANCE; i <= EPP_INDEX_POWERSAVE; i++) {
+		const char *name = energy_perf_strings[i];
 
-	if (cpudata->dynamic_epp)
-		return sysfs_emit(buf, "dynamic(profile:%s)\n", energy_perf_strings[preference]);
+		if (epp == values[i]) {
+			if (cpudata->dynamic_epp)
+				return sysfs_emit(buf, "dynamic(profile:%s)\n", name);
+			return sysfs_emit(buf, "%s\n", name);
+		}
+	}
 
-	return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
+	return sysfs_emit(buf, "%u\n", epp);
 }
 EXPORT_SYMBOL_FOR_PSTATE_UT(show_energy_performance_preference);
 
@@ -1944,9 +2034,11 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
 		cpudata->epp_default_ac = cpudata->epp_default_dc = default_epp;
 		cpudata->current_profile = PLATFORM_PROFILE_PERFORMANCE;
 	} else {
+		u8 *values = amd_pstate_cpu_epp_values(policy->cpu);
+
 		policy->policy = CPUFREQ_POLICY_POWERSAVE;
-		cpudata->epp_default_ac = AMD_CPPC_EPP_PERFORMANCE;
-		cpudata->epp_default_dc = AMD_CPPC_EPP_BALANCE_PERFORMANCE;
+		cpudata->epp_default_ac = values[EPP_INDEX_PERFORMANCE];
+		cpudata->epp_default_dc = values[EPP_INDEX_BALANCE_PERFORMANCE];
 		cpudata->current_profile = PLATFORM_PROFILE_BALANCED;
 	}
 
@@ -2245,6 +2337,34 @@ static bool amd_cppc_supported(void)
 	return true;
 }
 
+/*
+ * Resolve the numeric EPP values for hybrid systems. Only hybrid SoCs are listed
+ * in amd_pstate_epp_soc_ids[]; non-hybrid systems always use the legacy defaults.
+ */
+static inline void __init amd_pstate_set_epp_values(enum x86_topology_cpu_type type,
+						    const struct amd_pstate_epp_values *core)
+{
+	epp_values[type][EPP_INDEX_PERFORMANCE] = core->performance;
+	epp_values[type][EPP_INDEX_BALANCE_PERFORMANCE] = core->balance_performance;
+	epp_values[type][EPP_INDEX_BALANCE_POWERSAVE] = core->balance_power;
+	epp_values[type][EPP_INDEX_POWERSAVE] = core->power;
+}
+
+static void __init amd_pstate_init_epp_values(void)
+{
+	const struct x86_cpu_id *id = x86_match_cpu(amd_pstate_epp_soc_ids);
+	const struct amd_pstate_epp_soc *soc;
+
+	if (!id || !id->driver_data)
+		return;
+
+	soc = (const struct amd_pstate_epp_soc *)id->driver_data;
+
+	amd_pstate_set_epp_values(TOPO_CPU_TYPE_PERFORMANCE, &soc->performance_core);
+	amd_pstate_set_epp_values(TOPO_CPU_TYPE_EFFICIENCY, &soc->efficiency_core);
+	amd_pstate_set_epp_values(TOPO_CPU_TYPE_LOW_POWER, &soc->low_power_core);
+}
+
 static int __init amd_pstate_init(void)
 {
 	struct device *dev_root;
@@ -2272,6 +2392,9 @@ static int __init amd_pstate_init(void)
 	/* check if this machine need CPPC quirks */
 	dmi_check_system(amd_pstate_quirks_table);
 
+	/* resolve per-SoC EPP values for the named preferences */
+	amd_pstate_init_epp_values();
+
 	/*
 	* determine the driver mode from the command line or kernel config.
 	* If no command line input is provided, cppc_state will be AMD_PSTATE_UNDEFINED.
-- 
2.53.0


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

* [PATCH 2/2] cpufreq/amd-pstate: Add EPP tunings for Zen6 client platforms
  2026-08-31  5:46 [PATCH 0/2] Add support for Zen 6 client EPP tunings Mario Limonciello (AMD)
  2026-08-31  5:46 ` [PATCH 1/2] cpufreq/amd-pstate: Add per SoC and per core type EPP tuning values Mario Limonciello (AMD)
@ 2026-08-31  5:46 ` Mario Limonciello (AMD)
  1 sibling, 0 replies; 3+ messages in thread
From: Mario Limonciello (AMD) @ 2026-08-31  5:46 UTC (permalink / raw)
  To: K Prateek Nayak
  Cc: Perry Yuan, open list:X86 ARCHITECTURE (32-BIT AND 64-BIT),
	open list:CPU FREQUENCY SCALING FRAMEWORK, Vishal Badole,
	Richard Gong, Mario Limonciello (AMD)

Zen6 client platforms perform better with individual tunings for
different core types.  Add initial EPP tuning values for those
platforms.

Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
---
 drivers/cpufreq/amd-pstate.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index efac68f5e7658..d2b4a8eba3052 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -222,7 +222,33 @@ struct amd_pstate_epp_soc {
  * Per-CPU-type EPP overrides for hybrid systems. Only hybrid SoCs should be
  * listed here; non-hybrid systems always use the legacy defaults.
  */
+static const struct amd_pstate_epp_soc epp_soc_zen6_client __initconst = {
+	.performance_core = {
+		.performance		= 25,
+		.balance_performance	= 51,
+		.balance_power		= 64,
+		.power			= 64,
+	},
+	.efficiency_core = {
+		.performance		= 25,
+		.balance_performance	= 51,
+		.balance_power		= 64,
+		.power			= 115,
+	},
+	.low_power_core = {
+		.performance		= 25,
+		.balance_performance	= 51,
+		.balance_power		= 64,
+		.power			= 115,
+	},
+};
+
 static const struct x86_cpu_id amd_pstate_epp_soc_ids[] __initconst = {
+	X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x1A, 0x80, &epp_soc_zen6_client),
+	X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x1A, 0x81, &epp_soc_zen6_client),
+	X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x1A, 0x84, &epp_soc_zen6_client),
+	X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x1A, 0x85, &epp_soc_zen6_client),
+	X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x1A, 0xe0, &epp_soc_zen6_client),
 	{}
 };
 
-- 
2.53.0


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

end of thread, other threads:[~2026-08-31  5:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-31  5:46 [PATCH 0/2] Add support for Zen 6 client EPP tunings Mario Limonciello (AMD)
2026-08-31  5:46 ` [PATCH 1/2] cpufreq/amd-pstate: Add per SoC and per core type EPP tuning values Mario Limonciello (AMD)
2026-08-31  5:46 ` [PATCH 2/2] cpufreq/amd-pstate: Add EPP tunings for Zen6 client platforms Mario Limonciello (AMD)

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