| Message ID | 20251223121307.711773-12-sumitg@nvidia.com |
|---|---|
| State | Handled Elsewhere |
| Headers | show |
| Series | Enhanced autonomous selection and improvements | expand |
On 2025/12/23 20:13, 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: > - All CPUs are configured for autonomous operation during init > - EPP is set to performance preference (0x0) by default > - Min/max performance bounds use defaults or already set values > - CPU frequency scaling is handled by hardware instead of OS governor > > The boot parameter is applied only during first policy initialization. > User's runtime sysfs configuration is preserved across hotplug. > > For Documentation/: > Reviewed-by: Randy Dunlap <rdunlap@infradead.org> > Signed-off-by: Sumit Gupta <sumitg@nvidia.com> > --- > .../admin-guide/kernel-parameters.txt | 13 +++ > drivers/cpufreq/cppc_cpufreq.c | 85 +++++++++++++++++-- > 2 files changed, 90 insertions(+), 8 deletions(-) > > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt > index aab72efa1acd..450f0b0225dc 100644 > --- a/Documentation/admin-guide/kernel-parameters.txt > +++ b/Documentation/admin-guide/kernel-parameters.txt > @@ -1035,6 +1035,19 @@ Kernel parameters > Format: > <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>] > > + 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 > + > cpuidle.off=1 [CPU_IDLE] > disable the cpuidle sub-system > > diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c > index b3da263c18b0..8c6869e68504 100644 > --- a/drivers/cpufreq/cppc_cpufreq.c > +++ b/drivers/cpufreq/cppc_cpufreq.c > @@ -30,6 +30,9 @@ static struct cpufreq_driver cppc_cpufreq_driver; > > static DEFINE_MUTEX(cppc_cpufreq_update_autosel_config_lock); > > +/* Autonomous Selection boot parameter */ > +static bool auto_sel_mode; > + > #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE > static enum { > FIE_UNSET = -1, > @@ -643,11 +646,16 @@ static int cppc_cpufreq_set_mperf_limit(struct cpufreq_policy *policy, u64 val, > * cppc_cpufreq_update_autosel_config - Update autonomous selection config > * @policy: cpufreq policy > * @is_auto_sel: enable/disable autonomous selection > + * @epp_val: EPP value (used only if update_epp true) > + * @update_epp: whether to update EPP register > + * @update_policy: whether to update policy constraints > * > * Return: 0 on success, negative error code on failure > */ > static int cppc_cpufreq_update_autosel_config(struct cpufreq_policy *policy, > - bool is_auto_sel) > + bool is_auto_sel, u32 epp_val, > + bool update_epp, > + bool update_policy) cppc_cpufreq_set_mperf_limit() and cppc_cpufreq_update_autosel_config() have too much bool input param. Just break them down into several separate functions and call them only when needed. These two functions are now too hard to read. > { > struct cppc_cpudata *cpu_data = policy->driver_data; > struct cppc_perf_caps *caps = &cpu_data->perf_caps; > @@ -655,7 +663,6 @@ static int cppc_cpufreq_update_autosel_config(struct cpufreq_policy *policy, > u64 max_perf = caps->nominal_perf; > unsigned int cpu = policy->cpu; > bool update_reg = is_auto_sel; > - bool update_policy = true; > int ret; > > guard(mutex)(&cppc_cpufreq_update_autosel_config_lock); > @@ -685,6 +692,17 @@ static int cppc_cpufreq_update_autosel_config(struct cpufreq_policy *policy, > if (ret && ret != -EOPNOTSUPP) > return ret; > > + /* Update EPP register */ > + if (update_epp) { > + ret = cppc_set_epp(cpu, epp_val); > + if (ret && ret != -EOPNOTSUPP) { > + pr_warn("Failed to set EPP for CPU%d (%d)\n", cpu, ret); > + return ret; > + } > + if (!ret) > + cpu_data->perf_ctrls.energy_perf = epp_val; > + } > + > /* Update auto_sel register */ > ret = cppc_set_auto_sel(cpu, is_auto_sel); > if (ret && ret != -EOPNOTSUPP) { > @@ -816,11 +834,54 @@ 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) { > + if (ret == -EOPNOTSUPP) > + pr_debug("CPPC enable not supported CPU%d\n", > + cpu); > + else > + pr_warn("Failed enable CPPC CPU%d (%d)\n", > + cpu, ret); > + } > + > + /* > + * Enable autonomous mode; Pass false for update_policy to avoid > + * updating policy limits prematurely as they are not yet fully setup. > + */ > + ret = cppc_cpufreq_update_autosel_config(policy, > + true, /* is_auto_sel */ > + CPPC_EPP_PERFORMANCE_PREF, > + true, /* update_epp */ > + false); /* update_policy */ > + if (ret) > + pr_warn("Failed autonomous config CPU%d (%d)\n", > + cpu, ret); > + } > + > + /* If auto mode is enabled, sync policy limits with HW registers */ > + if (cpu_data->perf_ctrls.auto_sel) { > + 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 { > + /* Standard mode: governors control frequency */ > + ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); > + if (ret) { > + pr_debug("Err setting perf value:%d CPU:%d ret:%d\n", > + caps->highest_perf, cpu, ret); > + goto out; > + } > } > > cppc_cpufreq_cpu_fie_init(policy); > @@ -991,7 +1052,7 @@ static ssize_t store_auto_select(struct cpufreq_policy *policy, > if (ret) > return ret; > > - ret = cppc_cpufreq_update_autosel_config(policy, val); > + ret = cppc_cpufreq_update_autosel_config(policy, val, 0, false, true); > if (ret) > return ret; > > @@ -1253,10 +1314,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, 0000); > +MODULE_PARM_DESC(auto_sel_mode, "Enable Autonomous Performance Level Selection"); > + > module_exit(cppc_cpufreq_exit); > MODULE_AUTHOR("Ashwin Chaugule"); > MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");
On 26/12/25 13:33, zhenglifeng (A) wrote: > External email: Use caution opening links or attachments > > > On 2025/12/23 20:13, 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: >> - All CPUs are configured for autonomous operation during init >> - EPP is set to performance preference (0x0) by default >> - Min/max performance bounds use defaults or already set values >> - CPU frequency scaling is handled by hardware instead of OS governor >> >> The boot parameter is applied only during first policy initialization. >> User's runtime sysfs configuration is preserved across hotplug. >> >> For Documentation/: >> Reviewed-by: Randy Dunlap <rdunlap@infradead.org> >> Signed-off-by: Sumit Gupta <sumitg@nvidia.com> >> --- >> .../admin-guide/kernel-parameters.txt | 13 +++ >> drivers/cpufreq/cppc_cpufreq.c | 85 +++++++++++++++++-- >> 2 files changed, 90 insertions(+), 8 deletions(-) >> >> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt >> index aab72efa1acd..450f0b0225dc 100644 >> --- a/Documentation/admin-guide/kernel-parameters.txt >> +++ b/Documentation/admin-guide/kernel-parameters.txt >> @@ -1035,6 +1035,19 @@ Kernel parameters >> Format: >> <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>] >> >> + 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 >> + >> cpuidle.off=1 [CPU_IDLE] >> disable the cpuidle sub-system >> >> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c >> index b3da263c18b0..8c6869e68504 100644 >> --- a/drivers/cpufreq/cppc_cpufreq.c >> +++ b/drivers/cpufreq/cppc_cpufreq.c >> @@ -30,6 +30,9 @@ static struct cpufreq_driver cppc_cpufreq_driver; >> >> static DEFINE_MUTEX(cppc_cpufreq_update_autosel_config_lock); >> >> +/* Autonomous Selection boot parameter */ >> +static bool auto_sel_mode; >> + >> #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE >> static enum { >> FIE_UNSET = -1, >> @@ -643,11 +646,16 @@ static int cppc_cpufreq_set_mperf_limit(struct cpufreq_policy *policy, u64 val, >> * cppc_cpufreq_update_autosel_config - Update autonomous selection config >> * @policy: cpufreq policy >> * @is_auto_sel: enable/disable autonomous selection >> + * @epp_val: EPP value (used only if update_epp true) >> + * @update_epp: whether to update EPP register >> + * @update_policy: whether to update policy constraints >> * >> * Return: 0 on success, negative error code on failure >> */ >> static int cppc_cpufreq_update_autosel_config(struct cpufreq_policy *policy, >> - bool is_auto_sel) >> + bool is_auto_sel, u32 epp_val, >> + bool update_epp, >> + bool update_policy) > cppc_cpufreq_set_mperf_limit() and cppc_cpufreq_update_autosel_config() > have too much bool input param. Just break them down into several separate > functions and call them only when needed. These two functions are now too > hard to read. Sure, will break them and open code in v6. Thank you, Sumit Gupta ....
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index aab72efa1acd..450f0b0225dc 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1035,6 +1035,19 @@ Kernel parameters Format: <first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>] + 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 + cpuidle.off=1 [CPU_IDLE] disable the cpuidle sub-system diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index b3da263c18b0..8c6869e68504 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -30,6 +30,9 @@ static struct cpufreq_driver cppc_cpufreq_driver; static DEFINE_MUTEX(cppc_cpufreq_update_autosel_config_lock); +/* Autonomous Selection boot parameter */ +static bool auto_sel_mode; + #ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE static enum { FIE_UNSET = -1, @@ -643,11 +646,16 @@ static int cppc_cpufreq_set_mperf_limit(struct cpufreq_policy *policy, u64 val, * cppc_cpufreq_update_autosel_config - Update autonomous selection config * @policy: cpufreq policy * @is_auto_sel: enable/disable autonomous selection + * @epp_val: EPP value (used only if update_epp true) + * @update_epp: whether to update EPP register + * @update_policy: whether to update policy constraints * * Return: 0 on success, negative error code on failure */ static int cppc_cpufreq_update_autosel_config(struct cpufreq_policy *policy, - bool is_auto_sel) + bool is_auto_sel, u32 epp_val, + bool update_epp, + bool update_policy) { struct cppc_cpudata *cpu_data = policy->driver_data; struct cppc_perf_caps *caps = &cpu_data->perf_caps; @@ -655,7 +663,6 @@ static int cppc_cpufreq_update_autosel_config(struct cpufreq_policy *policy, u64 max_perf = caps->nominal_perf; unsigned int cpu = policy->cpu; bool update_reg = is_auto_sel; - bool update_policy = true; int ret; guard(mutex)(&cppc_cpufreq_update_autosel_config_lock); @@ -685,6 +692,17 @@ static int cppc_cpufreq_update_autosel_config(struct cpufreq_policy *policy, if (ret && ret != -EOPNOTSUPP) return ret; + /* Update EPP register */ + if (update_epp) { + ret = cppc_set_epp(cpu, epp_val); + if (ret && ret != -EOPNOTSUPP) { + pr_warn("Failed to set EPP for CPU%d (%d)\n", cpu, ret); + return ret; + } + if (!ret) + cpu_data->perf_ctrls.energy_perf = epp_val; + } + /* Update auto_sel register */ ret = cppc_set_auto_sel(cpu, is_auto_sel); if (ret && ret != -EOPNOTSUPP) { @@ -816,11 +834,54 @@ 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) { + if (ret == -EOPNOTSUPP) + pr_debug("CPPC enable not supported CPU%d\n", + cpu); + else + pr_warn("Failed enable CPPC CPU%d (%d)\n", + cpu, ret); + } + + /* + * Enable autonomous mode; Pass false for update_policy to avoid + * updating policy limits prematurely as they are not yet fully setup. + */ + ret = cppc_cpufreq_update_autosel_config(policy, + true, /* is_auto_sel */ + CPPC_EPP_PERFORMANCE_PREF, + true, /* update_epp */ + false); /* update_policy */ + if (ret) + pr_warn("Failed autonomous config CPU%d (%d)\n", + cpu, ret); + } + + /* If auto mode is enabled, sync policy limits with HW registers */ + if (cpu_data->perf_ctrls.auto_sel) { + 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 { + /* Standard mode: governors control frequency */ + ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); + if (ret) { + pr_debug("Err setting perf value:%d CPU:%d ret:%d\n", + caps->highest_perf, cpu, ret); + goto out; + } } cppc_cpufreq_cpu_fie_init(policy); @@ -991,7 +1052,7 @@ static ssize_t store_auto_select(struct cpufreq_policy *policy, if (ret) return ret; - ret = cppc_cpufreq_update_autosel_config(policy, val); + ret = cppc_cpufreq_update_autosel_config(policy, val, 0, false, true); if (ret) return ret; @@ -1253,10 +1314,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, 0000); +MODULE_PARM_DESC(auto_sel_mode, "Enable Autonomous Performance Level Selection"); + module_exit(cppc_cpufreq_exit); MODULE_AUTHOR("Ashwin Chaugule"); MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");