public inbox for linux-pm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] cpufreq: CPPC: add autonomous mode boot parameter support
@ 2026-03-17 15:10 Sumit Gupta
  2026-03-24 18:18 ` Pierre Gondois
  0 siblings, 1 reply; 2+ messages in thread
From: Sumit Gupta @ 2026-03-17 15:10 UTC (permalink / raw)
  To: rafael, viresh.kumar, pierre.gondois, ionela.voinescu,
	zhenglifeng1, zhanjie9, corbet, skhan, rdunlap, mario.limonciello,
	linux-pm, linux-doc, linux-kernel
  Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
	nhartman, mochs, bbasu, sumitg

Add kernel boot parameter 'cppc_cpufreq.auto_sel_mode' to enable CPPC
autonomous performance selection on all CPUs at system startup without
requiring runtime sysfs manipulation. When autonomous mode is enabled,
the hardware automatically adjusts CPU performance based on workload
demands using Energy Performance Preference (EPP) hints.

When auto_sel_mode=1:
- Configure all CPUs for autonomous operation on first init
- Set EPP to performance preference (0x0)
- Use HW min/max when set; otherwise program from policy limits (caps)
- Clamp desired_perf to bounds before enabling autonomous mode
- Hardware controls frequency instead of the OS governor

The boot parameter is applied only during first policy initialization.
On hotplug, skip applying it so that the user's runtime sysfs
configuration is preserved.

Reviewed-by: Randy Dunlap <rdunlap@infradead.org> (Documentation)
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
Part 1 [1] of this series was applied for 7.1 and present in next.
Sending this patch as reworked version of 'patch 11' from [2] based
on next.

[1] https://lore.kernel.org/lkml/20260206142658.72583-1-sumitg@nvidia.com/
[2] https://lore.kernel.org/lkml/20251223121307.711773-1-sumitg@nvidia.com/
---
 .../admin-guide/kernel-parameters.txt         | 13 +++
 drivers/cpufreq/cppc_cpufreq.c                | 84 +++++++++++++++++--
 2 files changed, 92 insertions(+), 5 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index fa6171b5fdd5..de4b4c89edfe 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1060,6 +1060,19 @@ Kernel parameters
 			policy to use. This governor must be registered in the
 			kernel before the cpufreq driver probes.
 
+	cppc_cpufreq.auto_sel_mode=
+			[CPU_FREQ] Enable ACPI CPPC autonomous performance
+			selection. When enabled, hardware automatically adjusts
+			CPU frequency on all CPUs based on workload demands.
+			In Autonomous mode, Energy Performance Preference (EPP)
+			hints guide hardware toward performance (0x0) or energy
+			efficiency (0xff).
+			Requires ACPI CPPC autonomous selection register support.
+			Format: <bool>
+			Default: 0 (disabled)
+			0: use cpufreq governors
+			1: enable if supported by hardware
+
 	cpu_init_udelay=N
 			[X86,EARLY] Delay for N microsec between assert and de-assert
 			of APIC INIT to start processors.  This delay occurs
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 5dfb109cf1f4..49c148b2a0a4 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -28,6 +28,9 @@
 
 static struct cpufreq_driver cppc_cpufreq_driver;
 
+/* Autonomous Selection boot parameter */
+static bool auto_sel_mode;
+
 #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
 static enum {
 	FIE_UNSET = -1,
@@ -708,11 +711,74 @@ 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;
 
-	ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
-	if (ret) {
-		pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
-			 caps->highest_perf, cpu, ret);
-		goto out;
+	/*
+	 * Enable autonomous mode on first init if boot param is set.
+	 * Check last_governor to detect first init and skip if auto_sel
+	 * is already enabled.
+	 */
+	if (auto_sel_mode && policy->last_governor[0] == '\0' &&
+	    !cpu_data->perf_ctrls.auto_sel) {
+		/* Enable CPPC - optional register, some platforms need it */
+		ret = cppc_set_enable(cpu, true);
+		if (ret && ret != -EOPNOTSUPP)
+			pr_warn("Failed to enable CPPC for CPU%d (%d)\n", cpu, ret);
+
+		/*
+		 * Prefer HW min/max_perf when set; otherwise program from
+		 * policy limits derived earlier from caps.
+		 * Clamp desired_perf to bounds and sync policy->cur.
+		 */
+		if (!cpu_data->perf_ctrls.min_perf || !cpu_data->perf_ctrls.max_perf)
+			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);
+
+		policy->cur = cppc_perf_to_khz(caps,
+					       cpu_data->perf_ctrls.desired_perf);
+
+		/* EPP is optional - some platforms may not support it */
+		ret = cppc_set_epp(cpu, CPPC_EPP_PERFORMANCE_PREF);
+		if (ret && ret != -EOPNOTSUPP)
+			pr_warn("Failed to set EPP for CPU%d (%d)\n", cpu, ret);
+		else if (!ret)
+			cpu_data->perf_ctrls.energy_perf = CPPC_EPP_PERFORMANCE_PREF;
+
+		ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
+		if (ret) {
+			pr_debug("Err setting perf for autonomous mode CPU:%d ret:%d\n",
+				 cpu, ret);
+			goto out;
+		}
+
+		ret = cppc_set_auto_sel(cpu, true);
+		if (ret && ret != -EOPNOTSUPP) {
+			pr_warn("Failed autonomous config for CPU%d (%d)\n",
+				cpu, ret);
+			goto out;
+		}
+		if (!ret)
+			cpu_data->perf_ctrls.auto_sel = true;
+	}
+
+	if (cpu_data->perf_ctrls.auto_sel) {
+		/* Sync policy limits from HW when autonomous mode is active */
+		policy->min = cppc_perf_to_khz(caps,
+					       cpu_data->perf_ctrls.min_perf ?:
+					       caps->lowest_nonlinear_perf);
+		policy->max = cppc_perf_to_khz(caps,
+					       cpu_data->perf_ctrls.max_perf ?:
+					       caps->nominal_perf);
+	} else {
+		/* Normal mode: governors control frequency */
+		ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
+		if (ret) {
+			pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
+				 caps->highest_perf, cpu, ret);
+			goto out;
+		}
 	}
 
 	cppc_cpufreq_cpu_fie_init(policy);
@@ -1038,10 +1104,18 @@ static int __init cppc_cpufreq_init(void)
 
 static void __exit cppc_cpufreq_exit(void)
 {
+	unsigned int cpu;
+
+	for_each_present_cpu(cpu)
+		cppc_set_auto_sel(cpu, false);
+
 	cpufreq_unregister_driver(&cppc_cpufreq_driver);
 	cppc_freq_invariance_exit();
 }
 
+module_param(auto_sel_mode, bool, 0444);
+MODULE_PARM_DESC(auto_sel_mode, "Enable CPPC autonomous performance selection at boot");
+
 module_exit(cppc_cpufreq_exit);
 MODULE_AUTHOR("Ashwin Chaugule");
 MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");
-- 
2.34.1


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

* Re: [PATCH] cpufreq: CPPC: add autonomous mode boot parameter support
  2026-03-17 15:10 [PATCH] cpufreq: CPPC: add autonomous mode boot parameter support Sumit Gupta
@ 2026-03-24 18:18 ` Pierre Gondois
  0 siblings, 0 replies; 2+ messages in thread
