Linux ACPI
 help / color / mirror / Atom feed
* [PATCHv2 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+
@ 2026-07-29 10:02 Christian Loehle
  2026-07-29 10:02 ` [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
                   ` (3 more replies)
  0 siblings, 4 replies; 17+ messages in thread
From: Christian Loehle @ 2026-07-29 10:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han, Christian Loehle

ACPI 6.6 changed the Optional Attribute of Desired Performance from
Read/Write to Write.

cppc-cpufreq reads Desired Performance when feedback counters cannot
provide a usable sample because some older platforms repurpose the
register to report actual delivered performance. Preserve that workaround
on systems reporting an older ACPI revision, but do not attempt the read
on ACPI 6.6 or later, where firmware no longer promises a readable value
and cppc-cpufreq can fall back to its cached OSPM request instead.

cppc_get_perf() also reads Desired Performance while populating the
control values used during cppc-cpufreq initialization. Its only in-tree
caller overwrites that value with highest_perf before the controls are
first written, so the value is never consumed.

Patches 1 and 2 provide minimal, backportable fixes for the two read
paths. Patch 3 simplifies the mainline API by no longer reading
Desired Performance through cppc_get_perf() on any ACPI revision.

Changes since v1:
- Mask the FADT minor revision's errata-generation bits.
- Add patch 2 as fix to also avoid reading Desired Performance from
cppc_get_perf(), as suggested by Zhongqiu Han.
- Add patch 3 to change the API as there's currently no in-tree use
of Desired Performance in cppc_get_perf()

Christian Loehle (3):
  ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
  ACPI: CPPC: Stop reading desired_perf in cppc_get_perf()

 drivers/acpi/cppc_acpi.c | 36 ++++++++++++++++++++++--------------
 1 file changed, 22 insertions(+), 14 deletions(-)

-- 
2.34.1

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  2026-07-29 10:02 [PATCHv2 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
@ 2026-07-29 10:02 ` Christian Loehle
  2026-07-31 10:45   ` Zhongqiu Han
  2026-07-31 20:52   ` Sumit Gupta
  2026-07-29 10:02 ` [PATCHv2 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 17+ messages in thread
From: Christian Loehle @ 2026-07-29 10:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han, Christian Loehle, stable

When CPPC feedback counters cannot provide a usable sample, cppc-cpufreq
calls cppc_get_desired_perf() because some platforms repurpose Desired
Performance to report actual delivered performance.

The fallback was added for platforms on which Desired Performance reflects
delivered performance. ACPI 6.6 defines the register as write-only, so
invoking that workaround on an ACPI 6.6 or later platform would require an
invalid register read.

Make cppc_get_desired_perf() return -EOPNOTSUPP in that case. Its caller
already handles an error by using the cached desired-performance value.
When checking the FADT minor revision, mask off its upper errata-generation
bits and compare only the specification minor version.

Fixes: c47195631960 ("cppc_cpufreq: Use desired perf if feedback ctrs are 0 or unchanged")
Cc: stable@vger.kernel.org
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
---
 drivers/acpi/cppc_acpi.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 53d09ca98f06..6e5381f8de38 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1316,15 +1316,28 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
 	return cpc_write(cpu, reg, val);
 }
 
+static bool cppc_desired_perf_readable(void)
+{
+	u8 minor_revision = acpi_gbl_FADT.minor_revision & 0x0f;
+
+	return acpi_gbl_FADT.header.revision < 6 ||
+	       (acpi_gbl_FADT.header.revision == 6 && minor_revision < 6);
+}
+
 /**
  * cppc_get_desired_perf - Get the desired performance register value.
  * @cpunum: CPU from which to get desired performance.
  * @desired_perf: Return address.
  *
- * Return: 0 for success, -EIO otherwise.
+ * Return: 0 for success, -EOPNOTSUPP for ACPI 6.6 or later, and a negative
+ * errno otherwise.
  */
 int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
 {
+	/* ACPI 6.6 no longer specifies Desired Performance as readable. */
+	if (!cppc_desired_perf_readable())
+		return -EOPNOTSUPP;
+
 	return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf);
 }
 EXPORT_SYMBOL_GPL(cppc_get_desired_perf);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
  2026-07-29 10:02 [PATCHv2 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
  2026-07-29 10:02 ` [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
@ 2026-07-29 10:02 ` Christian Loehle
  2026-07-31 12:38   ` Zhongqiu Han
  2026-07-29 10:02 ` [PATCHv2 3/3] ACPI: CPPC: Stop reading desired_perf " Christian Loehle
  2026-08-03 10:02 ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
  3 siblings, 1 reply; 17+ messages in thread
From: Christian Loehle @ 2026-07-29 10:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han, Christian Loehle, stable

ACPI 6.6 changed the Optional Attribute of Desired Performance from
Read/Write to Write. cppc_get_perf() nevertheless reads the register when
initializing performance controls, even though cppc-cpufreq overwrites the
value before using it.

Use the readability check from cppc_get_desired_perf() and leave
desired_perf zero instead of reading it on ACPI 6.6 or later. Also exclude
the register from PCC read-command detection so it cannot trigger an
otherwise unnecessary read command.

Fixes: 658fa7b1c47a ("ACPI: CPPC: Add cppc_get_perf() API to read performance controls")
Cc: stable@vger.kernel.org
Suggested-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
---
 drivers/acpi/cppc_acpi.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 6e5381f8de38..210988d57b71 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1843,6 +1843,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
 	int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
 	struct cppc_pcc_data *pcc_ss_data = NULL;
+	bool read_desired_perf = cppc_desired_perf_readable();
 	int ret = 0, regs_in_pcc = 0;
 
 	if (!cpc_desc) {
@@ -1862,7 +1863,8 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
 
 	/* Are any of the regs PCC ?*/
-	if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) ||
+	if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
+	    CPC_IN_PCC(min_perf_reg) ||
 	    CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
 	    CPC_IN_PCC(auto_sel_reg)) {
 		if (pcc_ss_id < 0) {
@@ -1894,7 +1896,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	}
 	perf_ctrls->min_perf = min;
 
-	if (CPC_SUPPORTED(desired_perf_reg)) {
+	if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
 		ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
 		if (ret)
 			goto out_err;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCHv2 3/3] ACPI: CPPC: Stop reading desired_perf in cppc_get_perf()
  2026-07-29 10:02 [PATCHv2 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
  2026-07-29 10:02 ` [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
  2026-07-29 10:02 ` [PATCHv2 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
@ 2026-07-29 10:02 ` Christian Loehle
  2026-07-31 13:19   ` Zhongqiu Han
  2026-08-03 10:02 ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
  3 siblings, 1 reply; 17+ messages in thread
From: Christian Loehle @ 2026-07-29 10:02 UTC (permalink / raw)
  To: Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han, Christian Loehle

cppc_get_perf() has one in-tree caller, cppc_cpufreq_get_cpu_data().
It uses the function to preserve existing controls before writing them, but
overwrites desired_perf with highest_perf before the first cppc_set_perf().
Consequently, the current Desired Performance value is not consumed.

Remove the Desired Performance read from this aggregate getter and
document that the field is returned as zero.

Signed-off-by: Christian Loehle <christian.loehle@arm.com>
---
 drivers/acpi/cppc_acpi.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 210988d57b71..8ce2033ba993 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1828,22 +1828,22 @@ int cppc_set_enable(int cpu, bool enable)
 EXPORT_SYMBOL_GPL(cppc_set_enable);
 
 /**
- * cppc_get_perf - Get a CPU's performance controls.
+ * cppc_get_perf - Get a CPU's readable performance controls.
  * @cpu: CPU for which to get performance controls.
  * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
  *
+ * Desired Performance is not read and is returned as 0.
+ *
  * Return: 0 for success with perf_ctrls, -ERRNO otherwise.
  */
 int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 {
 	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
-	struct cpc_register_resource *desired_perf_reg,
-				     *min_perf_reg, *max_perf_reg,
+	struct cpc_register_resource *min_perf_reg, *max_perf_reg,
 				     *energy_perf_reg, *auto_sel_reg;
-	u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
+	u64 min = 0, max = 0, energy_perf = 0, auto_sel = 0;
 	int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
 	struct cppc_pcc_data *pcc_ss_data = NULL;
-	bool read_desired_perf = cppc_desired_perf_readable();
 	int ret = 0, regs_in_pcc = 0;
 
 	if (!cpc_desc) {
@@ -1856,16 +1856,14 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 		return -EINVAL;
 	}
 
-	desired_perf_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
 	min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF];
 	max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF];
 	energy_perf_reg = &cpc_desc->cpc_regs[ENERGY_PERF];
 	auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
 
 	/* Are any of the regs PCC ?*/
-	if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
-	    CPC_IN_PCC(min_perf_reg) ||
-	    CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
+	if (CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg) ||
+	    CPC_IN_PCC(energy_perf_reg) ||
 	    CPC_IN_PCC(auto_sel_reg)) {
 		if (pcc_ss_id < 0) {
 			pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
@@ -1896,12 +1894,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	}
 	perf_ctrls->min_perf = min;
 
-	if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
-		ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
-		if (ret)
-			goto out_err;
-	}
-	perf_ctrls->desired_perf = desired_perf;
+	perf_ctrls->desired_perf = 0;
 
 	if (CPC_SUPPORTED(energy_perf_reg)) {
 		ret = cpc_read(cpu, energy_perf_reg, &energy_perf);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  2026-07-29 10:02 ` [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
@ 2026-07-31 10:45   ` Zhongqiu Han
  2026-08-03  9:12     ` Christian Loehle
  2026-07-31 20:52   ` Sumit Gupta
  1 sibling, 1 reply; 17+ messages in thread
From: Zhongqiu Han @ 2026-07-31 10:45 UTC (permalink / raw)
  To: Christian Loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, stable, zhongqiu.han

On 7/29/2026 6:02 PM, Christian Loehle wrote:
> When CPPC feedback counters cannot provide a usable sample, cppc-cpufreq
> calls cppc_get_desired_perf() because some platforms repurpose Desired
> Performance to report actual delivered performance.
> 
> The fallback was added for platforms on which Desired Performance reflects
> delivered performance. ACPI 6.6 defines the register as write-only, so
> invoking that workaround on an ACPI 6.6 or later platform would require an
> invalid register read.
> 
> Make cppc_get_desired_perf() return -EOPNOTSUPP in that case. Its caller
> already handles an error by using the cached desired-performance value.
> When checking the FADT minor revision, mask off its upper errata-generation
> bits and compare only the specification minor version.
> 
> Fixes: c47195631960 ("cppc_cpufreq: Use desired perf if feedback ctrs are 0 or unchanged")

Hi Christian,
Please feel free to correct me if there is any misunderstanding.

ACPI 6.6 was released on 05/13/2025:
https://uefi.org/sites/default/files/resources/ACPI_Spec_6.6.pdf

And the fixes tag commit c47195631960 was committed on 09/29/2024.

Would this be considered an adaptation rather than a regression fix?


With the Fixes tag confirmed/fixed:
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>

> Cc: stable@vger.kernel.org
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> ---
>   drivers/acpi/cppc_acpi.c | 15 ++++++++++++++-
>   1 file changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 53d09ca98f06..6e5381f8de38 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1316,15 +1316,28 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
>   	return cpc_write(cpu, reg, val);
>   }
>   
> +static bool cppc_desired_perf_readable(void)
> +{
> +	u8 minor_revision = acpi_gbl_FADT.minor_revision & 0x0f;
> +
> +	return acpi_gbl_FADT.header.revision < 6 ||
> +	       (acpi_gbl_FADT.header.revision == 6 && minor_revision < 6);
> +}
> +
>   /**
>    * cppc_get_desired_perf - Get the desired performance register value.
>    * @cpunum: CPU from which to get desired performance.
>    * @desired_perf: Return address.
>    *
> - * Return: 0 for success, -EIO otherwise.
> + * Return: 0 for success, -EOPNOTSUPP for ACPI 6.6 or later, and a negative
> + * errno otherwise.
>    */
>   int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
>   {
> +	/* ACPI 6.6 no longer specifies Desired Performance as readable. */
> +	if (!cppc_desired_perf_readable())
> +		return -EOPNOTSUPP;
> +
>   	return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf);
>   }
>   EXPORT_SYMBOL_GPL(cppc_get_desired_perf);


-- 
Thx and BRs,
Zhongqiu Han

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
  2026-07-29 10:02 ` [PATCHv2 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
@ 2026-07-31 12:38   ` Zhongqiu Han
  0 siblings, 0 replies; 17+ messages in thread
From: Zhongqiu Han @ 2026-07-31 12:38 UTC (permalink / raw)
  To: Christian Loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, stable, zhongqiu.han

On 7/29/2026 6:02 PM, Christian Loehle wrote:
> ACPI 6.6 changed the Optional Attribute of Desired Performance from
> Read/Write to Write. cppc_get_perf() nevertheless reads the register when
> initializing performance controls, even though cppc-cpufreq overwrites the
> value before using it.
> 
> Use the readability check from cppc_get_desired_perf() and leave
> desired_perf zero instead of reading it on ACPI 6.6 or later. Also exclude
> the register from PCC read-command detection so it cannot trigger an
> otherwise unnecessary read command.
> 
> Fixes: 658fa7b1c47a ("ACPI: CPPC: Add cppc_get_perf() API to read performance controls")
> Cc: stable@vger.kernel.org
> Suggested-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>

Looks good to me.

Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>

> ---
>   drivers/acpi/cppc_acpi.c | 6 ++++--
>   1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 6e5381f8de38..210988d57b71 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1843,6 +1843,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>   	u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
>   	int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
>   	struct cppc_pcc_data *pcc_ss_data = NULL;
> +	bool read_desired_perf = cppc_desired_perf_readable();
>   	int ret = 0, regs_in_pcc = 0;
>   
>   	if (!cpc_desc) {
> @@ -1862,7 +1863,8 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>   	auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
>   
>   	/* Are any of the regs PCC ?*/
> -	if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) ||
> +	if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
> +	    CPC_IN_PCC(min_perf_reg) ||
>   	    CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
>   	    CPC_IN_PCC(auto_sel_reg)) {
>   		if (pcc_ss_id < 0) {
> @@ -1894,7 +1896,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>   	}
>   	perf_ctrls->min_perf = min;
>   
> -	if (CPC_SUPPORTED(desired_perf_reg)) {
> +	if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
>   		ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
>   		if (ret)
>   			goto out_err;


-- 
Thx and BRs,
Zhongqiu Han

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 3/3] ACPI: CPPC: Stop reading desired_perf in cppc_get_perf()
  2026-07-29 10:02 ` [PATCHv2 3/3] ACPI: CPPC: Stop reading desired_perf " Christian Loehle
@ 2026-07-31 13:19   ` Zhongqiu Han
  0 siblings, 0 replies; 17+ messages in thread
From: Zhongqiu Han @ 2026-07-31 13:19 UTC (permalink / raw)
  To: Christian Loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

On 7/29/2026 6:02 PM, Christian Loehle wrote:
> cppc_get_perf() has one in-tree caller, cppc_cpufreq_get_cpu_data().
> It uses the function to preserve existing controls before writing them, but
> overwrites desired_perf with highest_perf before the first cppc_set_perf().
> Consequently, the current Desired Performance value is not consumed.
> 
> Remove the Desired Performance read from this aggregate getter and
> document that the field is returned as zero.
> 
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> ---
>   drivers/acpi/cppc_acpi.c | 23 ++++++++---------------
>   1 file changed, 8 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 210988d57b71..8ce2033ba993 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1828,22 +1828,22 @@ int cppc_set_enable(int cpu, bool enable)
>   EXPORT_SYMBOL_GPL(cppc_set_enable);
>   
>   /**
> - * cppc_get_perf - Get a CPU's performance controls.
> + * cppc_get_perf - Get a CPU's readable performance controls.

Small nit: is this also applicable to ACPI <6.6?

>    * @cpu: CPU for which to get performance controls.
>    * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
>    *
> + * Desired Performance is not read and is returned as 0.

Likewise.

> + *
>    * Return: 0 for success with perf_ctrls, -ERRNO otherwise.
>    */
>   int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>   {
>   	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
> -	struct cpc_register_resource *desired_perf_reg,
> -				     *min_perf_reg, *max_perf_reg,
> +	struct cpc_register_resource *min_perf_reg, *max_perf_reg,
>   				     *energy_perf_reg, *auto_sel_reg;
> -	u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
> +	u64 min = 0, max = 0, energy_perf = 0, auto_sel = 0;
>   	int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
>   	struct cppc_pcc_data *pcc_ss_data = NULL;
> -	bool read_desired_perf = cppc_desired_perf_readable();
>   	int ret = 0, regs_in_pcc = 0;
>   
>   	if (!cpc_desc) {
> @@ -1856,16 +1856,14 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>   		return -EINVAL;
>   	}
>   
> -	desired_perf_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
>   	min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF];
>   	max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF];
>   	energy_perf_reg = &cpc_desc->cpc_regs[ENERGY_PERF];
>   	auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
>   
>   	/* Are any of the regs PCC ?*/
> -	if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
> -	    CPC_IN_PCC(min_perf_reg) ||
> -	    CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
> +	if (CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg) ||
> +	    CPC_IN_PCC(energy_perf_reg) ||
>   	    CPC_IN_PCC(auto_sel_reg)) {
>   		if (pcc_ss_id < 0) {
>   			pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
> @@ -1896,12 +1894,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>   	}
>   	perf_ctrls->min_perf = min;
>   
> -	if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
> -		ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
> -		if (ret)
> -			goto out_err;
> -	}
> -	perf_ctrls->desired_perf = desired_perf;
> +	perf_ctrls->desired_perf = 0;
>   
>   	if (CPC_SUPPORTED(energy_perf_reg)) {
>   		ret = cpc_read(cpu, energy_perf_reg, &energy_perf);

This is an exported API, I'm not sure whether this would break any out
of-tree users, but I don't think compatibility concerns for out-of-tree
users should weigh heavily in this case.

Looks good to me.

Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>

-- 
Thx and BRs,
Zhongqiu Han

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  2026-07-29 10:02 ` [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
  2026-07-31 10:45   ` Zhongqiu Han
@ 2026-07-31 20:52   ` Sumit Gupta
  1 sibling, 0 replies; 17+ messages in thread
From: Sumit Gupta @ 2026-07-31 20:52 UTC (permalink / raw)
  To: Christian Loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sudeep Holla, Ionela Voinescu,
	zhongqiu.han, stable


On 29/07/26 15:32, Christian Loehle wrote:
> External email: Use caution opening links or attachments
>
>
> When CPPC feedback counters cannot provide a usable sample, cppc-cpufreq
> calls cppc_get_desired_perf() because some platforms repurpose Desired
> Performance to report actual delivered performance.
>
> The fallback was added for platforms on which Desired Performance reflects
> delivered performance. ACPI 6.6 defines the register as write-only, so
> invoking that workaround on an ACPI 6.6 or later platform would require an
> invalid register read.
>
> Make cppc_get_desired_perf() return -EOPNOTSUPP in that case. Its caller
> already handles an error by using the cached desired-performance value.
> When checking the FADT minor revision, mask off its upper errata-generation
> bits and compare only the specification minor version.
>
> Fixes: c47195631960 ("cppc_cpufreq: Use desired perf if feedback ctrs are 0 or unchanged")
> Cc: stable@vger.kernel.org
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> ---
>   drivers/acpi/cppc_acpi.c | 15 ++++++++++++++-
>   1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 53d09ca98f06..6e5381f8de38 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1316,15 +1316,28 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
>          return cpc_write(cpu, reg, val);
>   }
>
> +static bool cppc_desired_perf_readable(void)
> +{
> +       u8 minor_revision = acpi_gbl_FADT.minor_revision & 0x0f;
> +
> +       return acpi_gbl_FADT.header.revision < 6 ||
> +              (acpi_gbl_FADT.header.revision == 6 && minor_revision < 6);
> +}
> +

A platform whose _CPC follows ACPI 6.6 semantics but whose FADT still
reports 6.5 would pass this check as readable. If the register read
returns zero, cppc_cpufreq_get_rate() reports 0 kHz and policy online
fails with:
   cpufreq: cpufreq_policy_online: ->get() failed

Since the FADT version cannot be fully relied upon, would it make sense
to also harden the consumer? Although zero is valid Desired Performance
value, it is not usable as a frequency estimate.
So, cppc_cpufreq_get_rate() could fall back to the cached OSPM request:

   -    if (cppc_get_desired_perf(cpu, &delivered_perf))
   +    if (cppc_get_desired_perf(cpu, &delivered_perf) || !delivered_perf)
             delivered_perf = cpu_data->perf_ctrls.desired_perf;

Thanks,
Sumit


>   /**
>    * cppc_get_desired_perf - Get the desired performance register value.
>    * @cpunum: CPU from which to get desired performance.
>    * @desired_perf: Return address.
>    *
> - * Return: 0 for success, -EIO otherwise.
> + * Return: 0 for success, -EOPNOTSUPP for ACPI 6.6 or later, and a negative
> + * errno otherwise.
>    */
>   int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
>   {
> +       /* ACPI 6.6 no longer specifies Desired Performance as readable. */
> +       if (!cppc_desired_perf_readable())
> +               return -EOPNOTSUPP;
> +
>          return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf);
>   }
>   EXPORT_SYMBOL_GPL(cppc_get_desired_perf);
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  2026-07-31 10:45   ` Zhongqiu Han
@ 2026-08-03  9:12     ` Christian Loehle
  0 siblings, 0 replies; 17+ messages in thread
From: Christian Loehle @ 2026-08-03  9:12 UTC (permalink / raw)
  To: Zhongqiu Han, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, stable

On 7/31/26 11:45, Zhongqiu Han wrote:
> On 7/29/2026 6:02 PM, Christian Loehle wrote:
>> When CPPC feedback counters cannot provide a usable sample, cppc-cpufreq
>> calls cppc_get_desired_perf() because some platforms repurpose Desired
>> Performance to report actual delivered performance.
>>
>> The fallback was added for platforms on which Desired Performance reflects
>> delivered performance. ACPI 6.6 defines the register as write-only, so
>> invoking that workaround on an ACPI 6.6 or later platform would require an
>> invalid register read.
>>
>> Make cppc_get_desired_perf() return -EOPNOTSUPP in that case. Its caller
>> already handles an error by using the cached desired-performance value.
>> When checking the FADT minor revision, mask off its upper errata-generation
>> bits and compare only the specification minor version.
>>
>> Fixes: c47195631960 ("cppc_cpufreq: Use desired perf if feedback ctrs are 0 or unchanged")
> 
> Hi Christian,
> Please feel free to correct me if there is any misunderstanding.
> 
> ACPI 6.6 was released on 05/13/2025:
> https://uefi.org/sites/default/files/resources/ACPI_Spec_6.6.pdf
> 
> And the fixes tag commit c47195631960 was committed on 09/29/2024.
> 
> Would this be considered an adaptation rather than a regression fix?


That is all correct, but the fixes tag is supposed to mean "this patch makes
the commit in question work" (and therefore should be backported to all kernels
containing this), which is then correct, as older kernels may still boot on
newer (6.6) ACPI systems.
It doesn't mean that the mentioned commit is 'bad' or 'wrong'.


> 
> 
> With the Fixes tag confirmed/fixed:
> Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Thanks, I'll leave as-is and pick this up if you don't mind.

> 
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
>> ---
>>   drivers/acpi/cppc_acpi.c | 15 ++++++++++++++-
>>   1 file changed, 14 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
>> index 53d09ca98f06..6e5381f8de38 100644
>> --- a/drivers/acpi/cppc_acpi.c
>> +++ b/drivers/acpi/cppc_acpi.c
>> @@ -1316,15 +1316,28 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
>>       return cpc_write(cpu, reg, val);
>>   }
>>   +static bool cppc_desired_perf_readable(void)
>> +{
>> +    u8 minor_revision = acpi_gbl_FADT.minor_revision & 0x0f;
>> +
>> +    return acpi_gbl_FADT.header.revision < 6 ||
>> +           (acpi_gbl_FADT.header.revision == 6 && minor_revision < 6);
>> +}
>> +
>>   /**
>>    * cppc_get_desired_perf - Get the desired performance register value.
>>    * @cpunum: CPU from which to get desired performance.
>>    * @desired_perf: Return address.
>>    *
>> - * Return: 0 for success, -EIO otherwise.
>> + * Return: 0 for success, -EOPNOTSUPP for ACPI 6.6 or later, and a negative
>> + * errno otherwise.
>>    */
>>   int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
>>   {
>> +    /* ACPI 6.6 no longer specifies Desired Performance as readable. */
>> +    if (!cppc_desired_perf_readable())
>> +        return -EOPNOTSUPP;
>> +
>>       return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf);
>>   }
>>   EXPORT_SYMBOL_GPL(cppc_get_desired_perf);
> 
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+
  2026-07-29 10:02 [PATCHv2 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
                   ` (2 preceding siblings ...)
  2026-07-29 10:02 ` [PATCHv2 3/3] ACPI: CPPC: Stop reading desired_perf " Christian Loehle
@ 2026-08-03 10:02 ` Christian Loehle
  2026-08-03 10:02   ` [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
                     ` (3 more replies)
  3 siblings, 4 replies; 17+ messages in thread
From: Christian Loehle @ 2026-08-03 10:02 UTC (permalink / raw)
  To: christian.loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

ACPI 6.6 changed the Optional Attribute of Desired Performance from
Read/Write to Write.

cppc-cpufreq reads Desired Performance when feedback counters cannot
provide a usable sample because some older platforms repurpose the
register to report actual delivered performance. Preserve that workaround
on systems reporting an older ACPI revision, but do not attempt the read
on ACPI 6.6 or later, where firmware no longer promises a readable value
and cppc-cpufreq can fall back to its cached OSPM request instead.

cppc_get_perf() also reads Desired Performance while populating the
control values used during cppc-cpufreq initialization. Its only in-tree
caller overwrites that value with highest_perf before the controls are
first written, so the value is never consumed.

Patches 1 and 2 provide minimal, backportable fixes for the two read
paths. Patch 3 simplifies the mainline API by no longer reading
Desired Performance through cppc_get_perf() on any ACPI revision.

Changes since v2:
- Fall back to the cached OSPM request when reading Desired Performance
  returns zero as suggested by Sumit Gupta.
- Pick up Reviewed-by tags from Zhongqiu Han for patches 2 and 3.
- Rebase onto v7.2-rc6

Christian Loehle (3):
  ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
  ACPI: CPPC: Stop reading desired_perf in cppc_get_perf()

 drivers/acpi/cppc_acpi.c       | 36 +++++++++++++++++++++-------------
 drivers/cpufreq/cppc_cpufreq.c |  2 +-
 2 files changed, 23 insertions(+), 15 deletions(-)


base-commit: 075b74841bd0065a3bda3440873c747938e69b68
-- 
2.34.1

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  2026-08-03 10:02 ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
@ 2026-08-03 10:02   ` Christian Loehle
  2026-08-03 14:38     ` Rafael J. Wysocki (Intel)
  2026-08-03 10:02   ` [PATCH v3 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 17+ messages in thread
From: Christian Loehle @ 2026-08-03 10:02 UTC (permalink / raw)
  To: christian.loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

When CPPC feedback counters cannot provide a usable sample, cppc-cpufreq
calls cppc_get_desired_perf() because some platforms repurpose Desired
Performance to report actual delivered performance.

The fallback was added for platforms on which Desired Performance reflects
delivered performance. ACPI 6.6 defines the register as write-only, so
invoking that workaround on an ACPI 6.6 or later platform would require an
invalid register read.

Make cppc_get_desired_perf() return -EOPNOTSUPP in that case. When checking
the FADT minor revision, mask off its upper errata-generation bits and
compare only the specification minor version.

The FADT revision may not accurately describe the semantics implemented by
_CPC. If a nominally pre-6.6 platform implements Desired Performance as
write-only, a read may return zero and make cppc_cpufreq_get_rate() report
0 kHz. Treat a zero read as unusable and fall back to the cached OSPM
request, just as for a failed read.

Fixes: c47195631960 ("cppc_cpufreq: Use desired perf if feedback ctrs are 0 or unchanged")
Cc: stable@vger.kernel.org
Suggested-by: Sumit Gupta <sumitg@nvidia.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
---
 drivers/acpi/cppc_acpi.c       | 15 ++++++++++++++-
 drivers/cpufreq/cppc_cpufreq.c |  2 +-
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 53d09ca98f06..6e5381f8de38 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1316,15 +1316,28 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
 	return cpc_write(cpu, reg, val);
 }
 
+static bool cppc_desired_perf_readable(void)
+{
+	u8 minor_revision = acpi_gbl_FADT.minor_revision & 0x0f;
+
+	return acpi_gbl_FADT.header.revision < 6 ||
+	       (acpi_gbl_FADT.header.revision == 6 && minor_revision < 6);
+}
+
 /**
  * cppc_get_desired_perf - Get the desired performance register value.
  * @cpunum: CPU from which to get desired performance.
  * @desired_perf: Return address.
  *
- * Return: 0 for success, -EIO otherwise.
+ * Return: 0 for success, -EOPNOTSUPP for ACPI 6.6 or later, and a negative
+ * errno otherwise.
  */
 int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
 {
+	/* ACPI 6.6 no longer specifies Desired Performance as readable. */
+	if (!cppc_desired_perf_readable())
+		return -EOPNOTSUPP;
+
 	return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf);
 }
 EXPORT_SYMBOL_GPL(cppc_get_desired_perf);
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 6fe0e972952a..80893844353c 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -836,7 +836,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
 	 * value first as some platforms may update the actual delivered perf
 	 * there; if failed, resort to the cached desired perf.
 	 */
-	if (cppc_get_desired_perf(cpu, &delivered_perf))
+	if (cppc_get_desired_perf(cpu, &delivered_perf) || !delivered_perf)
 		delivered_perf = cpu_data->perf_ctrls.desired_perf;
 
 	return cppc_perf_to_khz(&cpu_data->perf_caps, delivered_perf);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
  2026-08-03 10:02 ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
  2026-08-03 10:02   ` [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
@ 2026-08-03 10:02   ` Christian Loehle
  2026-08-03 14:43     ` Rafael J. Wysocki (Intel)
  2026-08-03 10:02   ` [PATCH v3 3/3] ACPI: CPPC: Stop reading desired_perf " Christian Loehle
  2026-08-03 13:07   ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Sumit Gupta
  3 siblings, 1 reply; 17+ messages in thread
From: Christian Loehle @ 2026-08-03 10:02 UTC (permalink / raw)
  To: christian.loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

ACPI 6.6 changed the Optional Attribute of Desired Performance from
Read/Write to Write. cppc_get_perf() nevertheless reads the register when
initializing performance controls, even though cppc-cpufreq overwrites the
value before using it.

Use the readability check from cppc_get_desired_perf() and leave
desired_perf zero instead of reading it on ACPI 6.6 or later. Also exclude
the register from PCC read-command detection so it cannot trigger an
otherwise unnecessary read command.

Fixes: 658fa7b1c47a ("ACPI: CPPC: Add cppc_get_perf() API to read performance controls")
Cc: stable@vger.kernel.org
Suggested-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
---
 drivers/acpi/cppc_acpi.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 6e5381f8de38..210988d57b71 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1843,6 +1843,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
 	int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
 	struct cppc_pcc_data *pcc_ss_data = NULL;
+	bool read_desired_perf = cppc_desired_perf_readable();
 	int ret = 0, regs_in_pcc = 0;
 
 	if (!cpc_desc) {
@@ -1862,7 +1863,8 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
 
 	/* Are any of the regs PCC ?*/
-	if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) ||
+	if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
+	    CPC_IN_PCC(min_perf_reg) ||
 	    CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
 	    CPC_IN_PCC(auto_sel_reg)) {
 		if (pcc_ss_id < 0) {
@@ -1894,7 +1896,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	}
 	perf_ctrls->min_perf = min;
 
-	if (CPC_SUPPORTED(desired_perf_reg)) {
+	if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
 		ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
 		if (ret)
 			goto out_err;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 3/3] ACPI: CPPC: Stop reading desired_perf in cppc_get_perf()
  2026-08-03 10:02 ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
  2026-08-03 10:02   ` [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
  2026-08-03 10:02   ` [PATCH v3 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
@ 2026-08-03 10:02   ` Christian Loehle
  2026-08-03 13:07   ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Sumit Gupta
  3 siblings, 0 replies; 17+ messages in thread
From: Christian Loehle @ 2026-08-03 10:02 UTC (permalink / raw)
  To: christian.loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

cppc_get_perf() has one in-tree caller, cppc_cpufreq_get_cpu_data().
It uses the function to preserve existing controls before writing them, but
overwrites desired_perf with highest_perf before the first cppc_set_perf().
Consequently, the current Desired Performance value is not consumed.

Remove the Desired Performance read from this aggregate getter and
document that the field is returned as zero.

Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
Signed-off-by: Christian Loehle <christian.loehle@arm.com>
---
 drivers/acpi/cppc_acpi.c | 23 ++++++++---------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 210988d57b71..8ce2033ba993 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1828,22 +1828,22 @@ int cppc_set_enable(int cpu, bool enable)
 EXPORT_SYMBOL_GPL(cppc_set_enable);
 
 /**
- * cppc_get_perf - Get a CPU's performance controls.
+ * cppc_get_perf - Get a CPU's readable performance controls.
  * @cpu: CPU for which to get performance controls.
  * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
  *
+ * Desired Performance is not read and is returned as 0.
+ *
  * Return: 0 for success with perf_ctrls, -ERRNO otherwise.
  */
 int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 {
 	struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
-	struct cpc_register_resource *desired_perf_reg,
-				     *min_perf_reg, *max_perf_reg,
+	struct cpc_register_resource *min_perf_reg, *max_perf_reg,
 				     *energy_perf_reg, *auto_sel_reg;
-	u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
+	u64 min = 0, max = 0, energy_perf = 0, auto_sel = 0;
 	int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
 	struct cppc_pcc_data *pcc_ss_data = NULL;
-	bool read_desired_perf = cppc_desired_perf_readable();
 	int ret = 0, regs_in_pcc = 0;
 
 	if (!cpc_desc) {
@@ -1856,16 +1856,14 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 		return -EINVAL;
 	}
 
-	desired_perf_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
 	min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF];
 	max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF];
 	energy_perf_reg = &cpc_desc->cpc_regs[ENERGY_PERF];
 	auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
 
 	/* Are any of the regs PCC ?*/
-	if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
-	    CPC_IN_PCC(min_perf_reg) ||
-	    CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
+	if (CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg) ||
+	    CPC_IN_PCC(energy_perf_reg) ||
 	    CPC_IN_PCC(auto_sel_reg)) {
 		if (pcc_ss_id < 0) {
 			pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
@@ -1896,12 +1894,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
 	}
 	perf_ctrls->min_perf = min;
 
-	if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
-		ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
-		if (ret)
-			goto out_err;
-	}
-	perf_ctrls->desired_perf = desired_perf;
+	perf_ctrls->desired_perf = 0;
 
 	if (CPC_SUPPORTED(energy_perf_reg)) {
 		ret = cpc_read(cpu, energy_perf_reg, &energy_perf);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+
  2026-08-03 10:02 ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
                     ` (2 preceding siblings ...)
  2026-08-03 10:02   ` [PATCH v3 3/3] ACPI: CPPC: Stop reading desired_perf " Christian Loehle
@ 2026-08-03 13:07   ` Sumit Gupta
  3 siblings, 0 replies; 17+ messages in thread
From: Sumit Gupta @ 2026-08-03 13:07 UTC (permalink / raw)
  To: Christian Loehle, Rafael J . Wysocki, Viresh Kumar
  Cc: linux-pm, linux-acpi, linux-kernel, Len Brown, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sudeep Holla, Ionela Voinescu,
	zhongqiu.han


On 03/08/26 15:32, Christian Loehle wrote:
> External email: Use caution opening links or attachments
>
>
> ACPI 6.6 changed the Optional Attribute of Desired Performance from
> Read/Write to Write.
>
> cppc-cpufreq reads Desired Performance when feedback counters cannot
> provide a usable sample because some older platforms repurpose the
> register to report actual delivered performance. Preserve that workaround
> on systems reporting an older ACPI revision, but do not attempt the read
> on ACPI 6.6 or later, where firmware no longer promises a readable value
> and cppc-cpufreq can fall back to its cached OSPM request instead.
>
> cppc_get_perf() also reads Desired Performance while populating the
> control values used during cppc-cpufreq initialization. Its only in-tree
> caller overwrites that value with highest_perf before the controls are
> first written, so the value is never consumed.
>
> Patches 1 and 2 provide minimal, backportable fixes for the two read
> paths. Patch 3 simplifies the mainline API by no longer reading
> Desired Performance through cppc_get_perf() on any ACPI revision.
>
> Changes since v2:
> - Fall back to the cached OSPM request when reading Desired Performance
>    returns zero as suggested by Sumit Gupta.
> - Pick up Reviewed-by tags from Zhongqiu Han for patches 2 and 3.
> - Rebase onto v7.2-rc6
>
> Christian Loehle (3):
>    ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
>    ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
>    ACPI: CPPC: Stop reading desired_perf in cppc_get_perf()

For the entire series:
   Reviewed-by: Sumit Gupta <sumitg@nvidia.com>

Thanks,
Sumit



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  2026-08-03 10:02   ` [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
@ 2026-08-03 14:38     ` Rafael J. Wysocki (Intel)
  2026-08-03 14:44       ` Christian Loehle
  0 siblings, 1 reply; 17+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-08-03 14:38 UTC (permalink / raw)
  To: Christian Loehle
  Cc: Viresh Kumar, linux-pm, linux-acpi, linux-kernel, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

On Mon, Aug 3, 2026 at 12:03 PM Christian Loehle
<christian.loehle@arm.com> wrote:
>
> When CPPC feedback counters cannot provide a usable sample, cppc-cpufreq
> calls cppc_get_desired_perf() because some platforms repurpose Desired
> Performance to report actual delivered performance.
>
> The fallback was added for platforms on which Desired Performance reflects
> delivered performance. ACPI 6.6 defines the register as write-only, so
> invoking that workaround on an ACPI 6.6 or later platform would require an
> invalid register read.
>
> Make cppc_get_desired_perf() return -EOPNOTSUPP in that case. When checking
> the FADT minor revision, mask off its upper errata-generation bits and
> compare only the specification minor version.

I'm wondering if the _CPC revision can be used for this instead of the
spec revision?

The _CPC revision changed from 3 to 4 between ACPI 6.5 and ACPI 6.6,
so doing that should be straightforward.

> The FADT revision may not accurately describe the semantics implemented by
> _CPC. If a nominally pre-6.6 platform implements Desired Performance as
> write-only, a read may return zero and make cppc_cpufreq_get_rate() report
> 0 kHz. Treat a zero read as unusable and fall back to the cached OSPM
> request, just as for a failed read.
>
> Fixes: c47195631960 ("cppc_cpufreq: Use desired perf if feedback ctrs are 0 or unchanged")
> Cc: stable@vger.kernel.org
> Suggested-by: Sumit Gupta <sumitg@nvidia.com>
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> ---
>  drivers/acpi/cppc_acpi.c       | 15 ++++++++++++++-
>  drivers/cpufreq/cppc_cpufreq.c |  2 +-
>  2 files changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 53d09ca98f06..6e5381f8de38 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1316,15 +1316,28 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val)
>         return cpc_write(cpu, reg, val);
>  }
>
> +static bool cppc_desired_perf_readable(void)
> +{
> +       u8 minor_revision = acpi_gbl_FADT.minor_revision & 0x0f;
> +
> +       return acpi_gbl_FADT.header.revision < 6 ||
> +              (acpi_gbl_FADT.header.revision == 6 && minor_revision < 6);
> +}
> +
>  /**
>   * cppc_get_desired_perf - Get the desired performance register value.
>   * @cpunum: CPU from which to get desired performance.
>   * @desired_perf: Return address.
>   *
> - * Return: 0 for success, -EIO otherwise.
> + * Return: 0 for success, -EOPNOTSUPP for ACPI 6.6 or later, and a negative
> + * errno otherwise.
>   */
>  int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
>  {
> +       /* ACPI 6.6 no longer specifies Desired Performance as readable. */
> +       if (!cppc_desired_perf_readable())
> +               return -EOPNOTSUPP;
> +
>         return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf);
>  }
>  EXPORT_SYMBOL_GPL(cppc_get_desired_perf);
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index 6fe0e972952a..80893844353c 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -836,7 +836,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
>          * value first as some platforms may update the actual delivered perf
>          * there; if failed, resort to the cached desired perf.
>          */
> -       if (cppc_get_desired_perf(cpu, &delivered_perf))
> +       if (cppc_get_desired_perf(cpu, &delivered_perf) || !delivered_perf)
>                 delivered_perf = cpu_data->perf_ctrls.desired_perf;
>
>         return cppc_perf_to_khz(&cpu_data->perf_caps, delivered_perf);
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
  2026-08-03 10:02   ` [PATCH v3 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
@ 2026-08-03 14:43     ` Rafael J. Wysocki (Intel)
  0 siblings, 0 replies; 17+ messages in thread
From: Rafael J. Wysocki (Intel) @ 2026-08-03 14:43 UTC (permalink / raw)
  To: Christian Loehle
  Cc: Viresh Kumar, linux-pm, linux-acpi, linux-kernel, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

On Mon, Aug 3, 2026 at 12:03 PM Christian Loehle
<christian.loehle@arm.com> wrote:
>
> ACPI 6.6 changed the Optional Attribute of Desired Performance from
> Read/Write to Write. cppc_get_perf() nevertheless reads the register when
> initializing performance controls, even though cppc-cpufreq overwrites the
> value before using it.

IMV it would be better to say that the change from R/W to W happened
between _CPC rev 3 (in ACPI 6.5) and _CPC rev 4 (in ACPI 6.6).

It would also be better to refer to the _CPC revision in the paragraph below.

> Use the readability check from cppc_get_desired_perf() and leave
> desired_perf zero instead of reading it on ACPI 6.6 or later. Also exclude
> the register from PCC read-command detection so it cannot trigger an
> otherwise unnecessary read command.
>
> Fixes: 658fa7b1c47a ("ACPI: CPPC: Add cppc_get_perf() API to read performance controls")
> Cc: stable@vger.kernel.org
> Suggested-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
> Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
> Signed-off-by: Christian Loehle <christian.loehle@arm.com>
> ---
>  drivers/acpi/cppc_acpi.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 6e5381f8de38..210988d57b71 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1843,6 +1843,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>         u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
>         int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
>         struct cppc_pcc_data *pcc_ss_data = NULL;
> +       bool read_desired_perf = cppc_desired_perf_readable();
>         int ret = 0, regs_in_pcc = 0;
>
>         if (!cpc_desc) {
> @@ -1862,7 +1863,8 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>         auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
>
>         /* Are any of the regs PCC ?*/
> -       if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) ||
> +       if ((read_desired_perf && CPC_IN_PCC(desired_perf_reg)) ||
> +           CPC_IN_PCC(min_perf_reg) ||
>             CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
>             CPC_IN_PCC(auto_sel_reg)) {
>                 if (pcc_ss_id < 0) {
> @@ -1894,7 +1896,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
>         }
>         perf_ctrls->min_perf = min;
>
> -       if (CPC_SUPPORTED(desired_perf_reg)) {
> +       if (read_desired_perf && CPC_SUPPORTED(desired_perf_reg)) {
>                 ret = cpc_read(cpu, desired_perf_reg, &desired_perf);
>                 if (ret)
>                         goto out_err;
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf reads on ACPI 6.6+
  2026-08-03 14:38     ` Rafael J. Wysocki (Intel)
@ 2026-08-03 14:44       ` Christian Loehle
  0 siblings, 0 replies; 17+ messages in thread
From: Christian Loehle @ 2026-08-03 14:44 UTC (permalink / raw)
  To: Rafael J. Wysocki (Intel)
  Cc: Viresh Kumar, linux-pm, linux-acpi, linux-kernel, Jie Zhan,
	Lifeng Zheng, Pierre Gondois, Sumit Gupta, Sudeep Holla,
	Ionela Voinescu, zhongqiu.han

On 8/3/26 15:38, Rafael J. Wysocki (Intel) wrote:
>> When CPPC feedback counters cannot provide a usable sample, cppc-cpufreq
>> calls cppc_get_desired_perf() because some platforms repurpose Desired
>> Performance to report actual delivered performance.
>>
>> The fallback was added for platforms on which Desired Performance reflects
>> delivered performance. ACPI 6.6 defines the register as write-only, so
>> invoking that workaround on an ACPI 6.6 or later platform would require an
>> invalid register read.
>>
>> Make cppc_get_desired_perf() return -EOPNOTSUPP in that case. When checking
>> the FADT minor revision, mask off its upper errata-generation bits and
>> compare only the specification minor version.
> I'm wondering if the _CPC revision can be used for this instead of the
> spec revision?
> 
> The _CPC revision changed from 3 to 4 between ACPI 6.5 and ACPI 6.6,
> so doing that should be straightforward.

Yup you're correct, much nicer, I'll fix that

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-08-03 14:44 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29 10:02 [PATCHv2 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
2026-07-29 10:02 ` [PATCHv2 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
2026-07-31 10:45   ` Zhongqiu Han
2026-08-03  9:12     ` Christian Loehle
2026-07-31 20:52   ` Sumit Gupta
2026-07-29 10:02 ` [PATCHv2 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
2026-07-31 12:38   ` Zhongqiu Han
2026-07-29 10:02 ` [PATCHv2 3/3] ACPI: CPPC: Stop reading desired_perf " Christian Loehle
2026-07-31 13:19   ` Zhongqiu Han
2026-08-03 10:02 ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Christian Loehle
2026-08-03 10:02   ` [PATCH v3 1/3] ACPI: CPPC: Reject desired_perf " Christian Loehle
2026-08-03 14:38     ` Rafael J. Wysocki (Intel)
2026-08-03 14:44       ` Christian Loehle
2026-08-03 10:02   ` [PATCH v3 2/3] ACPI: CPPC: Skip desired_perf read in cppc_get_perf() Christian Loehle
2026-08-03 14:43     ` Rafael J. Wysocki (Intel)
2026-08-03 10:02   ` [PATCH v3 3/3] ACPI: CPPC: Stop reading desired_perf " Christian Loehle
2026-08-03 13:07   ` [PATCH v3 0/3] ACPI: CPPC: Avoid Desired Performance reads on ACPI 6.6+ Sumit Gupta

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox