* [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support
@ 2026-07-17 21:53 Sumit Gupta
2026-07-17 21:53 ` [PATCH v6 1/2] ACPI: " Sumit Gupta
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Sumit Gupta @ 2026-07-17 21:53 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, christian.loehle,
ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre,
linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra
Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu,
sumitg
This series adds support for the OSPM Nominal Performance register
(ACPI 6.6, Section 8.4.6.1.2.6) to the CPPC ACPI and cpufreq drivers.
Unlike the read-only Nominal Performance register, OSPM Nominal
Performance is writable and lets OSPM request a nominal level below
the platform-reported nominal. The platform treats performance above
this level as boost and below as throttle for its power and thermal
decisions.
Patch 1: adds the cppc_{get,set}_ospm_nominal_perf() helpers, a
per-policy cpufreq sysfs attribute (ospm_nominal_freq, in kHz), and
hooks the register into the OSPM-set save/restore table.
Patch 2: reflects the OSPM nominal in the cpufreq policy so that boost
and the frequency limits stay consistent with the register.
This series applies on top of the series
"cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload",
which provides the save/restore table that patch 1 hooks into:
https://lore.kernel.org/lkml/20260716153820.2007095-1-sumitg@nvidia.com/
v5[5] -> v6:
- New patch 2: reflect the OSPM nominal in the policy's boost state
and frequency limits.
- Patch 1:
- write only policy->cpu instead of looping over policy->cpus with
rollback. the register is treated as shared across a policy's CPUs.
- add the register to the OSPM-set save/restore table.
Sumit Gupta (2):
ACPI: CPPC: Add ospm_nominal_perf support
cpufreq: CPPC: Reflect ospm_nominal_perf in boost and limits
.../ABI/testing/sysfs-devices-system-cpu | 26 +++
drivers/acpi/cppc_acpi.c | 32 ++++
drivers/cpufreq/cppc_cpufreq.c | 166 +++++++++++++++++-
include/acpi/cppc_acpi.h | 10 ++
4 files changed, 226 insertions(+), 8 deletions(-)
v5: https://lore.kernel.org/lkml/20260615185934.2383514-1-sumitg@nvidia.com/
v4: https://lore.kernel.org/lkml/20260527194626.185286-1-sumitg@nvidia.com/
v3: https://lore.kernel.org/lkml/20260514194822.1841748-1-sumitg@nvidia.com/
v2: https://lore.kernel.org/lkml/20260430142430.755437-1-sumitg@nvidia.com/
v1: https://lore.kernel.org/lkml/20260427051823.280419-1-sumitg@nvidia.com/
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support 2026-07-17 21:53 [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta @ 2026-07-17 21:53 ` Sumit Gupta 2026-07-27 14:01 ` Christian Loehle 2026-07-28 13:24 ` Zhongqiu Han 2026-07-17 21:53 ` [PATCH v6 2/2] cpufreq: CPPC: Reflect ospm_nominal_perf in boost and limits Sumit Gupta 2026-07-27 13:27 ` [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Rafael J. Wysocki (Intel) 2 siblings, 2 replies; 10+ messages in thread From: Sumit Gupta @ 2026-07-17 21:53 UTC (permalink / raw) To: rafael, viresh.kumar, pierre.gondois, christian.loehle, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg 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 <sumitg@nvidia.com> --- .../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: linux-pm@vger.kernel.org +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)); +} + +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; -- 2.34.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support 2026-07-17 21:53 ` [PATCH v6 1/2] ACPI: " Sumit Gupta @ 2026-07-27 14:01 ` Christian Loehle 2026-07-27 17:49 ` Christian Loehle 2026-07-28 13:24 ` Zhongqiu Han 1 sibling, 1 reply; 10+ messages in thread From: Christian Loehle @ 2026-07-27 14:01 UTC (permalink / raw) To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu On 7/17/26 22:53, 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 <sumitg@nvidia.com> > --- > .../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: linux-pm@vger.kernel.org > +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); It's a write-only register, we need to track everything in the driver. > + > /** > * 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)); > +} > + > +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; ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support 2026-07-27 14:01 ` Christian Loehle @ 2026-07-27 17:49 ` Christian Loehle 2026-07-27 21:23 ` Christian Loehle 0 siblings, 1 reply; 10+ messages in thread From: Christian Loehle @ 2026-07-27 17:49 UTC (permalink / raw) To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu On 7/27/26 15:01, Christian Loehle wrote: > On 7/17/26 22:53, 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 <sumitg@nvidia.com> >> --- >> .../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: linux-pm@vger.kernel.org >> +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); > > It's a write-only register, we need to track everything in the driver. > So just reread Pierre's comments, TBH I don't see the point of ever reading it, even for sysfs reads, but I don't think reading it for cppc_cpufreq_get_effective_nominal() would be valid in any case? ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support 2026-07-27 17:49 ` Christian Loehle @ 2026-07-27 21:23 ` Christian Loehle 2026-08-04 16:12 ` Sumit Gupta 0 siblings, 1 reply; 10+ messages in thread From: Christian Loehle @ 2026-07-27 21:23 UTC (permalink / raw) To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu On 7/27/26 18:49, Christian Loehle wrote: > On 7/27/26 15:01, Christian Loehle wrote: >> On 7/17/26 22:53, 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 <sumitg@nvidia.com> >>> --- >>> .../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: linux-pm@vger.kernel.org >>> +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); >> >> It's a write-only register, we need to track everything in the driver. >> > > So just reread Pierre's comments, TBH I don't see the point of ever > reading it, even for sysfs reads, but I don't think > reading it for cppc_cpufreq_get_effective_nominal() would be valid > in any case? FWIW desired_perf was read/write up until ACPI 6.5 and only 6.6 marked it as write-only. I don't think we should be reading it either on platforms advertising 6.6. I will clarify and send a patch. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support 2026-07-27 21:23 ` Christian Loehle @ 2026-08-04 16:12 ` Sumit Gupta 0 siblings, 0 replies; 10+ messages in thread From: Sumit Gupta @ 2026-08-04 16:12 UTC (permalink / raw) To: Christian Loehle, rafael, viresh.kumar, pierre.gondois, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg On 28/07/26 02:53, Christian Loehle wrote: > External email: Use caution opening links or attachments > > > On 7/27/26 18:49, Christian Loehle wrote: >> On 7/27/26 15:01, Christian Loehle wrote: >>> On 7/17/26 22:53, 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 <sumitg@nvidia.com> >>>> --- >>>> .../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: linux-pm@vger.kernel.org >>>> +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); >>> It's a write-only register, we need to track everything in the driver. >>> >> So just reread Pierre's comments, TBH I don't see the point of ever >> reading it, even for sysfs reads, but I don't think >> reading it for cppc_cpufreq_get_effective_nominal() would be valid >> in any case? > FWIW desired_perf was read/write up until ACPI 6.5 and only 6.6 marked > it as write-only. I don't think we should be reading it either on > platforms advertising 6.6. > I will clarify and send a patch. Good catch that ACPI 6.6 makes Desired Performance write-only, and thanks for the patches preventing those reads. The same reasoning applies to OSPM Nominal Performance, so I will treat it as write-only: make ospm_nominal_freq write-only, remove show(), and drop cppc_get_ospm_nominal_perf(). Boost and policy limits will use the last value the driver successfully wrote, falling back to the platform reported Nominal Performance when nothing has been set. On unload, I will reset it to the platform Nominal Performance only if the driver wrote it during its lifetime. Otherwise the register is left untouched, since the pre-driver value cannot be read back. Thanks, Sumit ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support 2026-07-17 21:53 ` [PATCH v6 1/2] ACPI: " Sumit Gupta 2026-07-27 14:01 ` Christian Loehle @ 2026-07-28 13:24 ` Zhongqiu Han 2026-08-04 16:15 ` Sumit Gupta 1 sibling, 1 reply; 10+ messages in thread From: Zhongqiu Han @ 2026-07-28 13:24 UTC (permalink / raw) To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois, christian.loehle, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, zhongqiu.han 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 <sumitg@nvidia.com> > --- > .../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: linux-pm@vger.kernel.org > +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? > +} > + > +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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/2] ACPI: CPPC: Add ospm_nominal_perf support 2026-07-28 13:24 ` Zhongqiu Han @ 2026-08-04 16:15 ` Sumit Gupta 0 siblings, 0 replies; 10+ messages in thread From: Sumit Gupta @ 2026-08-04 16:15 UTC (permalink / raw) To: Zhongqiu Han, rafael, viresh.kumar, pierre.gondois, christian.loehle, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg 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 <sumitg@nvidia.com> >> --- >> .../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: linux-pm@vger.kernel.org >> +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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v6 2/2] cpufreq: CPPC: Reflect ospm_nominal_perf in boost and limits 2026-07-17 21:53 [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta 2026-07-17 21:53 ` [PATCH v6 1/2] ACPI: " Sumit Gupta @ 2026-07-17 21:53 ` Sumit Gupta 2026-07-27 13:27 ` [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Rafael J. Wysocki (Intel) 2 siblings, 0 replies; 10+ messages in thread From: Sumit Gupta @ 2026-07-17 21:53 UTC (permalink / raw) To: rafael, viresh.kumar, pierre.gondois, christian.loehle, ionela.voinescu, zhenglifeng1, zhanjie9, lenb, saket.dumbre, linux-kernel, linux-pm, linux-acpi, acpica-devel, linux-tegra Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu, sumitg OSPM Nominal Performance lets OSPM request a nominal level below the platform-reported nominal. Since boost is the range above nominal, lowering the nominal enlarges the boost range and drops the non-boost ceiling. cppc_cpufreq currently uses the platform nominal as the non-boost ceiling. Changing the OSPM nominal then leaves the policy limits unchanged, so the boost and non-boost ranges no longer match the register. Reflect the OSPM nominal in the cpufreq policy so that boost and the frequency limits stay consistent with the register: - Add cppc_cpufreq_get_effective_nominal(), which yields the OSPM Nominal Performance when set and the platform nominal otherwise. - Use it to derive cpuinfo.max_freq for the non-boost ceiling in init() and in set_boost() while boost is disabled. The cpufreq core includes a per-policy boost QoS request among the constraints that cap scaling_max_freq. It updates that request to match cpuinfo.max_freq, but only when boost is toggled. Writing ospm_nominal_freq changes cpuinfo.max_freq without toggling boost, so the request (boost_freq_req) is left stale and keeps scaling_max_freq at the old nominal. cppc_cpufreq_reflect_nominal() therefore updates the request directly when the nominal changes while boost is disabled. At boot, when highest_perf == nominal_perf there is no boost range, but lowering the OSPM nominal later from sysfs can create one if highest_perf > lowest_perf. Since the core registers its boost FREQ_QOS_MAX request at policy setup only when boost_supported is already set, set boost_supported in init() when the OSPM register is supported and such a range is possible. Boost can then be enabled once the nominal is lowered. Signed-off-by: Sumit Gupta <sumitg@nvidia.com> --- drivers/cpufreq/cppc_cpufreq.c | 119 ++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index eb6746810fa6..048bb567ec45 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -761,11 +761,63 @@ static void cppc_cpufreq_put_cpu_data(struct cpufreq_policy *policy) policy->driver_data = NULL; } +/** + * cppc_cpufreq_get_effective_nominal() - Get the effective nominal performance + * @policy: cpufreq policy associated with the CPU + * @nominal: Updated with the effective nominal performance + * @supported: Updated with whether OSPM Nominal Performance is supported. + * Pass NULL if not needed + * + * Use the OSPM Nominal Performance value when the register is supported and + * contains a nonzero value. Otherwise, use the platform-reported Nominal + * Performance. The resulting value is the non-boost performance ceiling. + * + * Return: 0 on success, or a negative error code if the register cannot be + * read or contains a value outside the supported performance range. + */ +static int cppc_cpufreq_get_effective_nominal(struct cpufreq_policy *policy, + u32 *nominal, bool *supported) +{ + struct cppc_cpudata *cpu_data = policy->driver_data; + struct cppc_perf_caps *caps = &cpu_data->perf_caps; + u32 effective_nominal = caps->nominal_perf; + bool ospm_supported = false; + u64 ospm_nominal; + int ret; + + ret = cppc_get_ospm_nominal_perf(policy->cpu, &ospm_nominal); + if (ret == -EOPNOTSUPP) + goto out; + if (ret) + return ret; + + ospm_supported = true; + + /* A zero value means OSPM has not selected a nominal level. */ + if (!ospm_nominal) + goto out; + + if (ospm_nominal < caps->lowest_perf || + ospm_nominal > caps->nominal_perf) + return -EINVAL; + + effective_nominal = (u32)ospm_nominal; + +out: + *nominal = effective_nominal; + if (supported) + *supported = ospm_supported; + + return 0; +} + static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; struct cppc_cpudata *cpu_data; struct cppc_perf_caps *caps; + bool ospm_supported; + u32 nominal, perf; int ret; cpu_data = cppc_cpufreq_get_cpu_data(cpu); @@ -788,8 +840,17 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) * nonlinear perf */ policy->cpuinfo.min_freq = cppc_perf_to_khz(caps, caps->lowest_perf); - policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, policy->boost_enabled ? - caps->highest_perf : caps->nominal_perf); + + ret = cppc_cpufreq_get_effective_nominal(policy, &nominal, + &ospm_supported); + if (ret) { + pr_debug("CPU%u: failed to get effective nominal: %d\n", + cpu, ret); + goto out; + } + + perf = policy->boost_enabled ? caps->highest_perf : nominal; + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, perf); policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu); policy->shared_type = cpu_data->shared_type; @@ -819,9 +880,13 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) /* * If 'highest_perf' is greater than 'nominal_perf', we assume CPU Boost - * is supported. + * is supported. A writable OSPM Nominal Performance register can also + * open a boost range at runtime by lowering the nominal, so assume + * boost is supported in that case too, letting the core register its + * QoS request up front. */ - if (caps->highest_perf > caps->nominal_perf) + if (caps->highest_perf > caps->nominal_perf || + (ospm_supported && caps->highest_perf > caps->lowest_perf)) policy->boost_supported = true; /* Set policy->cur to max now. The governors will adjust later. */ @@ -992,11 +1057,16 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state) { struct cppc_cpudata *cpu_data = policy->driver_data; struct cppc_perf_caps *caps = &cpu_data->perf_caps; + u32 perf = caps->highest_perf; + int ret; - if (state) - policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->highest_perf); - else - policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf); + if (!state) { + ret = cppc_cpufreq_get_effective_nominal(policy, &perf, NULL); + if (ret) + return ret; + } + + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, perf); return 0; } @@ -1025,6 +1095,35 @@ static ssize_t show_auto_select(struct cpufreq_policy *policy, char *buf) return sysfs_emit(buf, "%d\n", val); } +static int cppc_cpufreq_reflect_nominal(struct cpufreq_policy *policy, + u32 nominal) +{ + struct cppc_cpudata *cpu_data = policy->driver_data; + int ret; + + /* + * While boost is disabled, the nominal is the ceiling. Set + * cpuinfo.max_freq to it and update the core's boost_freq_req to + * match. The core only syncs boost_freq_req when boost is enabled or + * disabled, so a plain nominal change must update it here. + */ + if (!policy->boost_enabled) { + policy->cpuinfo.max_freq = + cppc_perf_to_khz(&cpu_data->perf_caps, nominal); + + if (freq_qos_request_active(&policy->boost_freq_req)) { + ret = freq_qos_update_request(&policy->boost_freq_req, + policy->cpuinfo.max_freq); + if (ret < 0) + return ret; + } + } + + refresh_frequency_limits(policy); + + return 0; +} + static ssize_t store_auto_select(struct cpufreq_policy *policy, const char *buf, size_t count) { @@ -1208,6 +1307,10 @@ static ssize_t store_ospm_nominal_freq(struct cpufreq_policy *policy, if (ret) return ret; + ret = cppc_cpufreq_reflect_nominal(policy, perf); + if (ret) + return ret; + return count; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support 2026-07-17 21:53 [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta 2026-07-17 21:53 ` [PATCH v6 1/2] ACPI: " Sumit Gupta 2026-07-17 21:53 ` [PATCH v6 2/2] cpufreq: CPPC: Reflect ospm_nominal_perf in boost and limits Sumit Gupta @ 2026-07-27 13:27 ` Rafael J. Wysocki (Intel) 2 siblings, 0 replies; 10+ messages in thread From: Rafael J. Wysocki (Intel) @ 2026-07-27 13:27 UTC (permalink / raw) To: Sumit Gupta, christian.loehle, pierre.gondois Cc: viresh.kumar, ionela.voinescu, zhenglifeng1, zhanjie9, linux-kernel, linux-pm, linux-acpi, linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu On Fri, Jul 17, 2026 at 11:54 PM Sumit Gupta <sumitg@nvidia.com> wrote: > > This series adds support for the OSPM Nominal Performance register > (ACPI 6.6, Section 8.4.6.1.2.6) to the CPPC ACPI and cpufreq drivers. > > Unlike the read-only Nominal Performance register, OSPM Nominal > Performance is writable and lets OSPM request a nominal level below > the platform-reported nominal. The platform treats performance above > this level as boost and below as throttle for its power and thermal > decisions. > > Patch 1: adds the cppc_{get,set}_ospm_nominal_perf() helpers, a > per-policy cpufreq sysfs attribute (ospm_nominal_freq, in kHz), and > hooks the register into the OSPM-set save/restore table. > > Patch 2: reflects the OSPM nominal in the cpufreq policy so that boost > and the frequency limits stay consistent with the register. > > This series applies on top of the series > "cpufreq: CPPC: Preserve OSPM-set registers across hotplug and unload", > which provides the save/restore table that patch 1 hooks into: > https://lore.kernel.org/lkml/20260716153820.2007095-1-sumitg@nvidia.com/ > > v5[5] -> v6: > - New patch 2: reflect the OSPM nominal in the policy's boost state > and frequency limits. > - Patch 1: > - write only policy->cpu instead of looping over policy->cpus with > rollback. the register is treated as shared across a policy's CPUs. > - add the register to the OSPM-set save/restore table. Christian, Pierre, any chance to have a look at this, please? > Sumit Gupta (2): > ACPI: CPPC: Add ospm_nominal_perf support > cpufreq: CPPC: Reflect ospm_nominal_perf in boost and limits > > .../ABI/testing/sysfs-devices-system-cpu | 26 +++ > drivers/acpi/cppc_acpi.c | 32 ++++ > drivers/cpufreq/cppc_cpufreq.c | 166 +++++++++++++++++- > include/acpi/cppc_acpi.h | 10 ++ > 4 files changed, 226 insertions(+), 8 deletions(-) > > v5: https://lore.kernel.org/lkml/20260615185934.2383514-1-sumitg@nvidia.com/ > v4: https://lore.kernel.org/lkml/20260527194626.185286-1-sumitg@nvidia.com/ > v3: https://lore.kernel.org/lkml/20260514194822.1841748-1-sumitg@nvidia.com/ > v2: https://lore.kernel.org/lkml/20260430142430.755437-1-sumitg@nvidia.com/ > v1: https://lore.kernel.org/lkml/20260427051823.280419-1-sumitg@nvidia.com/ ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-08-04 16:15 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-17 21:53 [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Sumit Gupta 2026-07-17 21:53 ` [PATCH v6 1/2] ACPI: " Sumit Gupta 2026-07-27 14:01 ` Christian Loehle 2026-07-27 17:49 ` Christian Loehle 2026-07-27 21:23 ` Christian Loehle 2026-08-04 16:12 ` Sumit Gupta 2026-07-28 13:24 ` Zhongqiu Han 2026-08-04 16:15 ` Sumit Gupta 2026-07-17 21:53 ` [PATCH v6 2/2] cpufreq: CPPC: Reflect ospm_nominal_perf in boost and limits Sumit Gupta 2026-07-27 13:27 ` [PATCH v6 0/2] ACPI / cpufreq: CPPC: Add ospm_nominal_perf support Rafael J. Wysocki (Intel)
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox