Skip to contentSkip to conversation

ACPI: CPPC: Add CPPC v4 support (ACPI 6.6)

PATCH Superseded Sumit Gupta 4 participants 10 messages Apr 27 – Apr 28

Subsystems (5)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

Sumit Gupta

author reviewer
#0 lore raw

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): write-only 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, handle the Resource Priority package, and mark the two new registers optional.

Patch 2: cppc_set_ospm_nominal_perf() API, write-only acpi_cppc/ospm_nominal_perf sysfs attribute, and init to platform nominal during cppc_cpufreq policy init.

Sumit Gupta (2):
ACPI: CPPC: Add support for CPPC v4
ACPI: CPPC: Add ospm_nominal_perf support

 drivers/acpi/cppc_acpi.c       | 66 ++++++++++++++++++++++++++++++----
 drivers/cpufreq/cppc_cpufreq.c | 10 ++++++
 include/acpi/cppc_acpi.h       | 13 +++++--
 3 files changed, 81 insertions(+), 8 deletions(-)
Signature · 1 line
2.34.1
author reviewer
#1 lore raw

PATCH 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 | 24 ++++++++++++++++++------
 include/acpi/cppc_acpi.h |  8 ++++++--
 2 files changed, 24 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +18 -6
index 2e91c5a97761..a1c91ce20cc8 100644
@@ -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,17 @@ 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) {
+			/*
+			 * 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 entry %d: package type not supported\n",
+				 pr->id, i);
+			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
index d1f02ceec4f9..8693890a7275 100644
@@ -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
@@ -109,6 +111,8 @@ enum cppc_regs {
 	REFERENCE_PERF,
 	LOWEST_FREQ,
 	NOMINAL_FREQ,
+	OSPM_NOMINAL_PERF,
+	RESOURCE_PRIORITY,
 };
 
 /*
Signature · 1 line
2.34.1
#2 lore raw

Re: [PATCH 1/2] ACPI: CPPC: Add support for CPPC v4

It seems that mario has sent a similar patch:

https://lore.kernel.org/all/[email protected]/

Quoted 113 lines · Sumit Gupta

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 | 24 ++++++++++++++++++------
 include/acpi/cppc_acpi.h |  8 ++++++--
 2 files changed, 24 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +18 -6
index 2e91c5a97761..a1c91ce20cc8 100644
@@ -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,17 @@ 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) {
+			/*
+			 * 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 entry %d: package type not supported\n",
+				 pr->id, i);
+			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
index d1f02ceec4f9..8693890a7275 100644
@@ -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
@@ -109,6 +111,8 @@ enum cppc_regs {
 	REFERENCE_PERF,
 	LOWEST_FREQ,
 	NOMINAL_FREQ,
+	OSPM_NOMINAL_PERF,
+	RESOURCE_PRIORITY,
 };
 
 /*
author reviewer
#3 lore raw

Re: [PATCH 1/2] ACPI: CPPC: Add support for CPPC v4

Quoted 6 lines · zhenglifeng (A)

External email: Use caution opening links or attachments

It seems that mario has sent a similar patch:

https://lore.kernel.org/all/[email protected]/

Thank you for sharing.
Yes, both look similar with below two change.
1. REG_OPTIONAL needs the 0x1FC7D0 -> 0x7FC7D0 update to mark the two new registers optional. This is present in my [PATCH 1/2].
2. For Resource Priority, pkg_data added to cpc_entry. This is present in Mario's [PATCH 2/6].

Hi Mario,
How would you like to proceed? A few options:
  (a) Let both CPPCv4 patches from this series go separately.
  (b) Fold the REG_OPTIONAL update from my patch 1/2 into your patch, and pull my patch 2/2 into your series.
  (c) Anything else you'd prefer.
Either way works for me.

Thank you,
Sumit Gupta

Quoted 115 lines · Sumit Gupta
Quoted 113 lines

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 | 24 ++++++++++++++++++------
  include/acpi/cppc_acpi.h |  8 ++++++--
  2 files changed, 24 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +18 -6
index 2e91c5a97761..a1c91ce20cc8 100644
@@ -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,17 @@ 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) {
+                     /*
+                      * 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 entry %d: package type not supported\n",
+                              pr->id, i);
+                     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
index d1f02ceec4f9..8693890a7275 100644
@@ -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
@@ -109,6 +111,8 @@ enum cppc_regs {
       REFERENCE_PERF,
       LOWEST_FREQ,
       NOMINAL_FREQ,
+     OSPM_NOMINAL_PERF,
+     RESOURCE_PRIORITY,
  };
 
  /*
#4 lore raw

Re: [PATCH 1/2] ACPI: CPPC: Add support for CPPC v4

Quoted 26 lines · Sumit Gupta
Quoted 6 lines · zhenglifeng (A)

External email: Use caution opening links or attachments

It seems that mario has sent a similar patch:

https://lore.kernel.org/all/[email protected]/

Thank you for sharing.
Yes, both look similar with below two change.
1. REG_OPTIONAL needs the 0x1FC7D0 -> 0x7FC7D0 update to mark the two new registers optional. This is present in my [PATCH 1/2].
2. For Resource Priority, pkg_data added to cpc_entry.
    This is present in Mario's [PATCH 2/6].

Hi Mario,
How would you like to proceed? A few options:
  (a) Let both CPPCv4 patches from this series go separately.
  (b) Fold the REG_OPTIONAL update from my patch 1/2 into your patch, and pull my patch 2/2 into your series.
  (c) Anything else you'd prefer.
Either way works for me.

Quoted 3 lines

Thank you,
Sumit Gupta

Reviewing yours points out that I totally missed updating REG_OPTIONAL with the two new ACPI 6.7 fields being optional too.

In my series I only add in CPPv4 so I can build on top of the changes for CPPCv5.

So - I would say we should let your patches merge for v4 and I'll drop the relevant ones from my series and rebase mine on top of your work.

Quoted 124 lines
Quoted 124 lines · Sumit Gupta
Quoted 121 lines

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 | 24 ++++++++++++++++++------ include/acpi/cppc_acpi.h |  8 ++++++--

  2 files changed, 24 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +1 -1
index 2e91c5a97761..a1c91ce20cc8 100644
@@ -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

drivers/acpi/cppc_acpi.c +1 -1
@@ -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;

drivers/acpi/cppc_acpi.c +3 -0
@@ -845,6 +846,17 @@ 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) {
+                     /*
+                      * 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 entry %d: package type not supported\n",
+                              pr->id, i);
+                     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
index d1f02ceec4f9..8693890a7275 100644
@@ -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
@@ -109,6 +111,8 @@ enum cppc_regs {
        REFERENCE_PERF,
        LOWEST_FREQ,
        NOMINAL_FREQ,
+     OSPM_NOMINAL_PERF,
+     RESOURCE_PRIORITY,
   };
 
   /*
author reviewer
#5 lore raw

Re: [PATCH 1/2] ACPI: CPPC: Add support for CPPC v4

Quoted 36 lines · Mario Limonciello

External email: Use caution opening links or attachments

Quoted 27 lines · Sumit Gupta
Quoted 7 lines · zhenglifeng (A)

External email: Use caution opening links or attachments

It seems that mario has sent a similar patch:

https://lore.kernel.org/all/[email protected]/

Thank you for sharing.
Yes, both look similar with below two change.
1. REG_OPTIONAL needs the 0x1FC7D0 -> 0x7FC7D0 update to mark the two new registers optional. This is present in my [PATCH 1/2].
2. For Resource Priority, pkg_data added to cpc_entry.
     This is present in Mario's [PATCH 2/6].

Hi Mario,
How would you like to proceed? A few options:
   (a) Let both CPPCv4 patches from this series go separately.
   (b) Fold the REG_OPTIONAL update from my patch 1/2 into your patch, and pull my patch 2/2 into your series.
   (c) Anything else you'd prefer.
Either way works for me.

Quoted 3 lines

Thank you,
Sumit Gupta

Quoted 9 lines

Reviewing yours points out that I totally missed updating REG_OPTIONAL with the two new ACPI 6.7 fields being optional too.

In my series I only add in CPPv4 so I can build on top of the changes for CPPCv5.

So - I would say we should let your patches merge for v4 and I'll drop the relevant ones from my series and rebase mine on top of your work.

Thanks Mario.
I will proceed with this series and add your Reviewed-by to this patch in v2.

Thank you,
Sumit Gupta

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines · Sumit Gupta
Quoted 19 lines

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.

---

....

Reviewed-by on v1 1/2
#6 lore raw

Re: [PATCH 1/2] ACPI: CPPC: Add support for CPPC v4

In reply to Sumit Gupta
Quoted 14 lines · Sumit Gupta

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.

Quoted 4 lines

Add v4 _CPC table parsing (25 entries) and update REG_OPTIONAL to mark the two new registers as optional.

Quoted 95 lines
---
  drivers/acpi/cppc_acpi.c | 24 ++++++++++++++++++------
  include/acpi/cppc_acpi.h |  8 ++++++--
  2 files changed, 24 insertions(+), 8 deletions(-)
drivers/acpi/cppc_acpi.c +18 -6
index 2e91c5a97761..a1c91ce20cc8 100644
@@ -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,17 @@ 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) {
+			/*
+			 * 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 entry %d: package type not supported\n",
+				 pr->id, i);
+			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
index d1f02ceec4f9..8693890a7275 100644
@@ -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
@@ -109,6 +111,8 @@ enum cppc_regs {
  	REFERENCE_PERF,
  	LOWEST_FREQ,
  	NOMINAL_FREQ,
+	OSPM_NOMINAL_PERF,
+	RESOURCE_PRIORITY,
  };
 
  /*
author reviewer
#7 lore raw

PATCH 2/2 ACPI: CPPC: Add ospm_nominal_perf support

In reply to Sumit Gupta

Add acpi_cppc/ospm_nominal_perf sysfs attribute (write-only) and cppc_set_ospm_nominal_perf() API for the OSPM Nominal Performance register (ACPI 6.6, Section 8.4.6.1.2.6).

The register conveys the desired nominal performance level at which the platform may run. OSPM can request a lower level than platform nominal. Valid range is [Lowest Performance, Nominal Performance]. The value tells the platform what OSPM considers nominal. The platform classifies performance above this as boosted and below as throttled. It uses that for its power/thermal decisions.

Initialize to platform nominal at policy init. Override via sysfs if needed.

---
 drivers/acpi/cppc_acpi.c       | 42 ++++++++++++++++++++++++++++++++++
 drivers/cpufreq/cppc_cpufreq.c | 10 ++++++++
 include/acpi/cppc_acpi.h       |  5 ++++
 3 files changed, 57 insertions(+)
drivers/acpi/cppc_acpi.c +42 -0
index a1c91ce20cc8..83b4b14652fb 100644
@@ -155,6 +155,10 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
 static struct kobj_attribute _name =		\
 __ATTR(_name, 0444, show_##_name, NULL)
 
+#define define_one_cppc_wo(_name)		\
+static struct kobj_attribute _name =		\
+__ATTR(_name, 0200, NULL, store_##_name)
+
 #define to_cpc_desc(a) container_of(a, struct cpc_desc, kobj)
 
 #define show_cppc_data(access_fn, struct_name, member_name)		\
@@ -211,6 +215,26 @@ static ssize_t show_feedback_ctrs(struct kobject *kobj,
 }
 define_one_cppc_ro(feedback_ctrs);
 
+static ssize_t store_ospm_nominal_perf(struct kobject *kobj,
+				       struct kobj_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct cpc_desc *cpc_ptr = to_cpc_desc(kobj);
+	u64 val;
+	int ret;
+
+	ret = kstrtou64(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	ret = cppc_set_ospm_nominal_perf(cpc_ptr->cpu_id, val);
+	if (ret)
+		return ret;
+
+	return count;
+}
+define_one_cppc_wo(ospm_nominal_perf);
+
 static struct attribute *cppc_attrs[] = {
 	&feedback_ctrs.attr,
 	&reference_perf.attr,
@@ -222,6 +246,7 @@ static struct attribute *cppc_attrs[] = {
 	&nominal_perf.attr,
 	&nominal_freq.attr,
 	&lowest_freq.attr,
+	&ospm_nominal_perf.attr,
 	NULL
 };
 ATTRIBUTE_GROUPS(cppc);
@@ -1683,6 +1708,23 @@ 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 allows OSPM to inform the platform of the nominal
+ * performance level it intends to maintain. This is a write-only register per
+ * ACPI specification.
+ *
+ * Return: 0 for success, -EOPNOTSUPP if not supported, -EIO otherwise.
+ */
+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_auto_act_window() - Read autonomous activity window register.
  * @cpu: CPU from which to read register.
drivers/cpufreq/cppc_cpufreq.c +10 -0
index 7e7f9dfb7a24..d06cba963550 100644
@@ -715,6 +715,16 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
 		goto out;
 	}
 
+	/*
+	 * Initialize OSPM Nominal Performance to inform firmware of
+	 * OSPM's nominal level. Performance above this value = boost;
+	 * below = throttle. Uses platform nominal by default.
+	 */
+	ret = cppc_set_ospm_nominal_perf(cpu, caps->nominal_perf);
+	if (ret && ret != -EOPNOTSUPP)
+		pr_debug("Failed to set ospm_nominal_perf for CPU%d: %d\n",
+			 cpu, ret);
+
 	cppc_cpufreq_cpu_fie_init(policy);
 	return 0;
 
include/acpi/cppc_acpi.h +5 -0
index 8693890a7275..ad1035b0e1de 100644
@@ -180,6 +180,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);
@@ -266,6 +267,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
#8 lore raw

Re: [PATCH 2/2] ACPI: CPPC: Add ospm_nominal_perf support

Quoted 11 lines · Sumit Gupta

Add acpi_cppc/ospm_nominal_perf sysfs attribute (write-only) and cppc_set_ospm_nominal_perf() API for the OSPM Nominal Performance register (ACPI 6.6, Section 8.4.6.1.2.6).

The register conveys the desired nominal performance level at which the platform may run. OSPM can request a lower level than platform nominal. Valid range is [Lowest Performance, Nominal Performance]. The value tells the platform what OSPM considers nominal. The platform classifies performance above this as boosted and below as throttled. It uses that for its power/thermal decisions.

