* [PATCH v5] ACPI: CPPC: Add ospm_nominal_perf support
@ 2026-06-15 18:59 Sumit Gupta
2026-07-01 16:23 ` Pierre Gondois
0 siblings, 1 reply; 3+ messages in thread
From: Sumit Gupta @ 2026-06-15 18:59 UTC (permalink / raw)
To: rafael, viresh.kumar, lenb, pierre.gondois, zhenglifeng1,
zhanjie9, mario.limonciello, saket.dumbre, linux-acpi,
linux-kernel, linux-pm, acpica-devel
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/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.
On read, the current register value is returned, or
"<unsupported>" if the platform does not implement the register.
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
Patch 1 of the v4 series ("ACPI: CPPC: Add support for CPPC v4") is
already applied, so this contains only patch 2.
Changes in v5:
- Add cppc_get_ospm_nominal_perf() to read the register directly.
- Drop the cppc_cpudata cache variables ospm_nominal_perf/_set.
- Show_ospm_nominal_freq() returns register value or "<unsupported>".
- Register rollback reads the register too.
- Move range check into the sysfs store from cppc_set_ospm_nominal_perf()
- ABI doc: update read description and add a task-migration note.
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/
.../ABI/testing/sysfs-devices-system-cpu | 26 ++++++++
drivers/acpi/cppc_acpi.c | 32 +++++++++
drivers/cpufreq/cppc_cpufreq.c | 65 +++++++++++++++++++
include/acpi/cppc_acpi.h | 10 +++
4 files changed, 133 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 9f572f481241..1fcc22a10b4c 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 f6cea0c54dd9..d160ceced7d9 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -1011,11 +1011,75 @@ 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 sib, freq_khz, failing_cpu = 0;
+ u64 prev_perf;
+ 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;
+
+ /* Save the current value to roll back to if a sibling write fails. */
+ ret = cppc_get_ospm_nominal_perf(policy->cpu, &prev_perf);
+ if (ret)
+ return ret;
+
+ for_each_cpu(sib, policy->cpus) {
+ ret = cppc_set_ospm_nominal_perf(sib, perf);
+ if (ret) {
+ failing_cpu = sib;
+ goto rollback;
+ }
+ }
+
+ 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.
+ */
+ 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,
@@ -1023,6 +1087,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 8693890a7275..b545fec3fd47 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);
@@ -266,6 +268,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] 3+ messages in thread
* Re: [PATCH v5] ACPI: CPPC: Add ospm_nominal_perf support
2026-06-15 18:59 [PATCH v5] ACPI: CPPC: Add ospm_nominal_perf support Sumit Gupta
@ 2026-07-01 16:23 ` Pierre Gondois
2026-07-09 17:01 ` Sumit Gupta
0 siblings, 1 reply; 3+ messages in thread
From: Pierre Gondois @ 2026-07-01 16:23 UTC (permalink / raw)
To: Sumit Gupta, rafael, viresh.kumar, lenb, zhenglifeng1, zhanjie9,
linux-pm, acpica-devel
Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu,
mario.limonciello, linux-kernel, saket.dumbre, linux-acpi
Hello Sumit,
On 6/15/26 20:59, 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/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.
>
> On read, the current register value is returned, or
> "<unsupported>" if the platform does not implement the register.
>
> Signed-off-by: Sumit Gupta<sumitg@nvidia.com>
> ---
> Patch 1 of the v4 series ("ACPI: CPPC: Add support for CPPC v4") is
> already applied, so this contains only patch 2.
>
> Changes in v5:
> - Add cppc_get_ospm_nominal_perf() to read the register directly.
> - Drop the cppc_cpudata cache variables ospm_nominal_perf/_set.
> - Show_ospm_nominal_freq() returns register value or "<unsupported>".
> - Register rollback reads the register too.
> - Move range check into the sysfs store from cppc_set_ospm_nominal_perf()
> - ABI doc: update read description and add a task-migration note.
>
> 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/
>
> .../ABI/testing/sysfs-devices-system-cpu | 26 ++++++++
> drivers/acpi/cppc_acpi.c | 32 +++++++++
> drivers/cpufreq/cppc_cpufreq.c | 65 +++++++++++++++++++
> include/acpi/cppc_acpi.h | 10 +++
> 4 files changed, 133 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 9f572f481241..1fcc22a10b4c 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 f6cea0c54dd9..d160ceced7d9 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -1011,11 +1011,75 @@ 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 sib, freq_khz, failing_cpu = 0;
> + u64 prev_perf;
> + 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;
> +
Sorry I didn't notice in v3, but this function is the only
one setting the registers for all CPUs in the policy.
In v2, the interface was per-CPU. The main issue with that
is that we need a mechanism to aggregate values of CPUs
in the same policy.
In v3/v4/v5, the interface was per-policy, but the
ospm_nominal_freq was set for all CPUs CPPC regs individually.
If we do that, the sequence:
- unplug a CPU from a policy
- set ospm_nominal_freq for the policy
- hotplug back the CPU
might cause inconsistencies in the CPPC regs.
Maybe it is better to continue with the assumption that all
CPUs in the same policy have the same interface ? This
assumption seems to be made for auto_sel and other regs.
If this makes sense, would it be possible to:
- add such check and warn if it is not the case
- set the ospm_nominal_freq value only for policy->cpu
(and remove the rollback mechanism)
When updating the ospm_nominal_freq, we should also:
- update policy->cpuinfo.max_freq if boost=0
- refresh the freq. limits
- set policy->boost_supported if it is not already the case
Also, update cppc_cpufreq_set_boost() should rely on
ospm_nominal_freq instead of caps->nominal_perf as a reference.
Please let me know if this is ok
Regards,
Pierre
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v5] ACPI: CPPC: Add ospm_nominal_perf support
2026-07-01 16:23 ` Pierre Gondois
@ 2026-07-09 17:01 ` Sumit Gupta
0 siblings, 0 replies; 3+ messages in thread
From: Sumit Gupta @ 2026-07-09 17:01 UTC (permalink / raw)
To: Pierre Gondois, rafael, viresh.kumar, lenb, zhenglifeng1,
zhanjie9, linux-pm, acpica-devel
Cc: treding, jonathanh, vsethi, ksitaraman, sanjayc, mochs, bbasu,
mario.limonciello, linux-kernel, saket.dumbre, linux-acpi, sumitg
On 01/07/26 21:53, Pierre Gondois wrote:
> External email: Use caution opening links or attachments
>
>
> Hello Sumit,
>
> On 6/15/26 20:59, 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/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.
>>
>> On read, the current register value is returned, or
>> "<unsupported>" if the platform does not implement the register.
>>
>> Signed-off-by: Sumit Gupta<sumitg@nvidia.com>
>> ---
>> Patch 1 of the v4 series ("ACPI: CPPC: Add support for CPPC v4") is
>> already applied, so this contains only patch 2.
>>
>> Changes in v5:
>> - Add cppc_get_ospm_nominal_perf() to read the register directly.
>> - Drop the cppc_cpudata cache variables ospm_nominal_perf/_set.
>> - Show_ospm_nominal_freq() returns register value or "<unsupported>".
>> - Register rollback reads the register too.
>> - Move range check into the sysfs store from
>> cppc_set_ospm_nominal_perf()
>> - ABI doc: update read description and add a task-migration note.
>>
>> 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/
>>
>>
>> .../ABI/testing/sysfs-devices-system-cpu | 26 ++++++++
>> drivers/acpi/cppc_acpi.c | 32 +++++++++
>> drivers/cpufreq/cppc_cpufreq.c | 65 +++++++++++++++++++
>> include/acpi/cppc_acpi.h | 10 +++
>> 4 files changed, 133 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 9f572f481241..1fcc22a10b4c 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 f6cea0c54dd9..d160ceced7d9 100644
>> --- a/drivers/cpufreq/cppc_cpufreq.c
>> +++ b/drivers/cpufreq/cppc_cpufreq.c
>> @@ -1011,11 +1011,75 @@ 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 sib, freq_khz, failing_cpu = 0;
>> + u64 prev_perf;
>> + 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;
>> +
>
> Sorry I didn't notice in v3, but this function is the only
> one setting the registers for all CPUs in the policy.
>
> In v2, the interface was per-CPU. The main issue with that
> is that we need a mechanism to aggregate values of CPUs
> in the same policy.
>
> In v3/v4/v5, the interface was per-policy, but the
> ospm_nominal_freq was set for all CPUs CPPC regs individually.
> If we do that, the sequence:
> - unplug a CPU from a policy
> - set ospm_nominal_freq for the policy
> - hotplug back the CPU
> might cause inconsistencies in the CPPC regs.
>
> Maybe it is better to continue with the assumption that all
> CPUs in the same policy have the same interface ? This
> assumption seems to be made for auto_sel and other regs.
>
> If this makes sense, would it be possible to:
> - add such check and warn if it is not the case
Will send the mismatch check for the SHARED_TYPE_ANY case as a
separate patch, as it is a pre-existing issue.
> - set the ospm_nominal_freq value only for policy->cpu
> (and remove the rollback mechanism)
Yes, will write only policy->cpu and drop the rollback assuming a
shared register.
>
> When updating the ospm_nominal_freq, we should also:
> - update policy->cpuinfo.max_freq if boost=0
> - refresh the freq. limits
> - set policy->boost_supported if it is not already the case
>
> Also, update cppc_cpufreq_set_boost() should rely on
> ospm_nominal_freq instead of caps->nominal_perf as a reference.
>
> Please let me know if this is ok
>
> Regards,
>
> Pierre
Agreed. I will add an "effective nominal" (ospm_nominal_freq when set,
else caps->nominal_perf) and use it everywhere. Also will clear
boost_supported when it is raised back to highest_perf.
Thanks,
Sumit
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-09 17:01 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-15 18:59 [PATCH v5] ACPI: CPPC: Add ospm_nominal_perf support Sumit Gupta
2026-07-01 16:23 ` Pierre Gondois
2026-07-09 17:01 ` Sumit Gupta
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox