[PATCH 05/15] ACPI: CPPC: Serialize PCC single-register payload updates

From: Christian Loehle

Date: Fri Aug 07 2026 - 07:19:06 EST


The PCC doorbell protocol requires OSPM to confirm ownership of the shared
subspace before placing a command and its payload there.
cppc_set_reg_val_in_pcc() instead modifies the payload before taking
pcc_lock.

A concurrent command can consequently overwrite or consume the staged
value, and OSPM can write the shared region while the platform still owns
it.

Take the PCC write lock first, wait for the previous command to complete,
and keep the lock held while staging the value and submitting CMD_WRITE.
This follows the ownership sequence in ACPI 6.5 Section 14.5 and the
existing contract documented by send_pcc_cmd().

Fixes: e05c75072c2e ("ACPI: CPPC: Add cppc_set_reg_val()")
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Link: https://sashiko.dev/#/patchset/20260724134251.1632824-1-christian.loehle%40arm.com
Signed-off-by: Christian Loehle <christian.loehle@xxxxxxx>
---
drivers/acpi/cppc_acpi.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index bfbdf3294017..ca8fd092b44f 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1453,7 +1453,7 @@ static int cppc_get_reg_val(int cpu, enum cppc_regs reg_idx, u64 *val)
static int cppc_set_reg_val_in_pcc(int cpu, struct cpc_register_resource *reg, u64 val)
{
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
- struct cppc_pcc_data *pcc_ss_data = NULL;
+ struct cppc_pcc_data *pcc_ss_data;
int ret;

if (pcc_ss_id < 0) {
@@ -1461,15 +1461,24 @@ static int cppc_set_reg_val_in_pcc(int cpu, struct cpc_register_resource *reg, u
return -ENODEV;
}

- ret = cpc_write(cpu, reg, val);
- if (ret)
- return ret;
-
pcc_ss_data = pcc_data[pcc_ss_id];
+ if (!pcc_ss_data)
+ return -ENODEV;

down_write(&pcc_ss_data->pcc_lock);
+
+ ret = check_pcc_chan(pcc_ss_id, false);
+ if (ret)
+ goto out;
+
+ ret = cpc_write(cpu, reg, val);
+ if (ret)
+ goto out;
+
/* after writing CPC, transfer the ownership of PCC to platform */
ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
+
+out:
up_write(&pcc_ss_data->pcc_lock);

return ret;
--
2.34.1