mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
@ 2026-09-16 10:38 Sumit Gupta
  2026-09-16 10:38 ` [PATCH v5 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Sumit Gupta @ 2026-09-16 10:38 UTC (permalink / raw)
  To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
	ionela.voinescu, zhenglifeng1, zhanjie9, lenb, ray.huang,
	mario.limonciello, perry.yuan, kprateek.nayak, linux-kernel,
	linux-pm, linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg

This series keeps the CPPC cpufreq policy alive across CPU hotplug and
preserves the OSPM-set CPPC registers (Energy Performance Preference,
Autonomous Activity Window, Autonomous Selection - set via sysfs).

Without online()/offline() callbacks, the core tears a policy down when
its last CPU goes offline and rebuilds it on the way back, re-reading the
CPPC capabilities each time. The values written to these registers can
be lost:

 - Across CPU hotplug or suspend/resume: the platform may reset them
   while the CPU is offline.
 - On driver unload: the driver-written value is left in the register
   instead of returning to its pre-driver state.

Handle these with:

 - Patch 1: adds online()/offline() callbacks so the core keeps policy
   alive across CPU hotplug instead of tearing it down and rebuilding it.
 - Patch 2: makes the autonomous selection register helpers take a u64.
 - Patch 3: adds a table-driven mechanism that captures each register's
   firmware value at init(), restores it from offline(), and reapplies
   the OSPM-set value from online().
 - Patch 4: extends the same save/restore to system suspend/resume.

v4[4] -> v5:
 - Patch 1:
   - offline() stops the frequency invariance updates and online()
     restarts them, replacing the resync that raced with tick. (Sashiko)
   - reorder the functions to match cppc_cpufreq_driver. (Jie Zhan)
 - Patch 3:
   - reapply the OSPM-set registers even when the performance control
     write fails. (Sashiko)
 - Patch 4:
   - suspend() stops the frequency invariance updates too, completing the
     patch 1 change for a policy whose CPUs stay online.

Sumit Gupta (4):
  cpufreq: CPPC: Keep the policy across CPU hotplug
  ACPI: CPPC: Make autonomous selection helpers take a u64
  cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
  cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume

 drivers/acpi/cppc_acpi.c       |  20 +-
 drivers/cpufreq/amd-pstate.c   |   2 +-
 drivers/cpufreq/cppc_cpufreq.c | 378 ++++++++++++++++++++++++++++++++-
 include/acpi/cppc_acpi.h       |   8 +-
 4 files changed, 381 insertions(+), 27 deletions(-)

[1] v1: https://lore.kernel.org/lkml/20260623095403.3407436-1-sumitg@nvidia.com/
[2] v2: https://lore.kernel.org/lkml/20260716153820.2007095-1-sumitg@nvidia.com/
[3] v3: https://lore.kernel.org/lkml/20260724215937.3368276-1-sumitg@nvidia.com/
[4] v4: https://lore.kernel.org/lkml/20260806200857.601152-1-sumitg@nvidia.com/

-- 
2.34.1


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

* [PATCH v5 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug
  2026-09-16 10:38 [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
@ 2026-09-16 10:38 ` Sumit Gupta
  2026-09-16 10:38 ` [PATCH v5 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64 Sumit Gupta
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Sumit Gupta @ 2026-09-16 10:38 UTC (permalink / raw)
  To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
	ionela.voinescu, zhenglifeng1, zhanjie9, lenb, ray.huang,
	mario.limonciello, perry.yuan, kprateek.nayak, linux-kernel,
	linux-pm, linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg

Without online()/offline() callbacks, the cpufreq core calls exit() when
a policy's last online CPU goes down. That drops the driver's per-policy
data, which init() rebuilds when a CPU comes back.

Add lightweight online()/offline() callbacks so the core instead keeps
the policy live and reuses the driver's cpu_data across CPU hotplug.
init() then runs once instead of on every hotplug, making CPU hotplug
faster.

The driver can now save what the OS set in offline() and put it back in
online(). A later patch in this series uses this to preserve the OSPM-set
registers.

Move what init() and exit() did on hotplug into the new callbacks:

  - offline() requests the lowest desired performance and stops the
    frequency invariance updates, as exit() did.
  - online() re-enables CPPC and restores the performance controls, as
    the platform may have reset them. Failures are logged, not returned,
    as the core would free the policy. It also restarts the frequency
    invariance updates with a new counter snapshot, as init() did, so
    that no sample spans the offline window.

The restore in online() uses cppc_set_perf(), which writes MIN before
MAX. Each write takes effect on its own unless the registers are accessed
through PCC. If the saved MIN is above the MAX the platform currently has,
restoring it would leave MIN above MAX until the MAX write lands, so raise
MAX first.

Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 130 ++++++++++++++++++++++++++++++++-
 1 file changed, 126 insertions(+), 4 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index f767898ebfb5..37ead7f6c179 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -184,12 +184,10 @@ static void cppc_cpufreq_cpu_fie_init(struct cpufreq_policy *policy)
 }
 
 /*
- * We free all the resources on policy's removal and not on CPU removal as the
+ * We free the resources for the whole policy and not per CPU as the
  * irq-work are per-cpu and the hotplug core takes care of flushing the pending
  * irq-works (hint: smpcfd_dying_cpu()) on CPU hotplug. Even if the kthread-work
  * fires on another CPU after the concerned CPU is removed, it won't harm.
- *
- * We just need to make sure to remove them all on policy->exit().
  */
 static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
 {
@@ -199,7 +197,7 @@ static void cppc_cpufreq_cpu_fie_exit(struct cpufreq_policy *policy)
 	if (fie_disabled)
 		return;
 
-	/* policy->cpus will be empty here, use related_cpus instead */
+	/* policy->cpus excludes the offline CPUs, use related_cpus */
 	topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, policy->related_cpus);
 
 	for_each_cpu(cpu, policy->related_cpus) {
@@ -754,6 +752,128 @@ static void cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 	cppc_cpufreq_put_cpu_data(policy);
 }
 
+/*
+ * Prepare the restore in online() so that the platform never sees MIN above
+ * MAX.
+ *
+ * cppc_set_perf() writes MIN before MAX, and each write takes effect on its
+ * own unless the registers are accessed through PCC, which delivers them in
+ * one transaction. If the MIN being restored is above the MAX currently
+ * programmed, the CPU sits with MIN above MAX until the MAX write lands, so
+ * raise MAX first. Restoring a lower MAX needs no preparation. Both values
+ * come from the policy limits, which keep MIN below MAX, so the MIN written
+ * first is never above the MAX that follows it.
+ */
+static int
+cppc_cpufreq_prepare_perf_restore(unsigned int cpu,
+				  const struct cppc_perf_ctrls *target)
+{
+	struct cppc_perf_ctrls cur = {}, prep = {};
+	int ret;
+
+	ret = cppc_get_perf(cpu, &cur);
+	if (ret)
+		return ret;
+
+	if (!cur.max_perf || target->min_perf <= cur.max_perf)
+		return 0;
+
+	prep.desired_perf = target->desired_perf;
+	prep.min_perf = 0;	/* Zero leaves MIN unchanged. */
+	prep.max_perf = target->max_perf;
+
+	return cppc_set_perf(cpu, &prep);
+}
+
+/*
+ * Run when the policy's first CPU comes back online, the counterpart of
+ * offline().
+ *
+ * The platform may have disabled CPPC and reset the performance controls
+ * (desired, min and max performance) while the CPU was offline, so re-enable
+ * CPPC and reprogram them.
+ *
+ * Report failures without returning them, or the core would free the policy and
+ * leave the CPU without cpufreq. A failed write to the performance controls is
+ * not fatal, as the governor's next request programs them again. A failed CPPC
+ * enable stops the restore, as the writes that follow may not reach the
+ * platform.
+ */
+static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
+{
+	struct cppc_cpudata *cpu_data = policy->driver_data;
+	unsigned int cpu = policy->cpu;
+	int ret;
+
+	ret = cppc_set_enable(cpu, true);
+	if (ret && ret != -EOPNOTSUPP) {
+		pr_warn("Failed to re-enable CPPC for CPU%u (%d)\n", cpu, ret);
+		goto out_fie;
+	}
+
+	/*
+	 * Recompute min/max from the policy, clamp desired_perf into range, and
+	 * reprogram the performance controls.
+	 */
+	cppc_cpufreq_update_perf_limits(cpu_data, policy);
+
+	cpu_data->perf_ctrls.desired_perf =
+		clamp_t(u32, cpu_data->perf_ctrls.desired_perf,
+			cpu_data->perf_ctrls.min_perf,
+			cpu_data->perf_ctrls.max_perf);
+
+	ret = cppc_cpufreq_prepare_perf_restore(cpu, &cpu_data->perf_ctrls);
+	if (ret)
+		pr_debug("Failed to prepare perf restore on CPU%u (%d)\n",
+			 cpu, ret);
+
+	ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
+	if (ret)
+		pr_debug("Failed to restore perf controls on CPU%u (%d)\n",
+			 cpu, ret);
+
+out_fie:
+	/* Restart what offline() stopped, with a new counter snapshot. */
+	cppc_cpufreq_cpu_fie_init(policy);
+
+	return 0;
+}
+
+/*
+ * Run when the policy's last online CPU goes down, undoing what online() did.
+ * Defining offline() is what makes the core keep the policy alive instead of
+ * tearing it down.
+ */
+static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
+{
+	struct cppc_cpudata *cpu_data = policy->driver_data;
+	struct cppc_perf_ctrls perf_ctrls = cpu_data->perf_ctrls;
+	unsigned int cpu = policy->cpu;
+	int ret;
+
+	/*
+	 * Stop the frequency invariance updates and cancel the pending work, so
+	 * that no sample spans the offline window. online() restarts them with
+	 * a new counter snapshot.
+	 */
+	cppc_cpufreq_cpu_fie_exit(policy);
+
+	/*
+	 * Request the lowest desired performance while the policy has no online
+	 * CPU. Zeroing MIN and MAX makes cppc_set_perf() leave them unchanged.
+	 */
+	perf_ctrls.desired_perf = cpu_data->perf_caps.lowest_perf;
+	perf_ctrls.min_perf = 0;
+	perf_ctrls.max_perf = 0;
+
+	ret = cppc_set_perf(cpu, &perf_ctrls);
+	if (ret)
+		pr_debug("Err setting perf value:%u on CPU:%u. ret:%d\n",
+			 cpu_data->perf_caps.lowest_perf, cpu, ret);
+
+	return 0;
+}
+
 static inline u64 get_delta(u64 t1, u64 t0)
 {
 	if (t1 > t0 || t0 > ~(u32)0)
@@ -1047,6 +1167,8 @@ static struct cpufreq_driver cppc_cpufreq_driver = {
 	.fast_switch = cppc_cpufreq_fast_switch,
 	.init = cppc_cpufreq_cpu_init,
 	.exit = cppc_cpufreq_cpu_exit,
+	.online = cppc_cpufreq_cpu_online,
+	.offline = cppc_cpufreq_cpu_offline,
 	.set_boost = cppc_cpufreq_set_boost,
 	.attr = cppc_cpufreq_attr,
 	.name = "cppc_cpufreq",
-- 
2.34.1


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

* [PATCH v5 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64
  2026-09-16 10:38 [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
  2026-09-16 10:38 ` [PATCH v5 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
@ 2026-09-16 10:38 ` Sumit Gupta
  2026-09-16 18:48   ` K Prateek Nayak
  2026-09-16 10:38 ` [PATCH v5 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Sumit Gupta @ 2026-09-16 10:38 UTC (permalink / raw)
  To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
	ionela.voinescu, zhenglifeng1, zhanjie9, lenb, ray.huang,
	mario.limonciello, perry.yuan, kprateek.nayak, linux-kernel,
	linux-pm, linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg

cppc_get_auto_sel()/cppc_set_auto_sel() use a bool, unlike the other
CPPC register get/set helpers which use a u64.

The next patch in this series saves and restores the OSPM-set registers
across CPU hotplug and driver unload through a common table of register
get/set helpers that all take a u64. The bool autonomous selection
helpers cannot be added to that table.

Change cppc_get_auto_sel()/cppc_set_auto_sel() to take a u64 so the
autonomous selection register fits alongside the others, and update
their callers.

Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
 drivers/acpi/cppc_acpi.c       | 20 ++++----------------
 drivers/cpufreq/amd-pstate.c   |  2 +-
 drivers/cpufreq/cppc_cpufreq.c |  4 ++--
 include/acpi/cppc_acpi.h       |  8 ++++----
 4 files changed, 11 insertions(+), 23 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index fef54fcd00b7..9e882b3911e6 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1904,23 +1904,11 @@ EXPORT_SYMBOL_GPL(cppc_set_auto_act_window);
 /**
  * cppc_get_auto_sel() - Read autonomous selection register.
  * @cpu: CPU from which to read register.
- * @enable: Return address.
+ * @enable: Return address, set to 0 or 1.
  */
-int cppc_get_auto_sel(int cpu, bool *enable)
+int cppc_get_auto_sel(int cpu, u64 *enable)
 {
-	u64 auto_sel;
-	int ret;
-
-	if (enable == NULL)
-		return -EINVAL;
-
-	ret = cppc_get_reg_val(cpu, AUTO_SEL_ENABLE, &auto_sel);
-	if (ret)
-		return ret;
-
-	*enable = (bool)auto_sel;
-
-	return 0;
+	return cppc_get_reg_val(cpu, AUTO_SEL_ENABLE, enable);
 }
 EXPORT_SYMBOL_GPL(cppc_get_auto_sel);
 
@@ -1929,7 +1917,7 @@ EXPORT_SYMBOL_GPL(cppc_get_auto_sel);
  * @cpu    : CPU to which to write register.
  * @enable : the desired value of autonomous selection resiter to be updated.
  */
-int cppc_set_auto_sel(int cpu, bool enable)
+int cppc_set_auto_sel(int cpu, u64 enable)
 {
 	return cppc_set_reg_val(cpu, AUTO_SEL_ENABLE, enable);
 }
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 8bfd46d60843..20b9e216670c 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -499,7 +499,7 @@ static int shmem_init_perf(struct amd_cpudata *cpudata)
 	struct cppc_perf_caps cppc_perf;
 	union perf_cached perf = READ_ONCE(cpudata->perf);
 	u64 numerator;
-	bool auto_sel;
+	u64 auto_sel;
 
 	int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
 	if (ret)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 37ead7f6c179..d7d96fe0da1b 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -984,7 +984,7 @@ static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
 
 static ssize_t show_auto_select(struct cpufreq_policy *policy, char *buf)
 {
-	bool val;
+	u64 val;
 	int ret;
 
 	ret = cppc_get_auto_sel(policy->cpu, &val);
@@ -996,7 +996,7 @@ static ssize_t show_auto_select(struct cpufreq_policy *policy, char *buf)
 	if (ret)
 		return ret;
 
-	return sysfs_emit(buf, "%d\n", val);
+	return sysfs_emit(buf, "%llu\n", val);
 }
 
 static ssize_t store_auto_select(struct cpufreq_policy *policy,
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 94a6277edab2..3394e1b208be 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -187,8 +187,8 @@ extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool e
 extern int cppc_set_epp(int cpu, u64 epp_val);
 extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window);
 extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window);
-extern int cppc_get_auto_sel(int cpu, bool *enable);
-extern int cppc_set_auto_sel(int cpu, bool enable);
+extern int cppc_get_auto_sel(int cpu, u64 *enable);
+extern int cppc_set_auto_sel(int cpu, u64 enable);
 extern int cppc_get_perf_limited(int cpu, u64 *perf_limited);
 extern int cppc_set_perf_limited(int cpu, u64 bits_to_clear);
 extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
@@ -285,11 +285,11 @@ static inline int cppc_set_auto_act_window(int cpu, u64 auto_act_window)
 {
 	return -EOPNOTSUPP;
 }
-static inline int cppc_get_auto_sel(int cpu, bool *enable)
+static inline int cppc_get_auto_sel(int cpu, u64 *enable)
 {
 	return -EOPNOTSUPP;
 }
-static inline int cppc_set_auto_sel(int cpu, bool enable)
+static inline int cppc_set_auto_sel(int cpu, u64 enable)
 {
 	return -EOPNOTSUPP;
 }
-- 
2.34.1


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

* [PATCH v5 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
  2026-09-16 10:38 [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
  2026-09-16 10:38 ` [PATCH v5 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
  2026-09-16 10:38 ` [PATCH v5 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64 Sumit Gupta
@ 2026-09-16 10:38 ` Sumit Gupta
  2026-09-16 10:38 ` [PATCH v5 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
  2026-09-16 19:04 ` [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload K Prateek Nayak
  4 siblings, 0 replies; 8+ messages in thread
From: Sumit Gupta @ 2026-09-16 10:38 UTC (permalink / raw)
  To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
	ionela.voinescu, zhenglifeng1, zhanjie9, lenb, ray.huang,
	mario.limonciello, perry.yuan, kprateek.nayak, linux-kernel,
	linux-pm, linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg

Values written to OSPM-set CPPC registers via sysfs can be lost in two
ways:

  - Across CPU hotplug: the platform may reset a CPU's registers while it
    is offline.
  - On driver unload: the value the driver wrote is left in the register
    instead of returning to its pre-driver state.

Add a small table-driven mechanism that handles both:

  - On init(), capture each register's firmware value before the
    driver programs anything.
  - On offline(), read back each register's current value (whatever was
    last set via sysfs) so it can be reapplied, then restore the firmware
    value.
  - On online(), reapply the value captured at offline() after
    reprogramming the performance controls. A failed write to the controls
    does not skip the reapply, as no other path restores these registers.
  - On exit(), nothing is needed, as the core calls offline() first, which
    already restored the firmware values.

Cover the Autonomous Selection (auto_sel), Energy Performance Preference
(EPP) and Autonomous Activity Window (auto_act_window) registers. Writes
to EPP and auto_act_window only have meaning while auto_sel is enabled,
so write auto_sel before them when enabling it and after them when
disabling it. While autonomous selection stays disabled, the platform may
ignore those writes.

Suggested-by: Pierre Gondois <pierre.gondois@arm.com>
Link: https://lore.kernel.org/all/86780f97-29ee-4a72-b311-38c89434b707@arm.com/
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 193 ++++++++++++++++++++++++++++++++-
 1 file changed, 190 insertions(+), 3 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index d7d96fe0da1b..ac315071a979 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -28,6 +28,183 @@
 
 static struct cpufreq_driver cppc_cpufreq_driver;
 
+/*
+ * OSPM-set CPPC registers tracked for save/restore. A value the OS wrote is
+ * reapplied from online() across CPU hotplug, and the firmware value is
+ * restored from offline().
+ *
+ * Autonomous Selection (auto_sel) is kept first, as the registers after it
+ * only have meaning while it is enabled.
+ */
+enum cppc_saved_reg_id {
+	CPPC_SAVED_AUTO_SEL,
+	CPPC_SAVED_EPP,
+	CPPC_SAVED_AUTO_ACT_WINDOW,
+	CPPC_NR_SAVED_REGS,
+};
+
+struct cppc_saved_reg {
+	const char *name;
+	int (*get)(int cpu, u64 *val);
+	int (*set)(int cpu, u64 val);
+};
+
+static const struct cppc_saved_reg cppc_saved_regs[CPPC_NR_SAVED_REGS] = {
+	[CPPC_SAVED_AUTO_SEL] = {
+		.name = "auto_sel",
+		.get = cppc_get_auto_sel,
+		.set = cppc_set_auto_sel,
+	},
+	[CPPC_SAVED_EPP] = {
+		.name = "epp",
+		.get = cppc_get_epp_perf,
+		.set = cppc_set_epp,
+	},
+	[CPPC_SAVED_AUTO_ACT_WINDOW] = {
+		.name = "auto_act_window",
+		.get = cppc_get_auto_act_window,
+		.set = cppc_set_auto_act_window,
+	},
+};
+
+enum cppc_saved_type {
+	CPPC_SAVED_FIRMWARE,
+	CPPC_SAVED_REQUESTED,
+};
+
+/*
+ * Per-policy values saved for each register in cppc_saved_regs[]:
+ *   firmware_val  - value before the driver touched it, captured at init()
+ *                   and written back when the policy goes offline. U64_MAX
+ *                   if it could not be read
+ *   requested_val - value in effect when the policy last went offline,
+ *                   reapplied at online(). U64_MAX if none
+ */
+struct cppc_saved_vals {
+	u64 firmware_val;
+	u64 requested_val;
+};
+
+struct cppc_policy_state {
+	struct cppc_saved_vals regs[CPPC_NR_SAVED_REGS];
+};
+
+static DEFINE_PER_CPU(struct cppc_policy_state, cppc_policy_state);
+
+/*
+ * Per-policy state is kept in the per-CPU variable of the first CPU the policy
+ * manages. related_cpus (the policy's full set of CPUs) never changes while the
+ * policy exists, so this CPU (unlike policy->cpu) stays the same across CPU
+ * hotplug, and every callback reaches the same copy.
+ */
+static struct cppc_policy_state *
+cppc_cpufreq_policy_state(struct cpufreq_policy *policy)
+{
+	const struct cpumask *policy_cpus = policy->related_cpus;
+
+	/*
+	 * related_cpus is empty until the core fills it in after init(), so
+	 * fall back to policy->cpus, which has the same first CPU.
+	 */
+	if (cpumask_empty(policy_cpus))
+		policy_cpus = policy->cpus;
+
+	return &per_cpu(cppc_policy_state, cpumask_first(policy_cpus));
+}
+
+/*
+ * Save each register's current value, either as the firmware value, captured
+ * before the driver programs anything, or as the requested value, to reapply
+ * at online().
+ */
+static void cppc_cpufreq_save_regs(struct cpufreq_policy *policy,
+				   enum cppc_saved_type saved_type)
+{
+	struct cppc_policy_state *st = cppc_cpufreq_policy_state(policy);
+	unsigned int cpu = policy->cpu;
+	u64 val;
+	int i;
+
+	for (i = 0; i < CPPC_NR_SAVED_REGS; i++) {
+		if (cppc_saved_regs[i].get(cpu, &val))
+			val = U64_MAX;
+
+		if (saved_type == CPPC_SAVED_FIRMWARE) {
+			st->regs[i].firmware_val = val;
+			st->regs[i].requested_val = U64_MAX;
+		} else {
+			st->regs[i].requested_val = val;
+		}
+	}
+}
+
+static u64 cppc_cpufreq_saved_reg_value(const struct cppc_saved_vals *st,
+					enum cppc_saved_reg_id reg,
+					enum cppc_saved_type saved_type)
+{
+	if (saved_type == CPPC_SAVED_FIRMWARE)
+		return st[reg].firmware_val;
+
+	return st[reg].requested_val;
+}
+
+/*
+ * Write one tracked register, skipping it when there is no saved value.
+ * A register the platform does not allow writing is not an error.
+ */
+static void cppc_cpufreq_write_saved_reg(unsigned int cpu,
+					 enum cppc_saved_reg_id reg, u64 val,
+					 enum cppc_saved_type saved_type)
+{
+	const char *op = (saved_type == CPPC_SAVED_FIRMWARE) ?
+			 "restore firmware" : "reapply saved";
+	int ret;
+
+	if (val == U64_MAX)
+		return;
+
+	ret = cppc_saved_regs[reg].set(cpu, val);
+	if (ret == -EOPNOTSUPP)
+		return;
+	if (ret)
+		pr_debug("Failed to %s %s=%llu on CPU%u (%d)\n", op,
+			 cppc_saved_regs[reg].name, val, cpu, ret);
+}
+
+/*
+ * Apply the saved firmware or requested value to each tracked register.
+ *
+ * Write auto_sel first when the value being applied enables autonomous
+ * selection and last when it disables it, so the writes to the dependent
+ * registers can still take effect. While autonomous selection stays disabled,
+ * the platform may ignore those writes. Do not enable it temporarily to force
+ * them through.
+ */
+static void cppc_cpufreq_apply_saved_regs(struct cpufreq_policy *policy,
+					  enum cppc_saved_type saved_type)
+{
+	const struct cppc_saved_vals *st = cppc_cpufreq_policy_state(policy)->regs;
+	unsigned int cpu = policy->cpu;
+	u64 auto_sel, val;
+	int i;
+
+	auto_sel = cppc_cpufreq_saved_reg_value(st, CPPC_SAVED_AUTO_SEL,
+						saved_type);
+
+	if (auto_sel)
+		cppc_cpufreq_write_saved_reg(cpu, CPPC_SAVED_AUTO_SEL, auto_sel,
+					     saved_type);
+
+	for (i = CPPC_SAVED_AUTO_SEL + 1; i < CPPC_NR_SAVED_REGS; i++) {
+		val = cppc_cpufreq_saved_reg_value(st, i, saved_type);
+		cppc_cpufreq_write_saved_reg(cpu, i, val, saved_type);
+	}
+
+	if (!auto_sel)
+		cppc_cpufreq_write_saved_reg(cpu, CPPC_SAVED_AUTO_SEL, auto_sel,
+					     saved_type);
+}
+
 #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
 static enum {
 	FIE_UNSET = -1,
@@ -718,6 +895,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
 	policy->cur = cppc_perf_to_khz(caps, caps->highest_perf);
 	cpu_data->perf_ctrls.desired_perf =  caps->highest_perf;
 
+	cppc_cpufreq_save_regs(policy, CPPC_SAVED_FIRMWARE);
+
 	ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
 	if (ret) {
 		pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
@@ -791,12 +970,14 @@ cppc_cpufreq_prepare_perf_restore(unsigned int cpu,
  *
  * The platform may have disabled CPPC and reset the performance controls
  * (desired, min and max performance) while the CPU was offline, so re-enable
- * CPPC and reprogram them.
+ * CPPC and reprogram them. Also reapply the OSPM-set registers that offline()
+ * reset to firmware values.
  *
  * Report failures without returning them, or the core would free the policy and
  * leave the CPU without cpufreq. A failed write to the performance controls is
- * not fatal, as the governor's next request programs them again. A failed CPPC
- * enable stops the restore, as the writes that follow may not reach the
+ * not fatal, as the governor's next request programs them again. The OSPM-set
+ * registers are reapplied even then, as no other path restores them. A failed
+ * CPPC enable skips both restores, as the writes that follow may not reach the
  * platform.
  */
 static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
@@ -832,6 +1013,8 @@ static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
 		pr_debug("Failed to restore perf controls on CPU%u (%d)\n",
 			 cpu, ret);
 
+	cppc_cpufreq_apply_saved_regs(policy, CPPC_SAVED_REQUESTED);
+
 out_fie:
 	/* Restart what offline() stopped, with a new counter snapshot. */
 	cppc_cpufreq_cpu_fie_init(policy);
@@ -851,6 +1034,10 @@ static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
 	unsigned int cpu = policy->cpu;
 	int ret;
 
+	/* Save what the OS set, and leave the platform in its pre-driver state. */
+	cppc_cpufreq_save_regs(policy, CPPC_SAVED_REQUESTED);
+	cppc_cpufreq_apply_saved_regs(policy, CPPC_SAVED_FIRMWARE);
+
 	/*
 	 * Stop the frequency invariance updates and cancel the pending work, so
 	 * that no sample spans the offline window. online() restarts them with
-- 
2.34.1


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

* [PATCH v5 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume
  2026-09-16 10:38 [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
                   ` (2 preceding siblings ...)
  2026-09-16 10:38 ` [PATCH v5 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
@ 2026-09-16 10:38 ` Sumit Gupta
  2026-09-16 19:04 ` [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload K Prateek Nayak
  4 siblings, 0 replies; 8+ messages in thread
From: Sumit Gupta @ 2026-09-16 10:38 UTC (permalink / raw)
  To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
	ionela.voinescu, zhenglifeng1, zhanjie9, lenb, ray.huang,
	mario.limonciello, perry.yuan, kprateek.nayak, linux-kernel,
	linux-pm, linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg

The driver preserves the OSPM-set registers across CPU hotplug, but system
suspend/resume is a separate path. On platforms that reset those registers
or the performance controls across suspend, the values are lost.

The hotplug callbacks cannot cover suspend on their own. Secondary CPUs go
offline only after devices are suspended, too late to touch the CPPC
registers. offline() does not run for every policy either, as the boot CPU
stays up during suspend-to-RAM and no CPU goes offline during
suspend-to-idle. The driver's suspend() callback runs earlier, from
cpufreq_suspend(), while all CPUs are still online and no device is
suspended, so CPPC access is still safe.

Reuse the same save/restore mechanism for suspend/resume:

  - suspend() saves the current OSPM-set values, restores the firmware
    ones and sets a per-policy flag, suspend_regs_handled, to record that.
    It also stops the frequency invariance updates, so that no sample
    spans the suspend window.
  - offline() sees the flag and skips the save and restore, as suspend()
    has already done both. Saving again would capture the firmware values
    that suspend() wrote back and lose what the OS set. It still requests
    the lowest desired performance.
  - online() clears the flag, so that a later offline() takes a fresh
    snapshot. It also restarts the frequency invariance updates.
  - resume() calls online() for a policy that still has the flag set. CPUs
    offlined during suspend come back before the core calls resume(), so
    online() has already run for their policies and cleared the flag.

Suggested-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
 drivers/cpufreq/cppc_cpufreq.c | 63 ++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 3 deletions(-)

diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index ac315071a979..11f2e8111ef9 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -87,6 +87,12 @@ struct cppc_saved_vals {
 
 struct cppc_policy_state {
 	struct cppc_saved_vals regs[CPPC_NR_SAVED_REGS];
+	/*
+	 * Set by suspend() after it saves the OSPM-set values and restores the
+	 * firmware ones, so a later offline() does not repeat those accesses.
+	 * Cleared at init() and by online().
+	 */
+	bool suspend_regs_handled;
 };
 
 static DEFINE_PER_CPU(struct cppc_policy_state, cppc_policy_state);
@@ -895,6 +901,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
 	policy->cur = cppc_perf_to_khz(caps, caps->highest_perf);
 	cpu_data->perf_ctrls.desired_perf =  caps->highest_perf;
 
+	cppc_cpufreq_policy_state(policy)->suspend_regs_handled = false;
 	cppc_cpufreq_save_regs(policy, CPPC_SAVED_FIRMWARE);
 
 	ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
@@ -986,6 +993,8 @@ static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
 	unsigned int cpu = policy->cpu;
 	int ret;
 
+	cppc_cpufreq_policy_state(policy)->suspend_regs_handled = false;
+
 	ret = cppc_set_enable(cpu, true);
 	if (ret && ret != -EOPNOTSUPP) {
 		pr_warn("Failed to re-enable CPPC for CPU%u (%d)\n", cpu, ret);
@@ -1034,9 +1043,14 @@ static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
 	unsigned int cpu = policy->cpu;
 	int ret;
 
-	/* Save what the OS set, and leave the platform in its pre-driver state. */
-	cppc_cpufreq_save_regs(policy, CPPC_SAVED_REQUESTED);
-	cppc_cpufreq_apply_saved_regs(policy, CPPC_SAVED_FIRMWARE);
+	/*
+	 * Save what the OS set and leave the platform in its pre-driver state,
+	 * unless suspend() already did so earlier in this suspend cycle.
+	 */
+	if (!cppc_cpufreq_policy_state(policy)->suspend_regs_handled) {
+		cppc_cpufreq_save_regs(policy, CPPC_SAVED_REQUESTED);
+		cppc_cpufreq_apply_saved_regs(policy, CPPC_SAVED_FIRMWARE);
+	}
 
 	/*
 	 * Stop the frequency invariance updates and cancel the pending work, so
@@ -1061,6 +1075,47 @@ static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
 	return 0;
 }
 
+/*
+ * Run for every active policy when the system suspends, before any CPU goes
+ * offline.
+ *
+ * Save the OSPM-set values and restore the firmware values here, while CPPC
+ * access is still safe. Secondary CPUs go offline much later, with devices
+ * already suspended. That is too late for these accesses, so offline() skips
+ * them. Doing it here also covers a policy whose CPUs stay online, for which
+ * offline() never runs.
+ *
+ * Stop the frequency invariance updates here as well, so that no sample spans
+ * the suspend window. offline() would not do it for a policy whose CPUs stay
+ * online. online() restarts them on the way back.
+ */
+static int cppc_cpufreq_cpu_suspend(struct cpufreq_policy *policy)
+{
+	cppc_cpufreq_save_regs(policy, CPPC_SAVED_REQUESTED);
+	cppc_cpufreq_apply_saved_regs(policy, CPPC_SAVED_FIRMWARE);
+	cppc_cpufreq_policy_state(policy)->suspend_regs_handled = true;
+
+	cppc_cpufreq_cpu_fie_exit(policy);
+
+	return 0;
+}
+
+/*
+ * Run the online() restore for a policy whose CPUs stayed online through
+ * suspend.
+ *
+ * CPUs offlined during suspend come back before the core calls resume(), so
+ * online() has already run for their policies and cleared the flag. Only a
+ * policy that still has it set needs online() here.
+ */
+static int cppc_cpufreq_cpu_resume(struct cpufreq_policy *policy)
+{
+	if (!cppc_cpufreq_policy_state(policy)->suspend_regs_handled)
+		return 0;
+
+	return cppc_cpufreq_cpu_online(policy);
+}
+
 static inline u64 get_delta(u64 t1, u64 t0)
 {
 	if (t1 > t0 || t0 > ~(u32)0)
@@ -1356,6 +1411,8 @@ static struct cpufreq_driver cppc_cpufreq_driver = {
 	.exit = cppc_cpufreq_cpu_exit,
 	.online = cppc_cpufreq_cpu_online,
 	.offline = cppc_cpufreq_cpu_offline,
+	.suspend = cppc_cpufreq_cpu_suspend,
+	.resume = cppc_cpufreq_cpu_resume,
 	.set_boost = cppc_cpufreq_set_boost,
 	.attr = cppc_cpufreq_attr,
 	.name = "cppc_cpufreq",
-- 
2.34.1


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

* Re: [PATCH v5 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64
  2026-09-16 10:38 ` [PATCH v5 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64 Sumit Gupta
@ 2026-09-16 18:48   ` K Prateek Nayak
  0 siblings, 0 replies; 8+ messages in thread
From: K Prateek Nayak @ 2026-09-16 18:48 UTC (permalink / raw)
  To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois,
	christian.loehle, ionela.voinescu, zhenglifeng1, zhanjie9, lenb,
	ray.huang, mario.limonciello, perry.yuan, linux-kernel, linux-pm,
	linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu

Hello Sumit,

On 9/16/2026 4:08 PM, Sumit Gupta wrote:
> cppc_get_auto_sel()/cppc_set_auto_sel() use a bool, unlike the other
> CPPC register get/set helpers which use a u64.
> 
> The next patch in this series saves and restores the OSPM-set registers
> across CPU hotplug and driver unload through a common table of register
> get/set helpers that all take a u64. The bool autonomous selection
> helpers cannot be added to that table.
> 
> Change cppc_get_auto_sel()/cppc_set_auto_sel() to take a u64 so the
> autonomous selection register fits alongside the others, and update
> their callers.
> 
> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>

For amd-pstate bits, feel free to include:

Reviewed-by: K Prateek Nayak <kprateek.nayak@amd.com>
Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>

-- 
Thanks and Regards,
Prateek


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

* Re: [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
  2026-09-16 10:38 [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
                   ` (3 preceding siblings ...)
  2026-09-16 10:38 ` [PATCH v5 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
@ 2026-09-16 19:04 ` K Prateek Nayak
  2026-09-17  7:13   ` Sumit Gupta
  4 siblings, 1 reply; 8+ messages in thread
From: K Prateek Nayak @ 2026-09-16 19:04 UTC (permalink / raw)
  To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois,
	christian.loehle, ionela.voinescu, zhenglifeng1, zhanjie9, lenb,
	ray.huang, mario.limonciello, perry.yuan, linux-kernel, linux-pm,
	linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu

Hello Sumit,

On 9/16/2026 4:08 PM, Sumit Gupta wrote:
> This series keeps the CPPC cpufreq policy alive across CPU hotplug and
> preserves the OSPM-set CPPC registers (Energy Performance Preference,
> Autonomous Activity Window, Autonomous Selection - set via sysfs).
> 
> Without online()/offline() callbacks, the core tears a policy down when
> its last CPU goes offline and rebuilds it on the way back, re-reading the
> CPPC capabilities each time. The values written to these registers can
> be lost:
> 
>  - Across CPU hotplug or suspend/resume: the platform may reset them
>    while the CPU is offline.
>  - On driver unload: the driver-written value is left in the register
>    instead of returning to its pre-driver state.
> 
> Handle these with:
> 
>  - Patch 1: adds online()/offline() callbacks so the core keeps policy
>    alive across CPU hotplug instead of tearing it down and rebuilding it.
>  - Patch 2: makes the autonomous selection register helpers take a u64.
>  - Patch 3: adds a table-driven mechanism that captures each register's
>    firmware value at init(), restores it from offline(), and reapplies
>    the OSPM-set value from online().
>  - Patch 4: extends the same save/restore to system suspend/resume.
> 
> v4[4] -> v5:
>  - Patch 1:
>    - offline() stops the frequency invariance updates and online()
>      restarts them, replacing the resync that raced with tick. (Sashiko)
>    - reorder the functions to match cppc_cpufreq_driver. (Jie Zhan)
>  - Patch 3:
>    - reapply the OSPM-set registers even when the performance control
>      write fails. (Sashiko)
>  - Patch 4:
>    - suspend() stops the frequency invariance updates too, completing the
>      patch 1 change for a policy whose CPUs stay online.
> 
> Sumit Gupta (4):
>   cpufreq: CPPC: Keep the policy across CPU hotplug
>   ACPI: CPPC: Make autonomous selection helpers take a u64
>   cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
>   cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume
> 
>  drivers/acpi/cppc_acpi.c       |  20 +-
>  drivers/cpufreq/amd-pstate.c   |   2 +-
>  drivers/cpufreq/cppc_cpufreq.c | 378 ++++++++++++++++++++++++++++++++-
>  include/acpi/cppc_acpi.h       |   8 +-
>  4 files changed, 381 insertions(+), 27 deletions(-)

I was able to hack the Kconfig to build cppc_cpufreq.c for x86 too
and test this out on a Zen3 machine that uses shared memory based
CPPC control.

FWIW, I could verify that "auto_select" and
"energy_performance_preference_val" persists correctly across an
offline-online cycle on my system so feel free to include:

Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>

-- 
Thanks and Regards,
Prateek


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

* Re: [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
  2026-09-16 19:04 ` [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload K Prateek Nayak
@ 2026-09-17  7:13   ` Sumit Gupta
  0 siblings, 0 replies; 8+ messages in thread
From: Sumit Gupta @ 2026-09-17  7:13 UTC (permalink / raw)
  To: K Prateek Nayak, rafael, viresh.kumar, pierre.gondois,
	christian.loehle, ionela.voinescu, zhenglifeng1, zhanjie9, lenb,
	ray.huang, mario.limonciello, perry.yuan, linux-kernel, linux-pm,
	linux-acpi, acpica-devel, linux-tegra
  Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu



On 17/09/26 00:34, K Prateek Nayak wrote:
> External email: Use caution opening links or attachments
> 
> 
> Hello Sumit,
> 
> On 9/16/2026 4:08 PM, Sumit Gupta wrote:
>> This series keeps the CPPC cpufreq policy alive across CPU hotplug and
>> preserves the OSPM-set CPPC registers (Energy Performance Preference,
>> Autonomous Activity Window, Autonomous Selection - set via sysfs).
>>
>> Without online()/offline() callbacks, the core tears a policy down when
>> its last CPU goes offline and rebuilds it on the way back, re-reading the
>> CPPC capabilities each time. The values written to these registers can
>> be lost:
>>
>>   - Across CPU hotplug or suspend/resume: the platform may reset them
>>     while the CPU is offline.
>>   - On driver unload: the driver-written value is left in the register
>>     instead of returning to its pre-driver state.
>>
>> Handle these with:
>>
>>   - Patch 1: adds online()/offline() callbacks so the core keeps policy
>>     alive across CPU hotplug instead of tearing it down and rebuilding it.
>>   - Patch 2: makes the autonomous selection register helpers take a u64.
>>   - Patch 3: adds a table-driven mechanism that captures each register's
>>     firmware value at init(), restores it from offline(), and reapplies
>>     the OSPM-set value from online().
>>   - Patch 4: extends the same save/restore to system suspend/resume.
>>
>> v4[4] -> v5:
>>   - Patch 1:
>>     - offline() stops the frequency invariance updates and online()
>>       restarts them, replacing the resync that raced with tick. (Sashiko)
>>     - reorder the functions to match cppc_cpufreq_driver. (Jie Zhan)
>>   - Patch 3:
>>     - reapply the OSPM-set registers even when the performance control
>>       write fails. (Sashiko)
>>   - Patch 4:
>>     - suspend() stops the frequency invariance updates too, completing the
>>       patch 1 change for a policy whose CPUs stay online.
>>
>> Sumit Gupta (4):
>>    cpufreq: CPPC: Keep the policy across CPU hotplug
>>    ACPI: CPPC: Make autonomous selection helpers take a u64
>>    cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
>>    cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume
>>
>>   drivers/acpi/cppc_acpi.c       |  20 +-
>>   drivers/cpufreq/amd-pstate.c   |   2 +-
>>   drivers/cpufreq/cppc_cpufreq.c | 378 ++++++++++++++++++++++++++++++++-
>>   include/acpi/cppc_acpi.h       |   8 +-
>>   4 files changed, 381 insertions(+), 27 deletions(-)
> 
> I was able to hack the Kconfig to build cppc_cpufreq.c for x86 too
> and test this out on a Zen3 machine that uses shared memory based
> CPPC control.
> 
> FWIW, I could verify that "auto_select" and
> "energy_performance_preference_val" persists correctly across an
> offline-online cycle on my system so feel free to include:
> 
> Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
> 
> --
> Thanks and Regards,
> Prateek
> 

Hi Prateek,

Thanks for testing on x86.
I will add your Tested-by to the series, and Reviewed-by to patch 2.

Thanks,
Sumit


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

end of thread, other threads:[~2026-09-17  7:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16 10:38 [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
2026-09-16 10:38 ` [PATCH v5 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
2026-09-16 10:38 ` [PATCH v5 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64 Sumit Gupta
2026-09-16 18:48   ` K Prateek Nayak
2026-09-16 10:38 ` [PATCH v5 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
2026-09-16 10:38 ` [PATCH v5 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
2026-09-16 19:04 ` [PATCH v5 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload K Prateek Nayak
2026-09-17  7:13   ` Sumit Gupta

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

all inboxes | Powered by JetHome®