* [PATCH v3 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
@ 2026-07-24 21:59 Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Sumit Gupta @ 2026-07-24 21:59 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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 or the
autonomous boot parameter.
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 the 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, restores it when the policy goes down, and reapplies
the OSPM-set value when the policy comes back online.
- Patch 4: extends the same save/restore to system suspend/resume.
v2[2] -> v3:
- Patch 1: online() now re-establishes the desired/min/max tuple.
- Patch 2: make cppc_get/set_auto_sel() take a u64 arg.
- Patch 3: skip restoring/reapplying a reg whose value couldn't be read.
- Patch 3: split save_req_and_restore_firmware_regs() so patch 4 can
reuse save_requested_regs() for save-only suspend.
- New patch 4: preserve the OSPM-set registers across suspend/resume.
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 | 223 ++++++++++++++++++++++++++++++++-
include/acpi/cppc_acpi.h | 8 +-
4 files changed, 230 insertions(+), 23 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/
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug
2026-07-24 21:59 [PATCH v3 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
@ 2026-07-24 21:59 ` Sumit Gupta
2026-07-27 13:27 ` Christian Loehle
2026-07-28 8:41 ` zhenglifeng (A)
2026-07-24 21:59 ` [PATCH v3 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64 Sumit Gupta
` (2 subsequent siblings)
3 siblings, 2 replies; 10+ messages in thread
From: Sumit Gupta @ 2026-07-24 21:59 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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 fully tears
down a policy during exit() when its last online CPU is offlined, and
rebuilds it during init() when it 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.
This avoids re-reading the CPPC capabilities on every offline/online,
making CPU hotplug faster.
From online(), re-enable CPPC, as the platform may have disabled it
while the CPU was offline. Since the policy is no longer rebuilt via
init(), online() also reprograms the CPPC performance controls
(desired/min/max).
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/cpufreq/cppc_cpufreq.c | 44 ++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index f6cea0c54dd9..6dc59f99d880 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -722,6 +722,48 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
return ret;
}
+/*
+ * With offline() defined, the cpufreq core keeps the policy alive when
+ * a CPU is hotplugged out.
+ */
+static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
+{
+ return 0;
+}
+
+/*
+ * Re-enable CPPC when the policy's CPU comes back online, since the platform
+ * may have disabled it while the CPU was offline.
+ */
+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%d (%d)\n", cpu, ret);
+
+ /*
+ * The platform may reset the controls while the CPU is offline, so
+ * recompute min/max, clamp desired_perf into range, and reprogram them.
+ */
+ 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_set_perf(cpu, &cpu_data->perf_ctrls);
+ if (ret)
+ pr_debug("Failed to reapply perf request on CPU%d (%d)\n",
+ cpu, ret);
+
+ return 0;
+}
+
static void cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
struct cppc_cpudata *cpu_data = policy->driver_data;
@@ -1034,6 +1076,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 related [flat|nested] 10+ messages in thread
* [PATCH v3 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64
2026-07-24 21:59 [PATCH v3 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
@ 2026-07-24 21:59 ` Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
3 siblings, 0 replies; 10+ messages in thread
From: Sumit Gupta @ 2026-07-24 21:59 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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 9f572f481241..ffadd2ca26b1 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1757,23 +1757,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);
@@ -1782,7 +1770,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 f8d8288d644f..0f99bb86c3a3 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -507,7 +507,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 6dc59f99d880..34cdba00e61a 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -893,7 +893,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);
@@ -905,7 +905,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 8693890a7275..f4da73876287 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -182,8 +182,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);
@@ -274,11 +274,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 related [flat|nested] 10+ messages in thread
* [PATCH v3 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
2026-07-24 21:59 [PATCH v3 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64 Sumit Gupta
@ 2026-07-24 21:59 ` Sumit Gupta
2026-07-27 13:15 ` Christian Loehle
2026-07-24 21:59 ` [PATCH v3 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
3 siblings, 1 reply; 10+ messages in thread
From: Sumit Gupta @ 2026-07-24 21:59 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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 or the autonomous
boot parameter) 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 or the boot parameter) so it can be reapplied, then
restore the firmware value.
- On online(), reapply the value captured at offline() after the
performance request is re-established.
Keep Autonomous Selection (auto_sel) last in the table so that, on
online(), its saved value is reapplied after the other registers that
shape its behaviour.
Cover the Autonomous Selection (auto_sel), Energy Performance Preference
(EPP) and Autonomous Activity Window (auto_act_window) registers.
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 | 157 +++++++++++++++++++++++++++++++++
1 file changed, 157 insertions(+)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 34cdba00e61a..8a13ec49eb9d 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -28,6 +28,150 @@
static struct cpufreq_driver cppc_cpufreq_driver;
+/*
+ * OSPM-set CPPC registers tracked for save/restore. A value set via sysfs or
+ * the autonomous boot parameter is reapplied from online() across CPU
+ * hotplug, and the firmware value is restored from offline().
+ *
+ * Autonomous Selection (auto_sel) is kept last so its saved value is
+ * reapplied after the other registers that shape its behaviour.
+ */
+enum cppc_saved_reg_id {
+ CPPC_SAVED_EPP,
+ CPPC_SAVED_AUTO_ACT_WINDOW,
+ CPPC_SAVED_AUTO_SEL,
+ CPPC_NR_SAVED_REGS,
+};
+
+struct cppc_saved_reg {
+ 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_EPP] = {
+ cppc_get_epp_perf, cppc_set_epp,
+ },
+ [CPPC_SAVED_AUTO_ACT_WINDOW] = {
+ cppc_get_auto_act_window, cppc_set_auto_act_window,
+ },
+ [CPPC_SAVED_AUTO_SEL] = {
+ cppc_get_auto_sel, cppc_set_auto_sel,
+ },
+};
+
+/*
+ * Per-policy saved state for each register in cppc_saved_regs[]:
+ * firmware_val - value before the driver touched it, captured at init()
+ * and restored while the policy is 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_state {
+ u64 firmware_val;
+ u64 requested_val;
+};
+
+static DEFINE_PER_CPU(struct cppc_saved_state[CPPC_NR_SAVED_REGS], cppc_saved_state);
+
+/*
+ * Return this policy's saved state. Each policy keeps a single copy, stored in
+ * the per-CPU variable of the first CPU it manages. related_cpus (the policy's
+ * full set of CPUs) never changes while it exists, so this CPU (unlike
+ * policy->cpu) stays the same across CPU hotplug, and every callback reaches
+ * the same copy.
+ */
+static struct cppc_saved_state *cppc_cpufreq_policy_saved_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(). Until
+ * then, fall back to policy->cpus, which has the same first CPU.
+ */
+ if (cpumask_empty(policy_cpus))
+ policy_cpus = policy->cpus;
+
+ return per_cpu(cppc_saved_state, cpumask_first(policy_cpus));
+}
+
+/*
+ * Capture each register's firmware value before the driver programs anything.
+ */
+static void cppc_cpufreq_save_firmware_regs(struct cpufreq_policy *policy)
+{
+ struct cppc_saved_state *st = cppc_cpufreq_policy_saved_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;
+ st[i].firmware_val = val;
+ st[i].requested_val = U64_MAX;
+ }
+}
+
+/*
+ * Save each register's current value so it can later be reapplied.
+ */
+static void cppc_cpufreq_save_requested_regs(struct cpufreq_policy *policy)
+{
+ struct cppc_saved_state *st = cppc_cpufreq_policy_saved_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;
+ st[i].requested_val = val;
+ }
+}
+
+/*
+ * Restore each register's firmware value, leaving the platform in its
+ * pre-driver state.
+ */
+static void cppc_cpufreq_restore_firmware_regs(struct cpufreq_policy *policy)
+{
+ struct cppc_saved_state *st = cppc_cpufreq_policy_saved_state(policy);
+ unsigned int cpu = policy->cpu;
+ int i, ret;
+
+ for (i = 0; i < CPPC_NR_SAVED_REGS; i++) {
+ if (st[i].firmware_val == U64_MAX)
+ continue;
+
+ ret = cppc_saved_regs[i].set(cpu, st[i].firmware_val);
+ if (ret && ret != -EOPNOTSUPP)
+ pr_debug("Failed to restore firmware reg %d on CPU%u (%d)\n",
+ i, cpu, ret);
+ }
+}
+
+/*
+ * Reapply each register's requested value that offline() saved.
+ */
+static void cppc_cpufreq_reapply_requested_regs(struct cpufreq_policy *policy)
+{
+ struct cppc_saved_state *st = cppc_cpufreq_policy_saved_state(policy);
+ unsigned int cpu = policy->cpu;
+ int i, ret;
+
+ for (i = 0; i < CPPC_NR_SAVED_REGS; i++) {
+ if (st[i].requested_val == U64_MAX)
+ continue;
+
+ ret = cppc_saved_regs[i].set(cpu, st[i].requested_val);
+ if (ret && ret != -EOPNOTSUPP)
+ pr_debug("Failed to reapply saved reg %d on CPU%u (%d)\n",
+ i, cpu, ret);
+ }
+}
+
#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
static enum {
FIE_UNSET = -1,
@@ -707,6 +851,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_firmware_regs(policy);
+
ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
if (ret) {
pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
@@ -725,15 +871,24 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
/*
* With offline() defined, the cpufreq core keeps the policy alive when
* a CPU is hotplugged out.
+ *
+ * Save each register's current value so online() can reapply it, then
+ * restore the firmware value, leaving the platform in its pre-driver state.
*/
static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
{
+ cppc_cpufreq_save_requested_regs(policy);
+ cppc_cpufreq_restore_firmware_regs(policy);
+
return 0;
}
/*
* Re-enable CPPC when the policy's CPU comes back online, since the platform
* may have disabled it while the CPU was offline.
+ *
+ * offline() reset the registers to their firmware values, so reapply the
+ * OSPM-set values it saved.
*/
static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
{
@@ -761,6 +916,8 @@ static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
pr_debug("Failed to reapply perf request on CPU%d (%d)\n",
cpu, ret);
+ cppc_cpufreq_reapply_requested_regs(policy);
+
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume
2026-07-24 21:59 [PATCH v3 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
` (2 preceding siblings ...)
2026-07-24 21:59 ` [PATCH v3 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
@ 2026-07-24 21:59 ` Sumit Gupta
2026-07-27 13:45 ` Christian Loehle
3 siblings, 1 reply; 10+ messages in thread
From: Sumit Gupta @ 2026-07-24 21:59 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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 previous patch 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.
Reuse the same save/restore mechanism for suspend/resume:
- suspend() only saves the current OSPM-set values. It does not revert
them to firmware, since a later offline() already does that when
system suspend offlines the secondary CPUs.
- resume() needs the same steps as online(), so .resume points at
online() directly.
Suggested-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/cpufreq/cppc_cpufreq.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 8a13ec49eb9d..be2d873ccd84 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -921,6 +921,22 @@ static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
return 0;
}
+/*
+ * suspend() only saves the OSPM-set values. It does not revert them to the
+ * firmware values.
+ *
+ * This is because system suspend may later offline the secondary CPUs.
+ * That runs offline(), which saves the values and then reverts to firmware.
+ * If suspend() had already reverted, offline() would save the firmware value
+ * instead of the user's request, and the request would be lost.
+ */
+static int cppc_cpufreq_cpu_suspend(struct cpufreq_policy *policy)
+{
+ cppc_cpufreq_save_requested_regs(policy);
+
+ return 0;
+}
+
static void cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
struct cppc_cpudata *cpu_data = policy->driver_data;
@@ -1235,6 +1251,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_online,
.set_boost = cppc_cpufreq_set_boost,
.attr = cppc_cpufreq_attr,
.name = "cppc_cpufreq",
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload
2026-07-24 21:59 ` [PATCH v3 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
@ 2026-07-27 13:15 ` Christian Loehle
0 siblings, 0 replies; 10+ messages in thread
From: Christian Loehle @ 2026-07-27 13:15 UTC (permalink / raw)
To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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
On 7/24/26 22:59, Sumit Gupta wrote:
> Values written to OSPM-set CPPC registers (via sysfs or the autonomous
> boot parameter) 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 or the boot parameter) so it can be reapplied, then
> restore the firmware value.
> - On online(), reapply the value captured at offline() after the
> performance request is re-established.
>
> Keep Autonomous Selection (auto_sel) last in the table so that, on
> online(), its saved value is reapplied after the other registers that
> shape its behaviour.
>
> Cover the Autonomous Selection (auto_sel), Energy Performance Preference
> (EPP) and Autonomous Activity Window (auto_act_window) registers.
>
> 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 | 157 +++++++++++++++++++++++++++++++++
> 1 file changed, 157 insertions(+)
>
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index 34cdba00e61a..8a13ec49eb9d 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -28,6 +28,150 @@
>
> static struct cpufreq_driver cppc_cpufreq_driver;
>
> +/*
> + * OSPM-set CPPC registers tracked for save/restore. A value set via sysfs or
> + * the autonomous boot parameter is reapplied from online() across CPU
> + * hotplug, and the firmware value is restored from offline().
> + *
> + * Autonomous Selection (auto_sel) is kept last so its saved value is
> + * reapplied after the other registers that shape its behaviour.
While that would make sense, unfortunately:
"8.4.6.1.6 Autonomous Activity Window Register
Writes to this register only have meaning when Autonomous Selection is enabled."
I think restoring an inappropriate EPP/AUTO_ACT_WINDOW temporarily is okay though.
AFAICS it has to be:
1. enable CPPC
2. restore a valid DESIRED/MIN/MAX
3. restore AUTO_SEL_ENABLE
4. if autonomous mode is enabled, restore EPP and AUTO_ACT_WINDOW
> + */
> +enum cppc_saved_reg_id {
> + CPPC_SAVED_EPP,
> + CPPC_SAVED_AUTO_ACT_WINDOW,
> + CPPC_SAVED_AUTO_SEL,
> + CPPC_NR_SAVED_REGS,
> +};
> [snip]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug
2026-07-24 21:59 ` [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
@ 2026-07-27 13:27 ` Christian Loehle
2026-07-29 14:41 ` Sumit Gupta
2026-07-28 8:41 ` zhenglifeng (A)
1 sibling, 1 reply; 10+ messages in thread
From: Christian Loehle @ 2026-07-27 13:27 UTC (permalink / raw)
To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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
On 7/24/26 22:59, Sumit Gupta wrote:
> Without online()/offline() callbacks, the cpufreq core fully tears
> down a policy during exit() when its last online CPU is offlined, and
> rebuilds it during init() when it 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.
> This avoids re-reading the CPPC capabilities on every offline/online,
> making CPU hotplug faster.
>
> From online(), re-enable CPPC, as the platform may have disabled it
> while the CPU was offline. Since the policy is no longer rebuilt via
> init(), online() also reprograms the CPPC performance controls
> (desired/min/max).
>
> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
> ---
> drivers/cpufreq/cppc_cpufreq.c | 44 ++++++++++++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index f6cea0c54dd9..6dc59f99d880 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -722,6 +722,48 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
> return ret;
> }
>
> +/*
> + * With offline() defined, the cpufreq core keeps the policy alive when
> + * a CPU is hotplugged out.
> + */
> +static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
> +{
> + return 0;
> +}
> +
> +/*
> + * Re-enable CPPC when the policy's CPU comes back online, since the platform
> + * may have disabled it while the CPU was offline.
> + */
> +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%d (%d)\n", cpu, ret);
What's the intention of continuing restoring CPPC register values here?
> +
> + /*
> + * The platform may reset the controls while the CPU is offline, so
> + * recompute min/max, clamp desired_perf into range, and reprogram them.
> + */
> + 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_set_perf(cpu, &cpu_data->perf_ctrls);
> + if (ret)
> + pr_debug("Failed to reapply perf request on CPU%d (%d)\n",
> + cpu, ret);
I think cppc_set_perf() needs some prep first before using it on reset values.
We assume that reset value may be Autonomous Mode on, right? So we must never
write MIN>MAX and vice versa. I think we may just have to read and write
the 'otherwise-offending' value first on reset.
> +
> + return 0;
> +}
> +
> static void cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
> {
> struct cppc_cpudata *cpu_data = policy->driver_data;
> @@ -1034,6 +1076,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",
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume
2026-07-24 21:59 ` [PATCH v3 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
@ 2026-07-27 13:45 ` Christian Loehle
0 siblings, 0 replies; 10+ messages in thread
From: Christian Loehle @ 2026-07-27 13:45 UTC (permalink / raw)
To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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
On 7/24/26 22:59, Sumit Gupta wrote:
> The previous patch 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.
>
> Reuse the same save/restore mechanism for suspend/resume:
>
> - suspend() only saves the current OSPM-set values. It does not revert
> them to firmware, since a later offline() already does that when
> system suspend offlines the secondary CPUs.
> - resume() needs the same steps as online(), so .resume points at
> online() directly.
>
> Suggested-by: Christian Loehle <christian.loehle@arm.com>
> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
> ---
> drivers/cpufreq/cppc_cpufreq.c | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index 8a13ec49eb9d..be2d873ccd84 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -921,6 +921,22 @@ static int cppc_cpufreq_cpu_online(struct cpufreq_policy *policy)
> return 0;
> }
>
> +/*
> + * suspend() only saves the OSPM-set values. It does not revert them to the
> + * firmware values.
> + *
> + * This is because system suspend may later offline the secondary CPUs.
> + * That runs offline(), which saves the values and then reverts to firmware.
> + * If suspend() had already reverted, offline() would save the firmware value
> + * instead of the user's request, and the request would be lost.
> + */
> +static int cppc_cpufreq_cpu_suspend(struct cpufreq_policy *policy)
> +{
> + cppc_cpufreq_save_requested_regs(policy);
> +
> + return 0;
> +}
> +
Wouldn't it be safer to commit everything here and not rely on the later
offline() to still need a fully usable CPPC platform (in particular for
PCC), as at this stage all but 2 CPUs might already be offline()d?
Also either the later offline() saves registers successfully, and overwrites
this snapshot, or it fails and overwrites them with U64, right?
> static void cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
> {
> struct cppc_cpudata *cpu_data = policy->driver_data;
> @@ -1235,6 +1251,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_online,
> .set_boost = cppc_cpufreq_set_boost,
> .attr = cppc_cpufreq_attr,
> .name = "cppc_cpufreq",
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug
2026-07-24 21:59 ` [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
2026-07-27 13:27 ` Christian Loehle
@ 2026-07-28 8:41 ` zhenglifeng (A)
1 sibling, 0 replies; 10+ messages in thread
From: zhenglifeng (A) @ 2026-07-28 8:41 UTC (permalink / raw)
To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois,
christian.loehle, ionela.voinescu, zhanjie9, lenb, saket.dumbre,
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
On 7/25/2026 5:59 AM, Sumit Gupta wrote:
> Without online()/offline() callbacks, the cpufreq core fully tears
> down a policy during exit() when its last online CPU is offlined, and
> rebuilds it during init() when it 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.
> This avoids re-reading the CPPC capabilities on every offline/online,
> making CPU hotplug faster.
>
> From online(), re-enable CPPC, as the platform may have disabled it
> while the CPU was offline. Since the policy is no longer rebuilt via
> init(), online() also reprograms the CPPC performance controls
> (desired/min/max).
>
> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
> ---
> drivers/cpufreq/cppc_cpufreq.c | 44 ++++++++++++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index f6cea0c54dd9..6dc59f99d880 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -722,6 +722,48 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
> return ret;
> }
>
> +/*
> + * With offline() defined, the cpufreq core keeps the policy alive when
> + * a CPU is hotplugged out.
> + */
> +static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
> +{
> + return 0;
> +}
I am not sure if doing nothing here will cause issues. In my view, to be safe,
we should perform the actions found in cppc_cpufreq_cpu_exit() here, except
cppc_cpufreq_put_cpu_data().
> +
> +/*
> + * Re-enable CPPC when the policy's CPU comes back online, since the platform
> + * may have disabled it while the CPU was offline.
> + */
> +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%d (%d)\n", cpu, ret);
> +
> + /*
> + * The platform may reset the controls while the CPU is offline, so
> + * recompute min/max, clamp desired_perf into range, and reprogram them.
> + */
> + 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_set_perf(cpu, &cpu_data->perf_ctrls);
> + if (ret)
> + pr_debug("Failed to reapply perf request on CPU%d (%d)\n",
> + cpu, ret);
> +
> + return 0;
> +}
> +
> static void cppc_cpufreq_cpu_exit(struct cpufreq_policy *policy)
> {
> struct cppc_cpudata *cpu_data = policy->driver_data;
> @@ -1034,6 +1076,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",
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug
2026-07-27 13:27 ` Christian Loehle
@ 2026-07-29 14:41 ` Sumit Gupta
0 siblings, 0 replies; 10+ messages in thread
From: Sumit Gupta @ 2026-07-29 14:41 UTC (permalink / raw)
To: Christian Loehle, rafael, viresh.kumar, pierre.gondois,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
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
On 27/07/26 18:57, Christian Loehle wrote:
> External email: Use caution opening links or attachments
>
>
> On 7/24/26 22:59, Sumit Gupta wrote:
>> Without online()/offline() callbacks, the cpufreq core fully tears
>> down a policy during exit() when its last online CPU is offlined, and
>> rebuilds it during init() when it 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.
>> This avoids re-reading the CPPC capabilities on every offline/online,
>> making CPU hotplug faster.
>>
>> From online(), re-enable CPPC, as the platform may have disabled it
>> while the CPU was offline. Since the policy is no longer rebuilt via
>> init(), online() also reprograms the CPPC performance controls
>> (desired/min/max).
>>
>> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
>> ---
>> drivers/cpufreq/cppc_cpufreq.c | 44 ++++++++++++++++++++++++++++++++++
>> 1 file changed, 44 insertions(+)
>>
>> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
>> index f6cea0c54dd9..6dc59f99d880 100644
>> --- a/drivers/cpufreq/cppc_cpufreq.c
>> +++ b/drivers/cpufreq/cppc_cpufreq.c
>> @@ -722,6 +722,48 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
>> return ret;
>> }
>>
>> +/*
>> + * With offline() defined, the cpufreq core keeps the policy alive when
>> + * a CPU is hotplugged out.
>> + */
>> +static int cppc_cpufreq_cpu_offline(struct cpufreq_policy *policy)
>> +{
>> + return 0;
>> +}
>> +
>> +/*
>> + * Re-enable CPPC when the policy's CPU comes back online, since the platform
>> + * may have disabled it while the CPU was offline.
>> + */
>> +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%d (%d)\n", cpu, ret);
> What's the intention of continuing restoring CPPC register values here?
Yes, there is no benefit in continuing the restore when
cppc_set_enable() fails with anything other than -EOPNOTSUPP.
I will stop the restore at that point and return 0 with a warning,
since propagating the error would cause the core to tear down
the policy.
>> +
>> + /*
>> + * The platform may reset the controls while the CPU is offline, so
>> + * recompute min/max, clamp desired_perf into range, and reprogram them.
>> + */
>> + 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_set_perf(cpu, &cpu_data->perf_ctrls);
>> + if (ret)
>> + pr_debug("Failed to reapply perf request on CPU%d (%d)\n",
>> + cpu, ret);
> I think cppc_set_perf() needs some prep first before using it on reset values.
> We assume that reset value may be Autonomous Mode on, right? So we must never
> write MIN>MAX and vice versa. I think we may just have to read and write
> the 'otherwise-offending' value first on reset.
You are right. cppc_set_perf() writes MIN before MAX, so restoring
a window whose MIN is above the reset MAX can briefly produce MIN > MAX
on registers not accessed through PCC. I will add a preparatory write
that raises MAX in that case, followed by the full restore:
----
/* min/max recomputed and desired_perf clamped, as posted */
cppc_get_perf(cpu, &cur);
if (cpu_data->perf_ctrls.min_perf > cur.max_perf) {
prep = cur; /* Rewrites DESIRED with its current value. */
prep.min_perf = 0; /* Zero leaves MIN unchanged. */
prep.max_perf = cpu_data->perf_ctrls.max_perf;
/* Raise MAX first. */
cppc_set_perf(cpu, &prep);
}
/* Then restore the full desired/min/max request. */
cppc_set_perf(cpu, &cpu_data->perf_ctrls);
----
The reverse transition does not need this extra write because the
existing MIN-before-MAX order writes the lower MIN first, so the window
only widens before MAX comes down.
Please let me know if you see any issue with this.
Thanks,
Sumit
....
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-29 14:41 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-24 21:59 [PATCH v3 0/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 1/4] cpufreq: CPPC: Keep the policy across CPU hotplug Sumit Gupta
2026-07-27 13:27 ` Christian Loehle
2026-07-29 14:41 ` Sumit Gupta
2026-07-28 8:41 ` zhenglifeng (A)
2026-07-24 21:59 ` [PATCH v3 2/4] ACPI: CPPC: Make autonomous selection helpers take a u64 Sumit Gupta
2026-07-24 21:59 ` [PATCH v3 3/4] cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload Sumit Gupta
2026-07-27 13:15 ` Christian Loehle
2026-07-24 21:59 ` [PATCH v3 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
2026-07-27 13:45 ` Christian Loehle
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox