From: Pierre Gondois <pierre.gondois@arm.com>
To: Sumit Gupta <sumitg@nvidia.com>,
rafael@kernel.org, viresh.kumar@linaro.org,
christian.loehle@arm.com, ionela.voinescu@arm.com,
zhenglifeng1@huawei.com, zhanjie9@hisilicon.com, lenb@kernel.org,
ray.huang@amd.com, mario.limonciello@amd.com, perry.yuan@amd.com,
kprateek.nayak@amd.com, linux-kernel@vger.kernel.org,
linux-pm@vger.kernel.org, linux-acpi@vger.kernel.org,
acpica-devel@lists.linux.dev, linux-tegra@vger.kernel.org
Cc: treding@nvidia.com, jonathanh@nvidia.com, vsethi@nvidia.com,
ksitaraman@nvidia.com, sanjayc@nvidia.com, mochs@nvidia.com,
bbasu@nvidia.com
Subject: Re: [PATCH v5 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume
Date: Mon, 28 Sep 2026 14:21:04 +0200 [thread overview]
Message-ID: <e6ef3dd2-c2dc-4156-b5d5-35cad9c524f2@arm.com> (raw)
In-Reply-To: <20260916103820.1760297-5-sumitg@nvidia.com>
On 9/16/26 12:38, Sumit Gupta wrote:
> 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;
> +
Shouldn't we also request the lowest freq when calling suspend ?
This would make suspend/offline() function look similar aswell
> + 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);
I think there is something raised by sashiko:
https://sashiko.dev/#/patchset/20260916103820.1760297-1-sumitg%40nvidia.com
about the fact that fie is init using policy->cpus and exits using
policy->related_cpus. Is it possible to check ?
> +}
> +
> 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",
next prev parent reply other threads:[~2026-09-28 12:21 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
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-28 12:20 ` Pierre Gondois
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-28 12:21 ` Pierre Gondois
2026-09-16 10:38 ` [PATCH v5 4/4] cpufreq: CPPC: Preserve OSPM-set registers across suspend/resume Sumit Gupta
2026-09-28 12:21 ` Pierre Gondois [this message]
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
2026-09-25 19:23 ` Rafael J. Wysocki (Intel)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e6ef3dd2-c2dc-4156-b5d5-35cad9c524f2@arm.com \
--to=pierre.gondois@arm.com \
--cc=acpica-devel@lists.linux.dev \
--cc=bbasu@nvidia.com \
--cc=christian.loehle@arm.com \
--cc=ionela.voinescu@arm.com \
--cc=jonathanh@nvidia.com \
--cc=kprateek.nayak@amd.com \
--cc=ksitaraman@nvidia.com \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=mario.limonciello@amd.com \
--cc=mochs@nvidia.com \
--cc=perry.yuan@amd.com \
--cc=rafael@kernel.org \
--cc=ray.huang@amd.com \
--cc=sanjayc@nvidia.com \
--cc=sumitg@nvidia.com \
--cc=treding@nvidia.com \
--cc=viresh.kumar@linaro.org \
--cc=vsethi@nvidia.com \
--cc=zhanjie9@hisilicon.com \
--cc=zhenglifeng1@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®