Quoted 4 lines

Initialize to platform nominal at policy init. Override via sysfs if needed.

Even though it's a write only register; does it make sense to be a write only sysfs file?

I say this because if we're writing it at init time and we're the OSPM we should be able to track the state of what we wrote and display that to userspace if it wants to know.

Furthermore; tracking the state could mean store_ospm_nominal_perf() can avoid the extra register write if the state we tracked is the same userspace tried to write.

Quoted 124 lines
---
  drivers/acpi/cppc_acpi.c       | 42 ++++++++++++++++++++++++++++++++++
  drivers/cpufreq/cppc_cpufreq.c | 10 ++++++++
  include/acpi/cppc_acpi.h       |  5 ++++
  3 files changed, 57 insertions(+)
drivers/acpi/cppc_acpi.c +42 -0
index a1c91ce20cc8..83b4b14652fb 100644
@@ -155,6 +155,10 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr);
  static struct kobj_attribute _name =		\
  __ATTR(_name, 0444, show_##_name, NULL)
 
+#define define_one_cppc_wo(_name)		\
+static struct kobj_attribute _name =		\
+__ATTR(_name, 0200, NULL, store_##_name)
+
  #define to_cpc_desc(a) container_of(a, struct cpc_desc, kobj)
 
  #define show_cppc_data(access_fn, struct_name, member_name)		\
@@ -211,6 +215,26 @@ static ssize_t show_feedback_ctrs(struct kobject *kobj,
  }
  define_one_cppc_ro(feedback_ctrs);
 
+static ssize_t store_ospm_nominal_perf(struct kobject *kobj,
+				       struct kobj_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct cpc_desc *cpc_ptr = to_cpc_desc(kobj);
+	u64 val;
+	int ret;
+
+	ret = kstrtou64(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	ret = cppc_set_ospm_nominal_perf(cpc_ptr->cpu_id, val);
+	if (ret)
+		return ret;
+
+	return count;
+}
+define_one_cppc_wo(ospm_nominal_perf);
+
  static struct attribute *cppc_attrs[] = {
  	&feedback_ctrs.attr,
  	&reference_perf.attr,
@@ -222,6 +246,7 @@ static struct attribute *cppc_attrs[] = {
  	&nominal_perf.attr,
  	&nominal_freq.attr,
  	&lowest_freq.attr,
+	&ospm_nominal_perf.attr,
  	NULL
  };
  ATTRIBUTE_GROUPS(cppc);
@@ -1683,6 +1708,23 @@ 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 allows OSPM to inform the platform of the nominal
+ * performance level it intends to maintain. This is a write-only register per
+ * ACPI specification.
+ *
+ * Return: 0 for success, -EOPNOTSUPP if not supported, -EIO otherwise.
+ */
+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_auto_act_window() - Read autonomous activity window register.
   * @cpu: CPU from which to read register.
drivers/cpufreq/cppc_cpufreq.c +10 -0
index 7e7f9dfb7a24..d06cba963550 100644
@@ -715,6 +715,16 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
  		goto out;
  	}
 
+	/*
+	 * Initialize OSPM Nominal Performance to inform firmware of
+	 * OSPM's nominal level. Performance above this value = boost;
+	 * below = throttle. Uses platform nominal by default.
+	 */
+	ret = cppc_set_ospm_nominal_perf(cpu, caps->nominal_perf);
+	if (ret && ret != -EOPNOTSUPP)
+		pr_debug("Failed to set ospm_nominal_perf for CPU%d: %d\n",
+			 cpu, ret);
+
  	cppc_cpufreq_cpu_fie_init(policy);
  	return 0;
 
include/acpi/cppc_acpi.h +5 -0
index 8693890a7275..ad1035b0e1de 100644
@@ -180,6 +180,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);
@@ -266,6 +267,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;
author reviewer
#9 lore raw

Re: [PATCH 2/2] ACPI: CPPC: Add ospm_nominal_perf support

Quoted 23 lines · Mario Limonciello

External email: Use caution opening links or attachments

Quoted 11 lines · Sumit Gupta

Add acpi_cppc/ospm_nominal_perf sysfs attribute (write-only) and cppc_set_ospm_nominal_perf() API for the OSPM Nominal Performance register (ACPI 6.6, Section 8.4.6.1.2.6).

The register conveys the desired nominal performance level at which the platform may run. OSPM can request a lower level than platform nominal. Valid range is [Lowest Performance, Nominal Performance]. The value tells the platform what OSPM considers nominal. The platform classifies performance above this as boosted and below as throttled. It uses that for its power/thermal decisions.

Quoted 4 lines

Initialize to platform nominal at policy init. Override via sysfs if needed.

Even though it's a write only register; does it make sense to be a write only sysfs file?

Quoted 7 lines

I say this because if we're writing it at init time and we're the OSPM we should be able to track the state of what we wrote and display that to userspace if it wants to know.

Furthermore; tracking the state could mean store_ospm_nominal_perf() can avoid the extra register write if the state we tracked is the same userspace tried to write.

Agreed. Will update in v2 to:
- Make sysfs attribute rw.
- Cache the value in cpc_desc and skip register write when unchanged.
- Have show return the cached value.

Thank you,
Sumit Gupta

Quoted 138 lines
Quoted 137 lines

---
  drivers/acpi/cppc_acpi.c       | 42 ++++++++++++++++++++++++++++++++++ drivers/cpufreq/cppc_cpufreq.c | 10 ++++++++ include/acpi/cppc_acpi.h       |  5 ++++

  3 files changed, 57 insertions(+)
drivers/acpi/cppc_acpi.c +4 -0
index a1c91ce20cc8..83b4b14652fb 100644
@@ -155,6 +155,10 @@ static DEFINE_PER_CPU(struct cpc_desc *, 
 cpc_desc_ptr);
   static struct kobj_attribute _name =                \
   __ATTR(_name, 0444, show_##_name, NULL)
 
+#define define_one_cppc_wo(_name)            \
+static struct kobj_attribute _name =         \
+__ATTR(_name, 0200, NULL, store_##_name)
+
   #define to_cpc_desc(a) container_of(a, struct cpc_desc, kobj)
 

  #define show_cppc_data(access_fn, struct_name, member_name)         \

drivers/acpi/cppc_acpi.c +20 -0
@@ -211,6 +215,26 @@ static ssize_t show_feedback_ctrs(struct kobject 
 *kobj,
   }
   define_one_cppc_ro(feedback_ctrs);
 
+static ssize_t store_ospm_nominal_perf(struct kobject *kobj,
+                                    struct kobj_attribute *attr,
+                                    const char *buf, size_t count)
+{
+     struct cpc_desc *cpc_ptr = to_cpc_desc(kobj);
+     u64 val;
+     int ret;
+
+     ret = kstrtou64(buf, 0, &val);
+     if (ret)
+             return ret;
+
+     ret = cppc_set_ospm_nominal_perf(cpc_ptr->cpu_id, val);
+     if (ret)
+             return ret;
+
+     return count;
+}
+define_one_cppc_wo(ospm_nominal_perf);
+
   static struct attribute *cppc_attrs[] = {
       &feedback_ctrs.attr,

      &reference_perf.attr,

drivers/acpi/cppc_acpi.c +1 -0
@@ -222,6 +246,7 @@ static struct attribute *cppc_attrs[] = {
       &nominal_perf.attr,
       &nominal_freq.attr,
       &lowest_freq.attr,
+     &ospm_nominal_perf.attr,

      NULL
  };
  ATTRIBUTE_GROUPS(cppc);

drivers/acpi/cppc_acpi.c +2 -0
@@ -1683,6 +1708,23 @@ 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 allows OSPM to inform the platform of the nominal
+ * performance level it intends to maintain. This is a write-only register per
+ * ACPI specification.
+ *
+ * Return: 0 for success, -EOPNOTSUPP if not supported, -EIO otherwise.
+ */

drivers/acpi/cppc_acpi.c +3 -0
+int cppc_set_ospm_nominal_perf(int cpu, u64 ospm_nominal_perf)
+{
+     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 +10 -0
index 7e7f9dfb7a24..d06cba963550 100644
@@ -715,6 +715,16 @@ static int cppc_cpufreq_cpu_init(struct 
 cpufreq_policy *policy)
               goto out;
       }
 
+     /*
+      * Initialize OSPM Nominal Performance to inform firmware of
+      * OSPM's nominal level. Performance above this value = boost;
+      * below = throttle. Uses platform nominal by default.
+      */
+     ret = cppc_set_ospm_nominal_perf(cpu, caps->nominal_perf);
+     if (ret && ret != -EOPNOTSUPP)
+             pr_debug("Failed to set ospm_nominal_perf for CPU%d: 
 %d\n",
+                      cpu, ret);
+
       cppc_cpufreq_cpu_fie_init(policy);

      return 0;

include/acpi/cppc_acpi.h +1 -0
index 8693890a7275..ad1035b0e1de 100644
@@ -180,6 +180,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);

include/acpi/cppc_acpi.h +4 -0
@@ -266,6 +267,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;