Re: [PATCH v4 2/2] ACPI: CPPC: Add ospm_nominal_perf support
"Rafael J. Wysocki" <[email protected]> Mon, 1 Jun 2026 19:37:45 +0200
| Newsgroups | dev.linux.lists.acpica-devel,org.kernel.vger.linux-acpi,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm |
|---|---|
| Message-ID | <CAJZ5v0icPAmaiThjgUTxWRymNGBQFarodurJhODFOkLKpVwtOQ@mail.gmail.com> |
On Wed, May 27, 2026 at 9:47 PM Sumit Gupta <[email protected]> wrote: > > Expose the OSPM Nominal Performance register (ACPI 6.6, Section > 8.4.6.1.2.6), which conveys the desired nominal performance level > at which the platform may run. Unlike the existing read-only > Nominal Performance register, it is writable and lets OSPM > request a lower nominal level than the platform-reported nominal. > The platform classifies performance above this level as boosted > and below as throttled for its power/thermal decisions. > > It is exposed as a per-policy cpufreq sysfs attribute in kHz, to > match the cpufreq sysfs unit convention: > > /sys/devices/system/cpu/cpufreq/policyN/ospm_nominal_freq > > The attribute is documented in > Documentation/ABI/testing/sysfs-devices-system-cpu. > > Writes are converted to perf via cppc_khz_to_perf(), validated > against [Lowest Performance, Nominal Performance], and applied to > every CPU in policy->cpus. > > The register is write-only; the kernel caches the last written > value in struct cppc_cpudata for sysfs readback (returns 0 until > userspace writes a value). > > Signed-off-by: Sumit Gupta <[email protected]> There is some sashiko.dev feedback on this one that is valid AFAICS: https://sashiko.dev/#/patchset/20260527194626.185286-1-sumitg%40nvidia.com > --- > .../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ > drivers/acpi/cppc_acpi.c | 35 +++++++++++ > drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ > include/acpi/cppc_acpi.h | 12 ++++ > 4 files changed, 124 insertions(+) > > diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu > index 82d10d556cc8..ac1bf1b89ac4 100644 > --- a/Documentation/ABI/testing/sysfs-devices-system-cpu > +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu > @@ -346,6 +346,23 @@ Description: Performance Limited > > This file is only present if the cppc-cpufreq driver is in use. > > +What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq > +Date: May 2026 > +Contact: [email protected] > +Description: OSPM Nominal Performance (kHz) > + > + OSPM uses this attribute to request a nominal performance > + level lower than the platform-reported nominal. The > + platform treats performance above this level as boost > + and below as throttle for power and thermal decisions. > + > + Read returns the last written value in kHz, or 0 if no > + value has been written. Write a kHz value in the range > + [lowest_freq, nominal_freq]. > + > + This file is only present if the cppc-cpufreq driver is > + in use. > + > What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1} > Date: August 2008 > KernelVersion: 2.6.27 > diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c > index c76cfafa3589..ad6ece16c30d 100644 > --- a/drivers/acpi/cppc_acpi.c > +++ b/drivers/acpi/cppc_acpi.c > @@ -1682,6 +1682,41 @@ int cppc_set_epp(int cpu, u64 epp_val) > } > EXPORT_SYMBOL_GPL(cppc_set_epp); > > +/** > + * cppc_set_ospm_nominal_perf() - Write OSPM Nominal Performance register. > + * @cpu: CPU on which to write register. > + * @ospm_nominal_perf: Value to write to the OSPM Nominal Performance register. > + * > + * OSPM Nominal Performance conveys the desired nominal performance level > + * at which the platform may run. Per ACPI 6.6, s8.4.6.1.2.6, the value > + * must lie within [Lowest Performance, Nominal Performance] and may be > + * set independently of Minimum, Maximum and Desired performance. > + * > + * Return: 0 on success or negative error code. > + */ > +int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf) > +{ > + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); > + struct cppc_perf_caps caps; > + int ret; > + > + if (!cpc_desc) { > + pr_debug("No CPC descriptor for CPU:%d\n", cpu); > + return -ENODEV; > + } > + > + ret = cppc_get_perf_caps(cpu, &caps); > + if (ret) > + return ret; > + > + if (ospm_nominal_perf < caps.lowest_perf || > + ospm_nominal_perf > caps.nominal_perf) > + return -EINVAL; > + > + return cppc_set_reg_val(cpu, OSPM_NOMINAL_PERF, ospm_nominal_perf); > +} > +EXPORT_SYMBOL_GPL(cppc_set_ospm_nominal_perf); > + > /** > * cppc_get_auto_act_window() - Read autonomous activity window register. > * @cpu: CPU from which to read register. > diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c > index 15a728dea911..5c54af1655b5 100644 > --- a/drivers/cpufreq/cppc_cpufreq.c > +++ b/drivers/cpufreq/cppc_cpufreq.c > @@ -1139,11 +1139,70 @@ static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited) > CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited_filtered, > cppc_set_perf_limited) > > +static ssize_t show_ospm_nominal_freq(struct cpufreq_policy *policy, char *buf) > +{ > + struct cppc_cpudata *cpu_data = policy->driver_data; > + unsigned int freq_khz; > + > + if (!cpu_data->ospm_nominal_perf_set) > + return sysfs_emit(buf, "0\n"); > + > + freq_khz = cppc_perf_to_khz(&cpu_data->perf_caps, > + cpu_data->ospm_nominal_perf); > + return sysfs_emit(buf, "%u\n", freq_khz); > +} > + > +static ssize_t store_ospm_nominal_freq(struct cpufreq_policy *policy, > + const char *buf, size_t count) > +{ > + struct cppc_cpudata *cpu_data = policy->driver_data; > + bool prev_set = cpu_data->ospm_nominal_perf_set; > + u32 prev_perf = cpu_data->ospm_nominal_perf; > + unsigned int sib, freq_khz, failing_cpu = 0; > + u32 perf; > + int ret; > + > + ret = kstrtouint(buf, 0, &freq_khz); > + if (ret) > + return ret; > + > + perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz); > + > + for_each_cpu(sib, policy->cpus) { > + ret = cppc_set_ospm_nominal_perf(sib, perf); > + if (ret) { > + failing_cpu = sib; > + goto rollback; > + } > + } > + > + cpu_data->ospm_nominal_perf = perf; > + cpu_data->ospm_nominal_perf_set = true; > + return count; > + > +rollback: > + /* > + * Restore the previous value on siblings already updated. > + * for_each_cpu() iterates in CPU-id order, so siblings before > + * @failing_cpu were updated successfully. Skip restore when > + * there is no prior known-good value (first-ever write failed). > + */ > + if (prev_set) { > + for_each_cpu(sib, policy->cpus) { > + if (sib == failing_cpu) > + break; > + cppc_set_ospm_nominal_perf(sib, prev_perf); > + } > + } > + return ret; > +} > + > cpufreq_freq_attr_ro(freqdomain_cpus); > cpufreq_freq_attr_rw(auto_select); > cpufreq_freq_attr_rw(auto_act_window); > cpufreq_freq_attr_rw(energy_performance_preference_val); > cpufreq_freq_attr_rw(perf_limited); > +cpufreq_freq_attr_rw(ospm_nominal_freq); > > static struct freq_attr *cppc_cpufreq_attr[] = { > &freqdomain_cpus, > @@ -1151,6 +1210,7 @@ static struct freq_attr *cppc_cpufreq_attr[] = { > &auto_act_window, > &energy_performance_preference_val, > &perf_limited, > + &ospm_nominal_freq, > NULL, > }; > > diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h > index 9b18fb9aab7c..14c6d5d0ac12 100644 > --- a/include/acpi/cppc_acpi.h > +++ b/include/acpi/cppc_acpi.h > @@ -154,6 +154,13 @@ struct cppc_cpudata { > struct cppc_perf_fb_ctrs perf_fb_ctrs; > unsigned int shared_type; > cpumask_var_t shared_cpu_map; > + /* > + * Cached OSPM Nominal Performance value (write-only register). > + * ospm_nominal_perf_set is true once userspace has written, so an > + * unwritten cache is distinguishable from a valid 0 perf write. > + */ > + u32 ospm_nominal_perf; > + bool ospm_nominal_perf_set; > }; > > #ifdef CONFIG_ACPI_CPPC_LIB > @@ -181,6 +188,7 @@ extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val); > extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf); > extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable); > extern int cppc_set_epp(int cpu, u64 epp_val); > +extern int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf); > 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); > @@ -267,6 +275,10 @@ static inline int cppc_set_epp(int cpu, u64 epp_val) > { > return -EOPNOTSUPP; > } > +static inline int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf) > +{ > + return -EOPNOTSUPP; > +} > static inline int cppc_get_auto_act_window(int cpu, u64 *auto_act_window) > { > return -EOPNOTSUPP; > -- > 2.34.1 >