mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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",

  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®