public inbox for linux-pm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] intel_idle: Drop C-states redundant when PC6 is disabled
@ 2026-04-25  7:25 Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH 1/3] intel_idle: Add constants for MSR_PKG_CST_CONFIG_CONTROL Artem Bityutskiy
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Artem Bityutskiy @ 2026-04-25  7:25 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM Mailing List

From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

This patch series drops redundant requestable C-states when PC6 is disabled in
BIOS. For example, Granite Rapids Xeon has two C6 flavors: C6 and C6P. C6
allows only core C6 (CC6), while C6P allows both CC6 and package C6 (PC6).
When PC6 is disabled, C6P becomes identical to C6 and is therefore redundant.
Refer to patch 3 for the full rationale and details.

Patches 1 and 2 prepare the code for patch 3. They introduce no functional
changes, only restructure it to improve readability and maintainability.

For more information about Granite Rapids C6 vs C6P, refer to this article:
https://github.com/intel/pepc/blob/main/docs/misc-c6p-c6sp.md

Thanks, Artem.

Artem Bityutskiy (3):
  intel_idle: Add constants for MSR_PKG_CST_CONFIG_CONTROL
  intel_idle: Introduce a helper for checking PC6
  intel_idle: Drop C-states redundant when PC6 is disabled

 drivers/idle/intel_idle.c | 104 +++++++++++++++++++++++++++++---------
 1 file changed, 81 insertions(+), 23 deletions(-)

-- 
2.53.0


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

* [PATCH 1/3] intel_idle: Add constants for MSR_PKG_CST_CONFIG_CONTROL
  2026-04-25  7:25 [PATCH 0/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy
@ 2026-04-25  7:25 ` Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH] intel_idle: Add Panther Lake C-states table Artem Bityutskiy
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Artem Bityutskiy @ 2026-04-25  7:25 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM Mailing List

From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

Add two constants for the package C-state limit fields in
MSR_PKG_CST_CONFIG_CONTROL.

The SKX_ prefix stands for "Skylake Xeon" and makes it explicit that
the mask is CPU model-specific. The same values have applied to all
Xeon platforms starting from SKX.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
 drivers/idle/intel_idle.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index f49c939d636f4..49894c6c7f20b 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -81,6 +81,11 @@ static bool ibrs_off __read_mostly;
 /* Maximum allowed C-state target residency */
 #define MAX_CMDLINE_RESIDENCY_US (100 * USEC_PER_MSEC)
 
+/* The Package C-State Limit bits in MSR_PKG_CST_CONFIG_CONTROL */
+#define SKX_PKG_CST_LIMIT_MASK GENMASK(2, 0)
+/* PC6 is enabled when Package C-State Limit >= this value */
+#define SKX_PKG_CST_LIMIT_PC6 2
+
 static char cmdline_table_str[MAX_CMDLINE_TABLE_LEN] __read_mostly;
 
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
@@ -2048,7 +2053,7 @@ static void __init skx_idle_state_table_update(void)
 	 * 011b: C6 (retention)
 	 * 111b: No Package C state limits.
 	 */
-	if ((msr & 0x7) < 2) {
+	if ((msr & SKX_PKG_CST_LIMIT_MASK) < SKX_PKG_CST_LIMIT_PC6) {
 		/*
 		 * Uses the CC6 + PC0 latency and 3 times of
 		 * latency for target_residency if the PC6
@@ -2076,7 +2081,7 @@ static void __init spr_idle_state_table_update(void)
 	rdmsrq(MSR_PKG_CST_CONFIG_CONTROL, msr);
 
 	/* Limit value 2 and above allow for PC6. */
-	if ((msr & 0x7) < 2) {
+	if ((msr & SKX_PKG_CST_LIMIT_MASK) < SKX_PKG_CST_LIMIT_PC6) {
 		spr_cstates[2].exit_latency = 190;
 		spr_cstates[2].target_residency = 600;
 	}
-- 
2.53.0


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

* [PATCH] intel_idle: Add Panther Lake C-states table
  2026-04-25  7:25 [PATCH 0/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH 1/3] intel_idle: Add constants for MSR_PKG_CST_CONFIG_CONTROL Artem Bityutskiy
@ 2026-04-25  7:25 ` Artem Bityutskiy
  2026-04-25  7:27   ` Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH 2/3] intel_idle: Introduce a helper for checking PC6 Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH 3/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy
  3 siblings, 1 reply; 6+ messages in thread
From: Artem Bityutskiy @ 2026-04-25  7:25 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM Mailing List

From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

Panther Lake supports the following requestable C-states: C1, C1E, C6S, C10.
Add a custom table for them.

Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
 drivers/idle/intel_idle.c | 42 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

Based on latency analysis using the 'wult' tool, and power break even
analysis using the 'pbe' tool.

diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 167eb72105baf..36f5766381172 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -994,6 +994,43 @@ static struct cpuidle_state mtl_l_cstates[] __initdata = {
 		.enter = NULL }
 };
 
+static struct cpuidle_state ptl_cstates[] __initdata = {
+	{
+		.name = "C1",
+		.desc = "MWAIT 0x00",
+		.flags = MWAIT2flg(0x00),
+		.exit_latency = 1,
+		.target_residency = 1,
+		.enter = &intel_idle,
+		.enter_s2idle = intel_idle_s2idle, },
+	{
+		.name = "C1E",
+		.desc = "MWAIT 0x01",
+		.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE,
+		.exit_latency = 10,
+		.target_residency = 10,
+		.enter = &intel_idle,
+		.enter_s2idle = intel_idle_s2idle, },
+	{
+		.name = "C6S",
+		.desc = "MWAIT 0x21",
+		.flags = MWAIT2flg(0x21) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 300,
+		.target_residency = 300,
+		.enter = &intel_idle,
+		.enter_s2idle = intel_idle_s2idle, },
+	{
+		.name = "C10",
+		.desc = "MWAIT 0x60",
+		.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
+		.exit_latency = 370,
+		.target_residency = 2500,
+		.enter = &intel_idle,
+		.enter_s2idle = intel_idle_s2idle, },
+	{
+		.enter = NULL }
+};
+
 static struct cpuidle_state gmt_cstates[] __initdata = {
 	{
 		.name = "C1",
@@ -1623,6 +1660,10 @@ static const struct idle_cpu idle_cpu_mtl_l __initconst = {
 	.state_table = mtl_l_cstates,
 };
 
+static const struct idle_cpu idle_cpu_ptl __initconst = {
+	.state_table = ptl_cstates,
+};
+
 static const struct idle_cpu idle_cpu_gmt __initconst = {
 	.state_table = gmt_cstates,
 };
@@ -1737,6 +1778,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {
 	X86_MATCH_VFM(INTEL_ALDERLAKE,		&idle_cpu_adl),
 	X86_MATCH_VFM(INTEL_ALDERLAKE_L,	&idle_cpu_adl_l),
 	X86_MATCH_VFM(INTEL_METEORLAKE_L,	&idle_cpu_mtl_l),
+	X86_MATCH_VFM(INTEL_PANTHERLAKE_L,	&idle_cpu_ptl),
 	X86_MATCH_VFM(INTEL_ATOM_GRACEMONT,	&idle_cpu_gmt),
 	X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X,	&idle_cpu_spr),
 	X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X,	&idle_cpu_spr),
-- 
2.53.0


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

* [PATCH 2/3] intel_idle: Introduce a helper for checking PC6
  2026-04-25  7:25 [PATCH 0/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH 1/3] intel_idle: Add constants for MSR_PKG_CST_CONFIG_CONTROL Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH] intel_idle: Add Panther Lake C-states table Artem Bityutskiy
@ 2026-04-25  7:25 ` Artem Bityutskiy
  2026-04-25  7:25 ` [PATCH 3/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy
  3 siblings, 0 replies; 6+ messages in thread
From: Artem Bityutskiy @ 2026-04-25  7:25 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM Mailing List

From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

Introduce the skx_is_pc6_disabled() for checking if PC6 is disabled and
switch the following functions to use it:

- skx_idle_state_table_update()
- spr_idle_state_table_update()

At the same time, clean them up improving the commentary and moving it to
the function kernel-doc.

Purely a clean up, no functional changes intended.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
 drivers/idle/intel_idle.c | 48 +++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 49894c6c7f20b..562f8e27256e7 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -2037,12 +2037,13 @@ static void __init sklh_idle_state_table_update(void)
 }
 
 /**
- * skx_idle_state_table_update - Adjust the Sky Lake/Cascade Lake
- * idle states table.
+ * skx_is_pc6_disabled() - Check if PC6 is disabled in BIOS.
+ *
+ * Return: %true if PC6 is disabled, %false otherwise.
  */
-static void __init skx_idle_state_table_update(void)
+static bool __init skx_is_pc6_disabled(void)
 {
-	unsigned long long msr;
+	u64 msr;
 
 	rdmsrq(MSR_PKG_CST_CONFIG_CONTROL, msr);
 
@@ -2053,35 +2054,34 @@ static void __init skx_idle_state_table_update(void)
 	 * 011b: C6 (retention)
 	 * 111b: No Package C state limits.
 	 */
-	if ((msr & SKX_PKG_CST_LIMIT_MASK) < SKX_PKG_CST_LIMIT_PC6) {
-		/*
-		 * Uses the CC6 + PC0 latency and 3 times of
-		 * latency for target_residency if the PC6
-		 * is disabled in BIOS. This is consistent
-		 * with how intel_idle driver uses _CST
-		 * to set the target_residency.
-		 */
+	return (msr & SKX_PKG_CST_LIMIT_MASK) < SKX_PKG_CST_LIMIT_PC6;
+}
+
+/**
+ * skx_idle_state_table_update - Adjust the SKX/CLX idle states table.
+ *
+ * Adjust Sky Lake or Cascade Lake Xeon idle states if PC6 is disabled in BIOS.
+ * Use the CC6 + PC0 latency and 3 times of that latency for target_residency.
+ * This is consistent with how the intel_idle driver uses _CST to set the
+ * target_residency.
+ */
+static void __init skx_idle_state_table_update(void)
+{
+	if (skx_is_pc6_disabled()) {
 		skx_cstates[2].exit_latency = 92;
 		skx_cstates[2].target_residency = 276;
 	}
 }
 
 /**
- * spr_idle_state_table_update - Adjust Sapphire Rapids idle states table.
+ * spr_idle_state_table_update - Adjust Sapphire Rapids Xeon idle states table.
+ *
+ * By default, the C6 state assumes the worst-case scenario of package C6.
+ * However, if PC6 is disabled in BIOS, update the numbers to match core C6.
  */
 static void __init spr_idle_state_table_update(void)
 {
-	unsigned long long msr;
-
-	/*
-	 * By default, the C6 state assumes the worst-case scenario of package
-	 * C6. However, if PC6 is disabled, we update the numbers to match
-	 * core C6.
-	 */
-	rdmsrq(MSR_PKG_CST_CONFIG_CONTROL, msr);
-
-	/* Limit value 2 and above allow for PC6. */
-	if ((msr & SKX_PKG_CST_LIMIT_MASK) < SKX_PKG_CST_LIMIT_PC6) {
+	if (skx_is_pc6_disabled()) {
 		spr_cstates[2].exit_latency = 190;
 		spr_cstates[2].target_residency = 600;
 	}
-- 
2.53.0


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

* [PATCH 3/3] intel_idle: Drop C-states redundant when PC6 is disabled
  2026-04-25  7:25 [PATCH 0/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy
                   ` (2 preceding siblings ...)
  2026-04-25  7:25 ` [PATCH 2/3] intel_idle: Introduce a helper for checking PC6 Artem Bityutskiy
@ 2026-04-25  7:25 ` Artem Bityutskiy
  3 siblings, 0 replies; 6+ messages in thread
From: Artem Bityutskiy @ 2026-04-25  7:25 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM Mailing List

From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

On modern Xeon platforms, such as Granite Rapids, Sierra Forest, and
Clearwater Forest, there are two flavors of requestable C6 states: C6
and C6P. C6 allows only core C6 (CC6), while C6P allows both CC6 and
package C6 (PC6). PC6 saves more power but also has a higher exit
latency, so many users disable it in BIOS.

When PC6 is disabled, C6P becomes identical to C6 — the CPU treats C6P
requests as C6 requests. Exposing both C6 and C6P to user space in this
situation is confusing: two states with the same name look different but
behave the same. It also adds unnecessary overhead to the cpuidle
subsystem, which is a fast path: the governor evaluates every registered
state on idle entry.

Drop C-states that are redundant when PC6 is disabled by marking them
with CPUIDLE_FLAG_UNUSABLE, which causes cpuidle to exclude them when
registering idle states.

Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
---
 drivers/idle/intel_idle.c | 53 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 562f8e27256e7..f052564eb308b 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -2087,6 +2087,53 @@ static void __init spr_idle_state_table_update(void)
 	}
 }
 
+/**
+ * drop_pc6_redundant_cstates() - Drop C-states redundant when PC6 is disabled.
+ * @states: Idle states table to modify.
+ *
+ * When PC6 is disabled in BIOS, C-states that exist solely to enable PC6
+ * entry (such as C6P or C6SP) become identical to shallower C-states like
+ * C6, and are therefore redundant. Should be called only on systems with
+ * multiple C6 flavors.
+ */
+static void __init drop_pc6_redundant_cstates(struct cpuidle_state *states)
+{
+	int count;
+
+	if (!skx_is_pc6_disabled())
+		/* PC6 is not disabled, nothing to do */
+		return;
+
+	for (count = 0; states[count].enter; count++)
+		continue;
+
+	if (count < 2) {
+		pr_debug("Too few idle states to drop PC6-redundant states\n");
+		return;
+	}
+
+	/*
+	 * Sanity check: At this point all platforms with multiple C6 flavors
+	 * use the CPUIDLE_FLAG_PARTIAL_HINT_MATCH flag. And the last state in
+	 * the table is the one that becomes redundant when PC6 is disabled.
+	 */
+	if (!(states[count - 1].flags & CPUIDLE_FLAG_PARTIAL_HINT_MATCH)) {
+		pr_debug("Can't drop PC6-redundant states: unexpected flags\n");
+		return;
+	}
+
+	/*
+	 * On all current platforms with multiple C6 flavors, there is only one
+	 * C-state that becomes redundant when PC6 is disabled. This state is
+	 * the last one in the table. Drop it by marking it with
+	 * CPUIDLE_FLAG_UNUSABLE so that cpuidle excludes it when registering
+	 * idle states.
+	 */
+	pr_info("Dropping idle state %s because PC6 is disabled\n",
+		states[count - 1].name);
+	states[count - 1].flags |= CPUIDLE_FLAG_UNUSABLE;
+}
+
 /**
  * byt_cht_auto_demotion_disable - Disable Bay/Cherry Trail auto-demotion.
  */
@@ -2176,6 +2223,12 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
 	case INTEL_ATOM_AIRMONT:
 		byt_cht_auto_demotion_disable();
 		break;
+	case INTEL_GRANITERAPIDS_D:
+	case INTEL_GRANITERAPIDS_X:
+	case INTEL_ATOM_CRESTMONT_X:
+	case INTEL_ATOM_DARKMONT_X:
+		drop_pc6_redundant_cstates(cpuidle_state_table);
+		break;
 	}
 
 	for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
-- 
2.53.0


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

* Re: [PATCH] intel_idle: Add Panther Lake C-states table
  2026-04-25  7:25 ` [PATCH] intel_idle: Add Panther Lake C-states table Artem Bityutskiy
@ 2026-04-25  7:27   ` Artem Bityutskiy
  0 siblings, 0 replies; 6+ messages in thread
From: Artem Bityutskiy @ 2026-04-25  7:27 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM Mailing List

On Sat, 2026-04-25 at 10:25 +0300, Artem Bityutskiy wrote:
> From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
> 
> Panther Lake supports the following requestable C-states: C1, C1E, C6S, C10.
> Add a custom table for them.
> 
> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
> ---
>  drivers/idle/intel_idle.c | 42 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)

Oh I apologize for sending this one, it does not belong to the series,
I did not noticed that I copied to the same directory. Please, ignore
this patch.

Artem.

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

end of thread, other threads:[~2026-04-25  7:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-25  7:25 [PATCH 0/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy
2026-04-25  7:25 ` [PATCH 1/3] intel_idle: Add constants for MSR_PKG_CST_CONFIG_CONTROL Artem Bityutskiy
2026-04-25  7:25 ` [PATCH] intel_idle: Add Panther Lake C-states table Artem Bityutskiy
2026-04-25  7:27   ` Artem Bityutskiy
2026-04-25  7:25 ` [PATCH 2/3] intel_idle: Introduce a helper for checking PC6 Artem Bityutskiy
2026-04-25  7:25 ` [PATCH 3/3] intel_idle: Drop C-states redundant when PC6 is disabled Artem Bityutskiy

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