Re: [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support
Sumit Gupta <[email protected]> Tue, 4 Aug 2026 21:45:05 +0530
| Newsgroups | org.kernel.vger.linux-tegra,dev.linux.lists.acpica-devel,org.kernel.vger.linux-acpi,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm |
|---|---|
| Message-ID | <[email protected]> |
Hi Zhongqiu, On 28/07/26 18:54, Zhongqiu Han wrote: > External email: Use caution opening links or attachments > > > Hello Sumit, > > On 7/18/2026 5:53 AM, Sumit Gupta 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/cpuX/cpufreq/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 >> the policy->cpu. The register is assumed shared across the >> policy->cpus. >> >> On read, the current register value is returned, or >> "<unsupported>" if the platform does not implement the register. >> >> Also add the register to the OSPM-set register save/restore >> table, so its value survives CPU hotplug and reverts to the >> firmware value on driver unload, like the other registers in >> the table. >> >> Signed-off-by: Sumit Gupta <[email protected]> >> --- >> .../ABI/testing/sysfs-devices-system-cpu | 26 ++++++++++ >> drivers/acpi/cppc_acpi.c | 32 +++++++++++++ >> drivers/cpufreq/cppc_cpufreq.c | 47 +++++++++++++++++++ >> include/acpi/cppc_acpi.h | 10 ++++ >> 4 files changed, 115 insertions(+) >> >> diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu >> b/Documentation/ABI/testing/sysfs-devices-system-cpu >> index 82d10d556cc8..a8d592c08823 100644 >> --- a/Documentation/ABI/testing/sysfs-devices-system-cpu >> +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu >> @@ -346,6 +346,32 @@ 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 current value in kHz, or "<unsupported>" >> + if the platform does not implement the register. Write a >> + kHz value in the range [lowest_freq, nominal_freq]. >> + >> + Note that tasks may be migrated from one CPU to another >> + by the scheduler's load-balancing algorithm, and if >> + different OSPM Nominal Performance values are set for >> + those CPUs (through different cpufreq policies), that may >> + lead to undesirable outcomes. To avoid such issues it is >> + better to set the same value across all policies, or to >> + pin every task potentially sensitive to it to a specific >> + CPU. >> + >> + 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 a7fec6c93178..681d4fd40c11 100644 >> --- a/drivers/acpi/cppc_acpi.c >> +++ b/drivers/acpi/cppc_acpi.c >> @@ -1685,6 +1685,38 @@ 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. The >> + * caller is responsible for validating the range. >> + * >> + * Return: 0 on success or negative error code. >> + */ >> +int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf) >> +{ >> + return cppc_set_reg_val(cpu, OSPM_NOMINAL_PERF, >> ospm_nominal_perf); >> +} >> +EXPORT_SYMBOL_GPL(cppc_set_ospm_nominal_perf); >> + >> +/** >> + * cppc_get_ospm_nominal_perf() - Read OSPM Nominal Performance >> register. >> + * @cpu: CPU from which to read register. >> + * @ospm_nominal_perf: Pointer to store the OSPM Nominal Performance >> value. >> + * >> + * Return: 0 on success or negative error code. >> + */ >> +int cppc_get_ospm_nominal_perf(int cpu, u64 *ospm_nominal_perf) >> +{ >> + return cppc_get_reg_val(cpu, OSPM_NOMINAL_PERF, >> ospm_nominal_perf); >> +} >> +EXPORT_SYMBOL_GPL(cppc_get_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 9c88512d635c..eb6746810fa6 100644 >> --- a/drivers/cpufreq/cppc_cpufreq.c >> +++ b/drivers/cpufreq/cppc_cpufreq.c >> @@ -37,6 +37,7 @@ enum cppc_saved_reg_id { >> CPPC_SAVED_AUTO_SEL, >> CPPC_SAVED_EPP, >> CPPC_SAVED_AUTO_ACT_WINDOW, >> + CPPC_SAVED_OSPM_NOMINAL_PERF, >> CPPC_NR_SAVED_REGS, >> }; >> >> @@ -55,6 +56,9 @@ static const struct cppc_saved_reg >> cppc_saved_regs[CPPC_NR_SAVED_REGS] = { >> [CPPC_SAVED_AUTO_ACT_WINDOW] = { >> cppc_get_auto_act_window, cppc_set_auto_act_window, >> }, >> + [CPPC_SAVED_OSPM_NOMINAL_PERF] = { >> + cppc_get_ospm_nominal_perf, cppc_set_ospm_nominal_perf, >> + }, >> }; >> >> /* >> @@ -1166,11 +1170,53 @@ 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; >> + u64 perf; >> + int ret; >> + >> + ret = cppc_get_ospm_nominal_perf(policy->cpu, &perf); >> + if (ret == -EOPNOTSUPP) >> + return sysfs_emit(buf, "<unsupported>\n"); >> + if (ret) >> + return ret; >> + >> + return sysfs_emit(buf, "%u\n", >> + cppc_perf_to_khz(&cpu_data->perf_caps, perf)); > > In patch 2/2, cppc_cpufreq_get_effective_nominal() reads the OSPM > Nominal into ospm_nominal via the output pointer of > cppc_get_ospm_nominal_perf(policy->cpu, &ospm_nominal), then checks > ospm_nominal for zero ("A zero value means OSPM has not selected a > nominal level") and substitutes the platform Nominal in that case. > > However, show_ospm_nominal_freq() passes the value read through the same > output pointer straight into cppc_perf_to_khz() without the equivalent > zero check. This looks a bit inconsistent — is it intentional, or > should show() apply the same "zero means not selected" handling? > Thanks for pointing this out. In v7, I will make ospm_nominal_freq as write-only and remove sysfs show() and cppc_get_ospm_nominal_perf(), eliminating this inconsistency. The effective nominal calculation will use the last successfully written value, falling back to the platform Nominal Performance if none has been written. Thanks, Sumit > >> +} >> + >> +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; >> + unsigned int freq_khz; >> + 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); >> + if (perf < cpu_data->perf_caps.lowest_perf || >> + perf > cpu_data->perf_caps.nominal_perf) >> + return -EINVAL; >> + >> + /* The register is assumed shared across the policy's CPUs. */ >> + ret = cppc_set_ospm_nominal_perf(policy->cpu, perf); >> + if (ret) >> + return ret; >> + >> + return count; >> +} >> + >> 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, >> @@ -1178,6 +1224,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 cd07e1e92bf4..4c9e59643cc0 100644 >> --- a/include/acpi/cppc_acpi.h >> +++ b/include/acpi/cppc_acpi.h >> @@ -180,6 +180,8 @@ 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_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); >> @@ -268,6 +270,14 @@ 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_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; > > > -- > Thx and BRs, > Zhongqiu Han