ACPI: CPPC: Add CPPC v4 support (ACPI 6.6)
Subsystems (5)
Sumit Gupta
reviewerv4 cover ACPI: CPPC: Add CPPC v4 support (ACPI 6.6)
Add initial kernel support for CPPC v4 (ACPI 6.6, Section 8.4.6), which extends the _CPC package from 23 to 25 entries with two optional fields:
- OSPM Nominal Performance (8.4.6.1.2.6): register used by OSPM to tell the platform what it considers nominal. The platform classifies performance above this as boost and below as throttle for power/thermal decisions.
- Resource Priority (8.4.6.1.2.7): Package of Resource Priority Register Descriptor sub-packages. Full parsing is not yet implemented; such entries are marked as unsupported.
Patch 1: Add v4 _CPC parsing - validate the 25-entry layout, restrict the Resource Priority package fallback to that slot only, and mark the two new registers optional.
Patch 2: Add per-policy sysfs attribute ospm_nominal_freq (kHz) under cpufreq. Writes are converted to perf and applied to every CPU in policy->cpus.
---
v3[3] -> v4:
- Patch 2:
- Add a bool cpu_data->ospm_nominal_perf_set to distinguish an unwritten cache from a valid perf=0 write.
- Switch freq_khz to unsigned int and use kstrtouint().
- Add rollback in store_ospm_nominal_freq() to restore the previous cached value on a partial multi-CPU write failure.
v2[2] -> v3:
- Patch 1:
- Accept ACPI_TYPE_PACKAGE only at RESOURCE_PRIORITY; abort otherwise.
- Added Reviewed-by from Pierre Gondois.
- Patch 2:
- Sysfs moved from per-CPU acpi_cppc to per-policy cpufreq.
- Read ospm_nominal_freq sysfs input in kHz and convert to perf.
- Cached ospm_nominal_perf moved from cpc_desc to cppc_cpudata.
- Validate input against [Lowest Performance, Nominal Performance] in cppc_set_ospm_nominal_perf().
- Dropped unconditional init in cppc_cpufreq_cpu_init().
- Remove to skip write if cache matches in cppc_set_ospm_nominal_perf.
- Early -ENODEV return when no CPC descriptor.
- Added ABI documentation at Documentation/ABI/testing/sysfs-devices-system-cpu.
v1[1] -> v2:
- Patch 1: Added Reviewed-by from Mario Limonciello.
- Patch 2:
- Make ospm_nominal_perf sysfs read-write; cache last write in cpc_desc and skip redundant register writes.
- Validate input in cppc_set_ospm_nominal_perf.
Sumit Gupta (2):
ACPI: CPPC: Add support for CPPC v4
ACPI: CPPC: Add ospm_nominal_perf support
.../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ drivers/acpi/cppc_acpi.c | 58 ++++++++++++++++-- drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ include/acpi/cppc_acpi.h | 20 ++++++- 4 files changed, 147 insertions(+), 8 deletions(-)
[1] https://lore.kernel.org/lkml/[email protected]/
[2] https://lore.kernel.org/lkml/[email protected]/
[3] https://lore.kernel.org/lkml/[email protected]/
Signature · 1 line
2.34.1
Sumit Gupta
reviewerPATCH v4 1/2 ACPI: CPPC: Add support for CPPC v4
CPPC v4 (ACPI 6.6, Section 8.4.6) adds two optional entries to the _CPC package:
1. OSPM Nominal Performance (8.4.6.1.2.6): A write-only register that lets OSPM inform the platform what it considers nominal performance. The platform classifies performance above this level as boost and below as throttle for its power/thermal decisions.
2. Resource Priority (8.4.6.1.2.7): A Package of Resource Priority Register Descriptor sub-packages that allow OSPM to set relative priority among processors for shared resources (boost, throttle, L2/L3 cache, memory bandwidth). Parsing the full structure is not yet supported; such entries are marked as unsupported.
Add v4 _CPC table parsing (25 entries) and update REG_OPTIONAL to mark the two new registers as optional.
--- drivers/acpi/cppc_acpi.c | 23 +++++++++++++++++------ include/acpi/cppc_acpi.h | 8 ++++++-- 2 files changed, 23 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +17 -6
@@ -134,7 +134,7 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);* cpc_regs[] with the corresponding index. 0 means mandatory and 1 * means optional. */ -#define REG_OPTIONAL (0x1FC7D0) +#define REG_OPTIONAL (0x7FC7D0)/* * Use the index of the register in per-cpu cpc_regs[] to check if
@@ -751,18 +751,19 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)/* * Disregard _CPC if the number of entries in the return package is not * as expected, but support future revisions being proper supersets of -* the v3 and only causing more entries to be returned by _CPC. +* the v4 and only causing more entries to be returned by _CPC. */ if ((cpc_rev ==CPPC_V2_REV && num_ent !=CPPC_V2_NUM_ENT ) || (cpc_rev ==CPPC_V3_REV && num_ent !=CPPC_V3_NUM_ENT ) || - (cpc_rev >CPPC_V3_REV && num_ent <=CPPC_V3_NUM_ENT )) { + (cpc_rev ==CPPC_V4_REV && num_ent !=CPPC_V4_NUM_ENT ) || + (cpc_rev >CPPC_V4_REV && num_ent <=CPPC_V4_NUM_ENT )) {pr_debug ("Unexpected number of _CPC return package entries (%d) for CPU:%d\n" , num_ent, pr->id); goto out_free; } -if (cpc_rev >CPPC_V3_REV ) { - num_ent =CPPC_V3_NUM_ENT ; - cpc_rev =CPPC_V3_REV ; +if (cpc_rev >CPPC_V4_REV ) { + num_ent =CPPC_V4_NUM_ENT ; + cpc_rev =CPPC_V4_REV ; } cpc_ptr->num_entries = num_ent;
@@ -845,6 +846,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_BUFFER ;memcpy (&cpc_ptr->cpc_regs[i-2 ].cpc_entry.reg, gas_t,sizeof (*gas_t)); + }else if (cpc_obj->type ==ACPI_TYPE_PACKAGE && (i -2 ) ==RESOURCE_PRIORITY ) { +/* +* ACPI 6.6, s8.4.6.1.2.7 defines Resource Priority as a +* Package of Resource Priority Register Descriptor sub-packages. +* Parsing the full structure is not yet supported. +* Mark the register as unsupported for now. +*/ +pr_debug ("CPU:%d Resource Priority not supported\n" , pr->id); + cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_INTEGER ; + cpc_ptr->cpc_regs[i-2 ].cpc_entry.int_value =0 ; }else {pr_debug ("Invalid entry type (%d) in _CPC for CPU:%d\n" , i, pr->id);
include/acpi/cppc_acpi.h +6 -2
@@ -17,16 +17,18 @@#include <acpi/pcc.h> #include <acpi/processor.h> -/* CPPCv2 and CPPCv3 support */ +/* CPPCv2, CPPCv3 and CPPCv4 support */ #define CPPC_V2_REV 2#define CPPC_V3_REV 3 +#define CPPC_V4_REV 4#define CPPC_V2_NUM_ENT 21#define CPPC_V3_NUM_ENT 23 +#define CPPC_V4_NUM_ENT 25#define PCC_CMD_COMPLETE_MASK (1 << 0)#define PCC_ERROR_MASK (1 << 2) -#define MAX_CPC_REG_ENT 21 +#define MAX_CPC_REG_ENT 23/* CPPC specific PCC commands. */ #define CMD_READ 0
@@ -110,6 +112,8 @@ enum cppc_regs {REFERENCE_PERF ,LOWEST_FREQ ,NOMINAL_FREQ , +OSPM_NOMINAL_PERF , + RESOURCE_PRIORITY, };/*
Signature · 1 line
2.34.1
Rafael J. Wysocki
maintainerRe: [PATCH v4 1/2] ACPI: CPPC: Add support for CPPC v4
Quoted 15 lines · Sumit Gupta
CPPC v4 (ACPI 6.6, Section 8.4.6) adds two optional entries to the
_CPCpackage:1. OSPM Nominal Performance (8.4.6.1.2.6): A write-only register that lets OSPM inform the platform what it considers nominal performance. The platform classifies performance above this level as boost and below as throttle for its power/thermal decisions.
2. Resource Priority (8.4.6.1.2.7): A Package of Resource Priority Register Descriptor sub-packages that allow OSPM to set relative priority among processors for shared resources (boost, throttle, L2/L3 cache, memory bandwidth). Parsing the full structure is not yet supported; such entries are marked as unsupported.
Quoted 6 lines
Add v4
_CPCtable parsing (25 entries) and updateREG_OPTIONALto mark the two new registers as optional.Signed-off-by Sumit Gupta <[email protected]>Reviewed-by Mario Limonciello (AMD) <[email protected]>Reviewed-by Pierre Gondois <[email protected]>
This patch is good to go AFAICS, while there are still comments on the second one in the series.
Do you want me to apply this one separately?
Quoted 97 lines
--- drivers/acpi/cppc_acpi.c | 23 +++++++++++++++++------ include/acpi/cppc_acpi.h | 8 ++++++-- 2 files changed, 23 insertions(+), 8 deletions(-)drivers/acpi/cppc_acpi.c +17
-6@@ -134,7 +134,7 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);* cpc_regs[] with the corresponding index. 0 means mandatory and 1 * means optional. */ -#define REG_OPTIONAL (0x1FC7D0) +#define REG_OPTIONAL (0x7FC7D0)/* * Use the index of the register in per-cpu cpc_regs[] to check if @@ -751,18 +751,19 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)/* * Disregard _CPC if the number of entries in the return package is not * as expected, but support future revisions being proper supersets of -* the v3 and only causing more entries to be returned by _CPC. +* the v4 and only causing more entries to be returned by _CPC. */ if ((cpc_rev ==CPPC_V2_REV && num_ent !=CPPC_V2_NUM_ENT ) || (cpc_rev ==CPPC_V3_REV && num_ent !=CPPC_V3_NUM_ENT ) || - (cpc_rev >CPPC_V3_REV && num_ent <=CPPC_V3_NUM_ENT )) { + (cpc_rev ==CPPC_V4_REV && num_ent !=CPPC_V4_NUM_ENT ) || + (cpc_rev >CPPC_V4_REV && num_ent <=CPPC_V4_NUM_ENT )) {pr_debug ("Unexpected number of _CPC return package entries (%d) for CPU:%d\n" , num_ent, pr->id); goto out_free; } -if (cpc_rev >CPPC_V3_REV ) { - num_ent =CPPC_V3_NUM_ENT ; - cpc_rev =CPPC_V3_REV ; +if (cpc_rev >CPPC_V4_REV ) { + num_ent =CPPC_V4_NUM_ENT ; + cpc_rev =CPPC_V4_REV ; } cpc_ptr->num_entries = num_ent;@@ -845,6 +846,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_BUFFER ;memcpy (&cpc_ptr->cpc_regs[i-2 ].cpc_entry.reg, gas_t,sizeof (*gas_t)); + }else if (cpc_obj->type ==ACPI_TYPE_PACKAGE && (i -2 ) ==RESOURCE_PRIORITY ) { +/* +* ACPI 6.6, s8.4.6.1.2.7 defines Resource Priority as a +* Package of Resource Priority Register Descriptor sub-packages. +* Parsing the full structure is not yet supported. +* Mark the register as unsupported for now. +*/ +pr_debug ("CPU:%d Resource Priority not supported\n" , pr->id); + cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_INTEGER ; + cpc_ptr->cpc_regs[i-2 ].cpc_entry.int_value =0 ; }else {pr_debug ("Invalid entry type (%d) in _CPC for CPU:%d\n" , i, pr->id);include/acpi/cppc_acpi.h +6
-3@@ -17,16 +17,18 @@#include <acpi/pcc.h> #include <acpi/processor.h> -/* CPPCv2 and CPPCv3 support */ +/* CPPCv2, CPPCv3 and CPPCv4 support */ #define CPPC_V2_REV 2#define CPPC_V3_REV 3 +#define CPPC_V4_REV 4#define CPPC_V2_NUM_ENT 21#define CPPC_V3_NUM_ENT 23 +#define CPPC_V4_NUM_ENT 25#define PCC_CMD_COMPLETE_MASK (1 << 0)#define PCC_ERROR_MASK (1 << 2) -#define MAX_CPC_REG_ENT 21 +#define MAX_CPC_REG_ENT 23/* CPPC specific PCC commands. */ #define CMD_READ 0@@ -110,6 +112,8 @@ enum cppc_regs {REFERENCE_PERF ,LOWEST_FREQ ,NOMINAL_FREQ , +OSPM_NOMINAL_PERF , + RESOURCE_PRIORITY, };/* -- 2.34.1
Sumit Gupta
reviewerRe: [PATCH v4 1/2] ACPI: CPPC: Add support for CPPC v4
Hi Rafael,
Quoted 21 lines · Rafael J. Wysocki
External email: Use caution opening links or attachments
Quoted 17 lines · Sumit Gupta
CPPC v4 (ACPI 6.6, Section 8.4.6) adds two optional entries to the
_CPCpackage:1. OSPM Nominal Performance (8.4.6.1.2.6): A write-only register that lets OSPM inform the platform what it considers nominal performance. The platform classifies performance above this level as boost and below as throttle for its power/thermal decisions.
2. Resource Priority (8.4.6.1.2.7): A Package of Resource Priority Register Descriptor sub-packages that allow OSPM to set relative priority among processors for shared resources (boost, throttle, L2/L3 cache, memory bandwidth). Parsing the full structure is not yet supported; such entries are marked as unsupported.
Add v4
_CPCtable parsing (25 entries) and updateREG_OPTIONALto mark the two new registers as optional.
Quoted 7 lines
Quoted 3 lines
Signed-off-by Sumit Gupta <[email protected]>Reviewed-by Mario Limonciello (AMD) <[email protected]>Reviewed-by Pierre Gondois <[email protected]>This patch is good to go AFAICS, while there are still comments on the second one in the series.
Do you want me to apply this one separately?
Yes please. Patch 1 is independent of patch 2.
I will send patch 2 separately as a v5 after addressing the review comments.
Thank you,
Sumit Gupta
Quoted 98 lines
Quoted 98 lines
--- drivers/acpi/cppc_acpi.c | 23 +++++++++++++++++------ include/acpi/cppc_acpi.h | 8 ++++++-- 2 files changed, 23 insertions(+), 8 deletions(-)drivers/acpi/cppc_acpi.c +17
-6@@ -134,7 +134,7 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);* cpc_regs[] with the corresponding index. 0 means mandatory and 1 * means optional. */ -#define REG_OPTIONAL (0x1FC7D0) +#define REG_OPTIONAL (0x7FC7D0)/* * Use the index of the register in per-cpu cpc_regs[] to check if @@ -751,18 +751,19 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)/* * Disregard _CPC if the number of entries in the return package is not * as expected, but support future revisions being proper supersets of -* the v3 and only causing more entries to be returned by _CPC. +* the v4 and only causing more entries to be returned by _CPC. */ if ((cpc_rev ==CPPC_V2_REV && num_ent !=CPPC_V2_NUM_ENT ) || (cpc_rev ==CPPC_V3_REV && num_ent !=CPPC_V3_NUM_ENT ) || - (cpc_rev >CPPC_V3_REV && num_ent <=CPPC_V3_NUM_ENT )) { + (cpc_rev ==CPPC_V4_REV && num_ent !=CPPC_V4_NUM_ENT ) || + (cpc_rev >CPPC_V4_REV && num_ent <=CPPC_V4_NUM_ENT )) {pr_debug ("Unexpected number of _CPC return package entries (%d) for CPU:%d\n" , num_ent, pr->id); goto out_free; } -if (cpc_rev >CPPC_V3_REV ) { - num_ent =CPPC_V3_NUM_ENT ; - cpc_rev =CPPC_V3_REV ; +if (cpc_rev >CPPC_V4_REV ) { + num_ent =CPPC_V4_NUM_ENT ; + cpc_rev =CPPC_V4_REV ; } cpc_ptr->num_entries = num_ent;@@ -845,6 +846,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_BUFFER ;memcpy (&cpc_ptr->cpc_regs[i-2 ].cpc_entry.reg, gas_t,sizeof (*gas_t)); + }else if (cpc_obj->type ==ACPI_TYPE_PACKAGE && (i -2 ) ==RESOURCE_PRIORITY ) { +/* +* ACPI 6.6, s8.4.6.1.2.7 defines Resource Priority as a +* Package of Resource Priority Register Descriptor sub-packages. +* Parsing the full structure is not yet supported. +* Mark the register as unsupported for now. +*/ +pr_debug ("CPU:%d Resource Priority not supported\n" , pr->id); + cpc_ptr->cpc_regs[i-2 ].type =ACPI_TYPE_INTEGER ; + cpc_ptr->cpc_regs[i-2 ].cpc_entry.int_value =0 ; }else {pr_debug ("Invalid entry type (%d) in _CPC for CPU:%d\n" , i, pr->id);include/acpi/cppc_acpi.h +6
-3@@ -17,16 +17,18 @@#include <acpi/pcc.h> #include <acpi/processor.h> -/* CPPCv2 and CPPCv3 support */ +/* CPPCv2, CPPCv3 and CPPCv4 support */ #define CPPC_V2_REV 2#define CPPC_V3_REV 3 +#define CPPC_V4_REV 4#define CPPC_V2_NUM_ENT 21#define CPPC_V3_NUM_ENT 23 +#define CPPC_V4_NUM_ENT 25#define PCC_CMD_COMPLETE_MASK (1 << 0)#define PCC_ERROR_MASK (1 << 2) -#define MAX_CPC_REG_ENT 21 +#define MAX_CPC_REG_ENT 23/* CPPC specific PCC commands. */ #define CMD_READ 0@@ -110,6 +112,8 @@ enum cppc_regs {REFERENCE_PERF ,LOWEST_FREQ ,NOMINAL_FREQ , +OSPM_NOMINAL_PERF , + RESOURCE_PRIORITY, };/* -- 2.34.1
Re: [PATCH v4 1/2] ACPI: CPPC: Add support for CPPC v4
Quoted 29 lines · Sumit Gupta
Hi Rafael,
Quoted 24 lines · Rafael J. Wysocki
External email: Use caution opening links or attachments
Quoted 20 lines · Sumit Gupta
CPPC v4 (ACPI 6.6, Section 8.4.6) adds two optional entries to the
_CPCpackage:1. OSPM Nominal Performance (8.4.6.1.2.6): A write-only register that lets OSPM inform the platform what it considers nominal performance. The platform classifies performance above this level as boost and below as throttle for its power/thermal decisions.
2. Resource Priority (8.4.6.1.2.7): A Package of Resource Priority Register Descriptor sub-packages that allow OSPM to set relative priority among processors for shared resources (boost, throttle, L2/L3 cache, memory bandwidth). Parsing the full structure is not yet supported; such entries are marked as unsupported.
Add v4
_CPCtable parsing (25 entries) and updateREG_OPTIONALto mark the two new registers as optional.Signed-off-by Sumit Gupta <[email protected]>Reviewed-by Mario Limonciello (AMD) <[email protected]>Reviewed-by Pierre Gondois <[email protected]>
Quoted 8 lines
Quoted 4 lines
This patch is good to go AFAICS, while there are still comments on the second one in the series.
Do you want me to apply this one separately?
Yes please. Patch 1 is independent of patch 2.
I will send patch 2 separately as a v5 after addressing the review comments.
Applied as 7.2 material, thanks!
Sumit Gupta
reviewerPATCH v4 2/2 ACPI: CPPC: Add ospm_nominal_perf support
In reply to Sumit GuptaExpose the OSPM Nominal Performance register (ACPI 6.6, Section 8.4.6.1.2.6), which conveys the desired nominal performance level at which the platform may run. Unlike the existing read-only Nominal Performance register, it is writable and lets OSPM request a lower nominal level than the platform-reported nominal. The platform classifies performance above this level as boosted and below as throttled for its power/thermal decisions.
It is exposed as a per-policy cpufreq sysfs attribute in kHz, to match the cpufreq sysfs unit convention:
/sys/devices/system/cpu/cpufreq/policyN/ospm_nominal_freq
The attribute is documented in Documentation/ABI/testing/sysfs-devices-system-cpu.
Writes are converted to perf via cppc_khz_to_perf(), validated against [Lowest Performance, Nominal Performance], and applied to every CPU in policy->cpus.
The register is write-only; the kernel caches the last written value in struct cppc_cpudata for sysfs readback (returns 0 until userspace writes a value).
--- .../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ drivers/acpi/cppc_acpi.c | 35 +++++++++++ drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ include/acpi/cppc_acpi.h | 12 ++++ 4 files changed, 124 insertions(+)
Documentation/ABI/testing/sysfs-devices-system-cpu +17 -0
@@ -346,6 +346,23 @@ Description: Performance Limited This file is only present if the cppc-cpufreq driver is in use. +What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq +Date: May 2026 +Contact: [email protected] +Description: OSPM Nominal Performance (kHz) + + OSPM uses this attribute to request a nominal performance + level lower than the platform-reported nominal. The + platform treats performance above this level as boost + and below as throttle for power and thermal decisions. + + Read returns the last written value in kHz, or 0 if no + value has been written. Write a kHz value in the range + [lowest_freq, nominal_freq]. + + This file is only present if the cppc-cpufreq driver is + in use. + What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1} Date: August 2008 KernelVersion: 2.6.27
drivers/acpi/cppc_acpi.c +35 -0
@@ -1682,6 +1682,41 @@ int cppc_set_epp(int cpu, u64 epp_val) }EXPORT_SYMBOL_GPL (cppc_set_epp); +/** +* cppc_set_ospm_nominal_perf() - Write OSPM Nominal Performance register. +* @cpu: CPU on which to write register. +* @ospm_nominal_perf: Value to write to the OSPM Nominal Performance register. +* +* OSPM Nominal Performance conveys the desired nominal performance level +* at which the platform may run. Per ACPI 6.6, s8.4.6.1.2.6, the value +* must lie within [Lowest Performance, Nominal Performance] and may be +* set independently of Minimum, Maximum and Desired performance. +* +* Return: 0 on success or negative error code. +*/ +int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf) +{ +struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpu); +struct cppc_perf_caps caps; +int ret; + +if (!cpc_desc) { +pr_debug ("No CPC descriptor for CPU:%d\n" , cpu); +return -ENODEV ; + } + + ret =cppc_get_perf_caps (cpu, &caps); +if (ret) +return ret; + +if (ospm_nominal_perf < caps.lowest_perf || + ospm_nominal_perf > caps.nominal_perf) +return -EINVAL ; + +return cppc_set_reg_val (cpu,OSPM_NOMINAL_PERF , ospm_nominal_perf); +} +EXPORT_SYMBOL_GPL (cppc_set_ospm_nominal_perf); +/** * cppc_get_auto_act_window() - Read autonomous activity window register. * @cpu: CPU from which to read register.
drivers/cpufreq/cppc_cpufreq.c +60 -0
77 lines not on this page · raw message
include/acpi/cppc_acpi.h +12 -0
@@ -154,6 +154,13 @@ struct cppc_cpudata {struct cppc_perf_fb_ctrs perf_fb_ctrs;unsigned int shared_type;cpumask_var_t shared_cpu_map; +/* +* Cached OSPM Nominal Performance value (write-only register). +* ospm_nominal_perf_set is true once userspace has written, so an +* unwritten cache is distinguishable from a valid 0 perf write. +*/ +u32 ospm_nominal_perf; +bool ospm_nominal_perf_set; };#ifdef CONFIG_ACPI_CPPC_LIB
@@ -181,6 +188,7 @@ extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);extern int cppc_get_epp_perf (int cpunum,u64 *epp_perf);extern int cppc_set_epp_perf (int cpu,struct cppc_perf_ctrls *perf_ctrls,bool enable);extern int cppc_set_epp (int cpu,u64 epp_val); +extern int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf);extern int cppc_get_auto_act_window (int cpu,u64 *auto_act_window);extern int cppc_set_auto_act_window (int cpu,u64 auto_act_window);extern int cppc_get_auto_sel (int cpu,bool *enable);
@@ -267,6 +275,10 @@ static inline int cppc_set_epp(int cpu, u64 epp_val) {return -EOPNOTSUPP ; } +static inline int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf) +{ +return -EOPNOTSUPP ; +}static inline int cppc_get_auto_act_window (int cpu,u64 *auto_act_window) {return -EOPNOTSUPP ;
Signature · 1 line
2.34.1
Re: [PATCH v4 2/2] ACPI: CPPC: Add ospm_nominal_perf support
Hello Sumit,
Quoted 111 lines · Sumit Gupta
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_freqThe 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 inpolicy->cpus.The register is write-only; the kernel caches the last written value in struct
cppc_cpudatafor sysfs readback (returns 0 until userspace writes a value).Signed-off-by Sumit Gupta <[email protected]>--- .../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ drivers/acpi/cppc_acpi.c | 35 +++++++++++ drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ include/acpi/cppc_acpi.h | 12 ++++ 4 files changed, 124 insertions(+)Documentation/ABI/testing/sysfs-devices-system-cpu +17
-0@@ -346,6 +346,23 @@ Description: Performance Limited This file is only present if the cppc-cpufreq driver is in use. +What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq +Date: May 2026 +Contact: [email protected] +Description: OSPM Nominal Performance (kHz) + + OSPM uses this attribute to request a nominal performance + level lower than the platform-reported nominal. The + platform treats performance above this level as boost + and below as throttle for power and thermal decisions. + + Read returns the last written value in kHz, or 0 if no + value has been written. Write a kHz value in the range + [lowest_freq, nominal_freq]. + + This file is only present if the cppc-cpufreq driver is + in use. + What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1} Date: August 2008 KernelVersion: 2.6.27drivers/acpi/cppc_acpi.c +35
-0@@ -1682,6 +1682,41 @@ int cppc_set_epp(int cpu, u64 epp_val) }EXPORT_SYMBOL_GPL (cppc_set_epp); +/** +* cppc_set_ospm_nominal_perf() - Write OSPM Nominal Performance register. +* @cpu: CPU on which to write register. +* @ospm_nominal_perf: Value to write to the OSPM Nominal Performance register. +* +* OSPM Nominal Performance conveys the desired nominal performance level +* at which the platform may run. Per ACPI 6.6, s8.4.6.1.2.6, the value +* must lie within [Lowest Performance, Nominal Performance] and may be +* set independently of Minimum, Maximum and Desired performance. +* +* Return: 0 on success or negative error code. +*/ +int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf) +{ +struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpu); +struct cppc_perf_caps caps; +int ret; + +if (!cpc_desc) { +pr_debug ("No CPC descriptor for CPU:%d\n" , cpu); +return -ENODEV ; + } + + ret =cppc_get_perf_caps (cpu, &caps); +if (ret) +return ret; + +if (ospm_nominal_perf < caps.lowest_perf || + ospm_nominal_perf > caps.nominal_perf) +return -EINVAL ; + +return cppc_set_reg_val (cpu,OSPM_NOMINAL_PERF , ospm_nominal_perf); +} +EXPORT_SYMBOL_GPL (cppc_set_ospm_nominal_perf); +/** * cppc_get_auto_act_window() - Read autonomous activity window register. * @cpu: CPU from which to read register. drivers/cpufreq/cppc_cpufreq.c +0
-0
drivers/cpufreq/cppc_cpufreq.c static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited) · line 1148
Quoted 10 lines
drivers/cpufreq/cppc_cpufreq.c +7
-0@@ -1139,11 +1139,70 @@ static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited)CPPC_CPUFREQ_ATTR_RW_U64 (perf_limited, cppc_get_perf_limited_filtered, cppc_set_perf_limited) +static ssize_t show_ospm_nominal_freq (struct cpufreq_policy *policy,char *buf) +{ +struct cppc_cpudata *cpu_data = policy->driver_data; +unsigned int freq_khz; + +if (!cpu_data->ospm_nominal_perf_set) +return sysfs_emit (buf,"0\n" );
The questions on v3 might be more relevant,
but for instance here, the ospm_nominal_perf value is not 0, the hardware register might contain any value.
So reading the register might be more meaningful than returning 0.
Sumit Gupta
reviewerRe: [PATCH v4 2/2] ACPI: CPPC: Add ospm_nominal_perf support
Quoted 138 lines · Pierre Gondois
External email: Use caution opening links or attachments
Hello Sumit,
Quoted 117 lines · Sumit Gupta
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_freqThe 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 inpolicy->cpus.The register is write-only; the kernel caches the last written value in struct
cppc_cpudatafor sysfs readback (returns 0 until userspace writes a value).Signed-off-by Sumit Gupta <[email protected]>---
.../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ drivers/acpi/cppc_acpi.c | 35 +++++++++++ drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ include/acpi/cppc_acpi.h | 12 ++++4 files changed, 124 insertions(+)Documentation/ABI/testing/sysfs-devices-system-cpu +0
-0@@ -346,6 +346,23 @@ Description: Performance LimitedThis file is only present if the cppc-cpufreq driver is in use.
Documentation/ABI/testing/sysfs-devices-system-cpu +17
-0+What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq +Date: May 2026 +Contact: [email protected] +Description: OSPM Nominal Performance (kHz) + + OSPM uses this attribute to request a nominal performance + level lower than the platform-reported nominal. The + platform treats performance above this level as boost + and below as throttle for power and thermal decisions. + + Read returns the last written value in kHz, or 0 if no + value has been written. Write a kHz value in the range + [lowest_freq, nominal_freq]. + + This file is only present if the cppc-cpufreq driver is + in use. +What:
/sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}Date: August 2008
KernelVersion: 2.6.27drivers/acpi/cppc_acpi.c +2
-0@@ -1682,6 +1682,41 @@ int cppc_set_epp(int cpu, u64 epp_val) } EXPORT_SYMBOL_GPL(cppc_set_epp); +/** +* cppc_set_ospm_nominal_perf() - Write OSPM Nominal Performance register.
+ * @cpu: CPU on which to write register.
+ * @ospm_nominal_perf: Value to write to the OSPM Nominal Performance register.
+ *
+ * OSPM Nominal Performance conveys the desired nominal performance level
+ * at which the platform may run. Per ACPI 6.6, s8.4.6.1.2.6, the value
+ * must lie within [Lowest Performance, Nominal Performance] and may be
+ * set independently of Minimum, Maximum and Desired performance.
+ *
+ * Return: 0 on success or negative error code.
+ */drivers/acpi/cppc_acpi.c +20
-0+int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf) +{ + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); + struct cppc_perf_caps caps; + int ret; + + if (!cpc_desc) { + pr_debug("No CPC descriptor for CPU:%d\n", cpu); + return -ENODEV; + } + + ret = cppc_get_perf_caps(cpu, &caps); + if (ret) + return ret; + + if (ospm_nominal_perf < caps.lowest_perf || + ospm_nominal_perf > caps.nominal_perf) + return -EINVAL; + + return cppc_set_reg_val(cpu, OSPM_NOMINAL_PERF,
ospm_nominal_perf);drivers/acpi/cppc_acpi.c +3
-0+} +EXPORT_SYMBOL_GPL (cppc_set_ospm_nominal_perf); +/**
*cppc_get_auto_act_window()- Read autonomous activity window register.
* @cpu: CPU from which to read register.drivers/cpufreq/cppc_cpufreq.c +0
-0@@ -1139,11 +1139,70 @@ static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited) CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited_filtered,drivers/cpufreq/cppc_cpufreq.c static int cppc_get_perf_limited_filtered(int · line 1150
Quoted 10 lines
drivers/cpufreq/cppc_cpufreq.c +7
-0cppc_set_perf_limited) +static ssize_t show_ospm_nominal_freq(struct cpufreq_policy *policy,char *buf) +{ + struct cppc_cpudata *cpu_data = policy->driver_data; + unsigned int freq_khz; + + if (!cpu_data->ospm_nominal_perf_set) + return sysfs_emit(buf, "0\n");The questions on v3 might be more relevant,
but for instance here, theospm_nominal_perfvalue is not 0, the hardware register might contain any value.
Quoted 4 lines
So reading the register might be more meaningful than returning 0.
Agreed.
In v5, reading the register instead of caching:
- Added cppc_get_ospm_nominal_perf().
- show_ospm_nominal_freq() now returns the current register value, or "<unsupported>" on -EOPNOTSUPP.
- Dropped the cpu_data->ospm_nominal_perf cache and the ospm_nominal_perf_set bool entirely.
This also follows your earlier point that being write-only doesn't mean we can't read it (cppc_get_desired_perf() being the precedent).
Thank you,
Sumit Gupta
Christian Loehle
maintainerRe: [PATCH v4 2/2] ACPI: CPPC: Add ospm_nominal_perf support
In reply to Sumit GuptaQuoted 47 lines · Sumit Gupta
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_freqThe 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 inpolicy->cpus.The register is write-only; the kernel caches the last written value in struct
cppc_cpudatafor sysfs readback (returns 0 until userspace writes a value).Signed-off-by Sumit Gupta <[email protected]>--- .../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ drivers/acpi/cppc_acpi.c | 35 +++++++++++ drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ include/acpi/cppc_acpi.h | 12 ++++ 4 files changed, 124 insertions(+)Documentation/ABI/testing/sysfs-devices-system-cpu +7
-0@@ -346,6 +346,23 @@ Description: Performance Limited This file is only present if the cppc-cpufreq driver is in use. +What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq +Date: May 2026 +Contact: [email protected] +Description: OSPM Nominal Performance (kHz) + + OSPM uses this attribute to request a nominal performance + level lower than the platform-reported nominal. The
Documentation/ABI/testing/sysfs-devices-system-cpu Description: Performance Limited · line 365
Quoted 10 lines
Documentation/ABI/testing/sysfs-devices-system-cpu +10
-0+ platform treats performance above this level as boost + and below as throttle for power and thermal decisions. + + Read returns the last written value in kHz, or 0 if no + value has been written. Write a kHz value in the range + [lowest_freq, nominal_freq]. + + This file is only present if the cppc-cpufreq driver is + in use. +
Given that this value, based also on firmware behavior, can create vast asymmetries between CPUs, which the scheduler would be unaware of I wonder if this warrants a similar disclaimer like intel_pstate carries for their per-CPU EPP:
https://www.kernel.org/doc/html/v7.0/admin-guide/pm/intel_pstate.html#energy-vs-performance-hints
"[Note that tasks may by migrated from one CPU to another by the scheduler’s load-balancing algorithm and if different energy vs performance hints are set for those CPUs, that may lead to undesirable outcomes. To avoid such issues it is better to set the same energy vs performance hint for all CPUs or to pin every task potentially sensitive to them to a specific CPU.]"
Sumit Gupta
reviewerRe: [PATCH v4 2/2] ACPI: CPPC: Add ospm_nominal_perf support
Quoted 66 lines · Christian Loehle
External email: Use caution opening links or attachments
Quoted 47 lines · Sumit Gupta
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_freqThe 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 inpolicy->cpus.The register is write-only; the kernel caches the last written value in struct
cppc_cpudatafor sysfs readback (returns 0 until userspace writes a value).Signed-off-by Sumit Gupta <[email protected]>--- .../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ drivers/acpi/cppc_acpi.c | 35 +++++++++++ drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ include/acpi/cppc_acpi.h | 12 ++++ 4 files changed, 124 insertions(+)Documentation/ABI/testing/sysfs-devices-system-cpu +7
-0@@ -346,6 +346,23 @@ Description: Performance Limited This file is only present if the cppc-cpufreq driver is in use. +What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq +Date: May 2026 +Contact: [email protected] +Description: OSPM Nominal Performance (kHz) + + OSPM uses this attribute to request a nominal performance + level lower than the platform-reported nominal. TheDocumentation/ABI/testing/sysfs-devices-system-cpu Description: Performance Limited · line 365
Quoted 10 lines
Documentation/ABI/testing/sysfs-devices-system-cpu +10
-0+ platform treats performance above this level as boost + and below as throttle for power and thermal decisions. + + Read returns the last written value in kHz, or 0 if no + value has been written. Write a kHz value in the range + [lowest_freq, nominal_freq]. + + This file is only present if the cppc-cpufreq driver is + in use. +Given that this value, based also on firmware behavior, can create vast asymmetries between CPUs, which the scheduler would be unaware of I wonder if this warrants a similar disclaimer like
intel_pstatecarries for their per-CPU EPP:
https://www.kernel.org/doc/html/v7.0/admin-guide/pm/intel_pstate.html#energy-vs-performance-hints
Quoted 1 line
"[Note that tasks may by migrated from one CPU to another by the scheduler’s load-balancing algorithm and if different energy vs performance hints are set for those CPUs, that may lead to undesirable outcomes. To avoid such issues it is better to set the same energy vs performance hint for all CPUs or to pin every task potentially sensitive to them to a specific CPU.]"
Good point.
In v5 added below to the sysfs ABI doc, modeled on similar note:
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, 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 potentially sensitive task to a specific CPU.
Thank you,
Sumit Gupta
Rafael J. Wysocki
maintainerRe: [PATCH v4 2/2] ACPI: CPPC: Add ospm_nominal_perf support
In reply to Sumit GuptaQuoted 21 lines · Sumit Gupta
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_freqThe 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 inpolicy->cpus.
Quoted 5 lines
The register is write-only; the kernel caches the last written value in struct
cppc_cpudatafor sysfs readback (returns 0 until userspace writes a value).Signed-off-by Sumit Gupta <[email protected]>
There is some sashiko.dev feedback on this one that is valid AFAICS:
https://sashiko.dev/#/patchset/20260527194626.185286-1-sumitg%40nvidia.com
Quoted 204 lines
--- .../ABI/testing/sysfs-devices-system-cpu | 17 ++++++ drivers/acpi/cppc_acpi.c | 35 +++++++++++ drivers/cpufreq/cppc_cpufreq.c | 60 +++++++++++++++++++ include/acpi/cppc_acpi.h | 12 ++++ 4 files changed, 124 insertions(+)Documentation/ABI/testing/sysfs-devices-system-cpu +17
-0@@ -346,6 +346,23 @@ Description: Performance Limited This file is only present if the cppc-cpufreq driver is in use. +What: /sys/devices/system/cpu/cpuX/cpufreq/ospm_nominal_freq +Date: May 2026 +Contact: [email protected] +Description: OSPM Nominal Performance (kHz) + + OSPM uses this attribute to request a nominal performance + level lower than the platform-reported nominal. The + platform treats performance above this level as boost + and below as throttle for power and thermal decisions. + + Read returns the last written value in kHz, or 0 if no + value has been written. Write a kHz value in the range + [lowest_freq, nominal_freq]. + + This file is only present if the cppc-cpufreq driver is + in use. + What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1} Date: August 2008 KernelVersion: 2.6.27drivers/acpi/cppc_acpi.c +35
-0@@ -1682,6 +1682,41 @@ int cppc_set_epp(int cpu, u64 epp_val) }EXPORT_SYMBOL_GPL (cppc_set_epp); +/** +* cppc_set_ospm_nominal_perf() - Write OSPM Nominal Performance register. +* @cpu: CPU on which to write register. +* @ospm_nominal_perf: Value to write to the OSPM Nominal Performance register. +* +* OSPM Nominal Performance conveys the desired nominal performance level +* at which the platform may run. Per ACPI 6.6, s8.4.6.1.2.6, the value +* must lie within [Lowest Performance, Nominal Performance] and may be +* set independently of Minimum, Maximum and Desired performance. +* +* Return: 0 on success or negative error code. +*/ +int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf) +{ +struct cpc_desc *cpc_desc =per_cpu (cpc_desc_ptr, cpu); +struct cppc_perf_caps caps; +int ret; + +if (!cpc_desc) { +pr_debug ("No CPC descriptor for CPU:%d\n" , cpu); +return -ENODEV ; + } + + ret =cppc_get_perf_caps (cpu, &caps); +if (ret) +return ret; + +if (ospm_nominal_perf < caps.lowest_perf || + ospm_nominal_perf > caps.nominal_perf) +return -EINVAL ; + +return cppc_set_reg_val (cpu,OSPM_NOMINAL_PERF , ospm_nominal_perf); +} +EXPORT_SYMBOL_GPL (cppc_set_ospm_nominal_perf); +/** * cppc_get_auto_act_window() - Read autonomous activity window register. * @cpu: CPU from which to read register. drivers/cpufreq/cppc_cpufreq.c +60
-0@@ -1139,11 +1139,70 @@ static int cppc_get_perf_limited_filtered(int cpu, u64 *perf_limited)CPPC_CPUFREQ_ATTR_RW_U64 (perf_limited, cppc_get_perf_limited_filtered, cppc_set_perf_limited) +static ssize_t show_ospm_nominal_freq (struct cpufreq_policy *policy,char *buf) +{ +struct cppc_cpudata *cpu_data = policy->driver_data; +unsigned int freq_khz; + +if (!cpu_data->ospm_nominal_perf_set) +return sysfs_emit (buf,"0\n" ); + + freq_khz =cppc_perf_to_khz (&cpu_data->perf_caps, + cpu_data->ospm_nominal_perf); +return sysfs_emit (buf,"%u\n" , freq_khz); +} + +static ssize_t store_ospm_nominal_freq (struct cpufreq_policy *policy, +const char *buf,size_t count) +{ +struct cppc_cpudata *cpu_data = policy->driver_data; +bool prev_set = cpu_data->ospm_nominal_perf_set; +u32 prev_perf = cpu_data->ospm_nominal_perf; +unsigned int sib, freq_khz, failing_cpu =0 ; +u32 perf; +int ret; + + ret =kstrtouint (buf,0 , &freq_khz); +if (ret) +return ret; + + perf =cppc_khz_to_perf (&cpu_data->perf_caps, freq_khz); + +for_each_cpu (sib, policy->cpus) { + ret =cppc_set_ospm_nominal_perf (sib, perf); +if (ret) { + failing_cpu = sib; + goto rollback; + } + } + + cpu_data->ospm_nominal_perf = perf; + cpu_data->ospm_nominal_perf_set = true; +return count; + +rollback: +/* +* Restore the previous value on siblings already updated. +* for_each_cpu() iterates in CPU-id order, so siblings before +* @failing_cpu were updated successfully. Skip restore when +* there is no prior known-good value (first-ever write failed). +*/ +if (prev_set) { +for_each_cpu (sib, policy->cpus) { +if (sib == failing_cpu) +break ; +cppc_set_ospm_nominal_perf (sib, prev_perf); + } + } +return ret; +} +cpufreq_freq_attr_ro (freqdomain_cpus);cpufreq_freq_attr_rw (auto_select);cpufreq_freq_attr_rw (auto_act_window);cpufreq_freq_attr_rw (energy_performance_preference_val);cpufreq_freq_attr_rw (perf_limited); +cpufreq_freq_attr_rw (ospm_nominal_freq);static struct freq_attr *cppc_cpufreq_attr[] = { &freqdomain_cpus,@@ -1151,6 +1210,7 @@ static struct freq_attr *cppc_cpufreq_attr[] = { &auto_act_window, &energy_performance_preference_val, &perf_limited, + &ospm_nominal_freq, NULL, };include/acpi/cppc_acpi.h +12
-1@@ -154,6 +154,13 @@ struct cppc_cpudata {struct cppc_perf_fb_ctrs perf_fb_ctrs;unsigned int shared_type;cpumask_var_t shared_cpu_map; +/* +* Cached OSPM Nominal Performance value (write-only register). +* ospm_nominal_perf_set is true once userspace has written, so an +* unwritten cache is distinguishable from a valid 0 perf write. +*/ +u32 ospm_nominal_perf; +bool ospm_nominal_perf_set; };#ifdef CONFIG_ACPI_CPPC_LIB @@ -181,6 +188,7 @@ extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);extern int cppc_get_epp_perf (int cpunum,u64 *epp_perf);extern int cppc_set_epp_perf (int cpu,struct cppc_perf_ctrls *perf_ctrls,bool enable);extern int cppc_set_epp (int cpu,u64 epp_val); +extern int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf);extern int cppc_get_auto_act_window (int cpu,u64 *auto_act_window);extern int cppc_set_auto_act_window (int cpu,u64 auto_act_window);extern int cppc_get_auto_sel (int cpu,bool *enable);@@ -267,6 +275,10 @@ static inline int cppc_set_epp(int cpu, u64 epp_val) {return -EOPNOTSUPP ; } +static inline int cppc_set_ospm_nominal_perf (int cpu,u64 ospm_nominal_perf) +{ +return -EOPNOTSUPP ; +}static inline int cppc_get_auto_act_window (int cpu,u64 *auto_act_window) {return -EOPNOTSUPP ; --2.34.1
Sumit Gupta
reviewerRe: [PATCH v4 2/2] ACPI: CPPC: Add ospm_nominal_perf support
Quoted 24 lines · Rafael J. Wysocki
External email: Use caution opening links or attachments
Quoted 20 lines · Sumit Gupta
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_freqThe 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 inpolicy->cpus.
Quoted 8 lines
Quoted 5 lines
The register is write-only; the kernel caches the last written value in struct
cppc_cpudatafor sysfs readback (returns 0 until userspace writes a value).Signed-off-by Sumit Gupta <[email protected]>There is some sashiko.dev feedback on this one that is valid AFAICS:
https://sashiko.dev/#/patchset/20260527194626.185286-1-sumitg%40nvidia.com
Thanks for sharing. Will address all four in v5.
Quoted 2 lines
Could this validation reject valid frequencies on systems with CPPC favored cores?
1.
In v5, moved the range check into store_ospm_nominal_freq() in cppc_cpufreq.c, where it uses the same cpu_data->perf_caps as the kHz->perf conversion. OSPM Nominal is treated as a single per-policy value. It's validated once against the policy caps and applied to all CPUs in policy->cpus. This avoids validating against a sibling's separately-read caps.
Quoted 3 lines
When the platform's ACPI
_CPCtable does not support this register, will this unconditionally return '0' instead of an error like-EOPNOTSUPP?
2.
In v5, added cppc_get_ospm_nominal_perf() and dropped the cached value. show() now reads the register and returns "<unsupported>" on -EOPNOTSUPP.
Quoted 1 line
Are newly onlined CPUs missing this cached
ospm_nominal_perfvalue?
3.show() now reads the register directly and not cached value, so it always reflects true per-CPU state.
Quoted 2 lines
Does skipping this rollback loop when
prev_setis false leave the CPUs in a desynchronized state?
In v5, the cache and ospm_nominal_perf_set bool are removed and show() reads the register, so a partial write is no longer hidden. sysfs shows the real per-CPU value, not '0').store() reads the current value before writing and restores it on already updated CPUs if a sibling write fails, so there is no first write skip.
Thank you,
Sumit Gupta
....