From: Pierre Gondois @ 2026-03-24 18:18 UTC (permalink / raw)
  To: Sumit Gupta
  Cc: linux-tegra, linux-kernel, linux-doc, zhenglifeng1, treding,
	viresh.kumar, jonathanh, vsethi, ionela.voinescu, ksitaraman,
	sanjayc, zhanjie9, nhartman, corbet, mochs, skhan, bbasu, rdunlap,
	linux-pm, mario.limonciello, rafael

Hello Sumit,

On 3/17/26 16:10, Sumit Gupta wrote:
> Add kernel boot parameter 'cppc_cpufreq.auto_sel_mode' to enable CPPC
> autonomous performance selection on all CPUs at system startup without
> requiring runtime sysfs manipulation. When autonomous mode is enabled,
> the hardware automatically adjusts CPU performance based on workload
> demands using Energy Performance Preference (EPP) hints.
>
> When auto_sel_mode=1:
> - Configure all CPUs for autonomous operation on first init
> - Set EPP to performance preference (0x0)
> - Use HW min/max when set; otherwise program from policy limits (caps)
> - Clamp desired_perf to bounds before enabling autonomous mode
> - Hardware controls frequency instead of the OS governor
>
> The boot parameter is applied only during first policy initialization.
> On hotplug, skip applying it so that the user's runtime sysfs
> configuration is preserved.
>
> Reviewed-by: Randy Dunlap <rdunlap@infradead.org> (Documentation)
> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
> ---
> Part 1 [1] of this series was applied for 7.1 and present in next.
> Sending this patch as reworked version of 'patch 11' from [2] based
> on next.
>
> [1] https://lore.kernel.org/lkml/20260206142658.72583-1-sumitg@nvidia.com/
> [2] https://lore.kernel.org/lkml/20251223121307.711773-1-sumitg@nvidia.com/
> ---
>   .../admin-guide/kernel-parameters.txt         | 13 +++
>   drivers/cpufreq/cppc_cpufreq.c                | 84 +++++++++++++++++--
>   2 files changed, 92 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index fa6171b5fdd5..de4b4c89edfe 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -1060,6 +1060,19 @@ Kernel parameters
>   			policy to use. This governor must be registered in the
>   			kernel before the cpufreq driver probes.
>   
> +	cppc_cpufreq.auto_sel_mode=
> +			[CPU_FREQ] Enable ACPI CPPC autonomous performance
> +			selection. When enabled, hardware automatically adjusts
> +			CPU frequency on all CPUs based on workload demands.
> +			In Autonomous mode, Energy Performance Preference (EPP)
> +			hints guide hardware toward performance (0x0) or energy
> +			efficiency (0xff).
> +			Requires ACPI CPPC autonomous selection register support.
> +			Format: <bool>
> +			Default: 0 (disabled)
> +			0: use cpufreq governors
> +			1: enable if supported by hardware
> +
>   	cpu_init_udelay=N
>   			[X86,EARLY] Delay for N microsec between assert and de-assert
>   			of APIC INIT to start processors.  This delay occurs
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index 5dfb109cf1f4..49c148b2a0a4 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -28,6 +28,9 @@
>   
>   static struct cpufreq_driver cppc_cpufreq_driver;
>   
> +/* Autonomous Selection boot parameter */
> +static bool auto_sel_mode;
> +
>   #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
>   static enum {
>   	FIE_UNSET = -1,
> @@ -708,11 +711,74 @@ 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;
>   
> -	ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
> -	if (ret) {
> -		pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
> -			 caps->highest_perf, cpu, ret);
> -		goto out;
> +	/*
> +	 * Enable autonomous mode on first init if boot param is set.
> +	 * Check last_governor to detect first init and skip if auto_sel
> +	 * is already enabled.
> +	 */
If the goal is to set autosel only once at the driver init,
shouldn't this be done in cppc_cpufreq_init() ?
I understand that cpu_data doesn't exist yet in
cppc_cpufreq_init(), but this seems more appropriate to do
it there IMO.

This means the cpudata should be updated accordingly
in this cppc_cpufreq_cpu_init() function.

> +	if (auto_sel_mode && policy->last_governor[0] == '\0' &&
> +	    !cpu_data->perf_ctrls.auto_sel) {
> +		/* Enable CPPC - optional register, some platforms need it */
The documentation of the CPPC Enable Register is subject to
interpretation, but IIUC the field should be set to use the CPPC
controls, so I assume this should be set in cppc_cpufreq_init()
instead ?
> +		ret = cppc_set_enable(cpu, true);
> +		if (ret && ret != -EOPNOTSUPP)
> +			pr_warn("Failed to enable CPPC for CPU%d (%d)\n", cpu, ret);
> +
> +		/*
> +		 * Prefer HW min/max_perf when set; otherwise program from
> +		 * policy limits derived earlier from caps.
> +		 * Clamp desired_perf to bounds and sync policy->cur.
> +		 */
> +		if (!cpu_data->perf_ctrls.min_perf || !cpu_data->perf_ctrls.max_perf)

The function doesn't seem to exist.

> +			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);
> +
> +		policy->cur = cppc_perf_to_khz(caps,
> +					       cpu_data->perf_ctrls.desired_perf);
> +

Maybe this should also be done in cppc_cpufreq_init()
if the auto_sel_mode parameter is set ?

> +		/* EPP is optional - some platforms may not support it */
> +		ret = cppc_set_epp(cpu, CPPC_EPP_PERFORMANCE_PREF);
> +		if (ret && ret != -EOPNOTSUPP)
> +			pr_warn("Failed to set EPP for CPU%d (%d)\n", cpu, ret);
> +		else if (!ret)
> +			cpu_data->perf_ctrls.energy_perf = CPPC_EPP_PERFORMANCE_PREF;
> +
> +		ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
> +		if (ret) {
> +			pr_debug("Err setting perf for autonomous mode CPU:%d ret:%d\n",
> +				 cpu, ret);
> +			goto out;
> +		}
> +
> +		ret = cppc_set_auto_sel(cpu, true);
> +		if (ret && ret != -EOPNOTSUPP) {
> +			pr_warn("Failed autonomous config for CPU%d (%d)\n",
> +				cpu, ret);
> +			goto out;
> +		}
> +		if (!ret)
> +			cpu_data->perf_ctrls.auto_sel = true;
> +	}
> +
> +	if (cpu_data->perf_ctrls.auto_sel) {

There is a patchset ongoing which tries to remove
setting policy->min/max from driver initialization.
Indeed, these values are only temporarily valid,
until the governor override them.
It is not sure yet the patch will be accepted though.

https://lore.kernel.org/lkml/20260317101753.2284763-4-pierre.gondois@arm.com/


> +		/* Sync policy limits from HW when autonomous mode is active */
> +		policy->min = cppc_perf_to_khz(caps,
> +					       cpu_data->perf_ctrls.min_perf ?:
> +					       caps->lowest_nonlinear_perf);
> +		policy->max = cppc_perf_to_khz(caps,
> +					       cpu_data->perf_ctrls.max_perf ?:
> +					       caps->nominal_perf);
> +	} else {
> +		/* Normal mode: governors control frequency */
> +		ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
> +		if (ret) {
> +			pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
> +				 caps->highest_perf, cpu, ret);
> +			goto out;
> +		}
>   	}
>   
>   	cppc_cpufreq_cpu_fie_init(policy);
> @@ -1038,10 +1104,18 @@ static int __init cppc_cpufreq_init(void)
>   
>   static void __exit cppc_cpufreq_exit(void)
>   {
> +	unsigned int cpu;
> +
> +	for_each_present_cpu(cpu)
> +		cppc_set_auto_sel(cpu, false);

If the firmware has a default EPP value, it means that loading
and the unloading the driver will reset this default EPP value.
Maybe the initial EPP value and/or the auto_sel value should be
cached somewhere and restored on exit ?
I don't know if this is actually an issue, this is just to signal it.

> +
>   	cpufreq_unregister_driver(&cppc_cpufreq_driver);
>   	cppc_freq_invariance_exit();
>   }
>   
> +module_param(auto_sel_mode, bool, 0444);
> +MODULE_PARM_DESC(auto_sel_mode, "Enable CPPC autonomous performance selection at boot");
> +
>   module_exit(cppc_cpufreq_exit);
>   MODULE_AUTHOR("Ashwin Chaugule");
>   MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");

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

end of thread, other threads:[~2026-03-24 18:19 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17 15:10 [PATCH] cpufreq: CPPC: add autonomous mode boot parameter support Sumit Gupta
2026-03-24 18:18 ` Pierre Gondois

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