[PATCH 14/15] ACPI: CPPC: Validate SystemIO overlaps across processors

From: Christian Loehle

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


System I/O port space is global, but the overlap check only compares
registers within one _CPC package. Whole-width accesses from different
processors can therefore target partially overlapping port ranges and
clobber each other.

Extend the physical interval registry to SystemIO. Permit read-only
overlap and exact full-width aliases of the same logical CPPC entry.
Reject every other cross-processor overlap involving a writable entry.

Fixes: a2c8f92bea5f ("ACPI: CPPC: Implement support for SystemIO registers")
Signed-off-by: Christian Loehle <christian.loehle@xxxxxxx>
---
drivers/acpi/cppc_acpi.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index bcb3a6f075f0..621b190aea3c 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -138,6 +138,7 @@ INTERVAL_TREE_DEFINE(struct cpc_non_mmio_node, rb, u64, subtree_last,
cpc_non_mmio_itree)

static struct rb_root_cached cpc_pcc_trees[MAX_PCC_SUBSPACES];
+static struct rb_root_cached cpc_sysio_tree = RB_ROOT_CACHED;
static DEFINE_MUTEX(cpc_non_mmio_lock);

static struct cpc_sysmem_node *cpc_sysmem_first(u64 start, u64 last)
@@ -590,6 +591,8 @@ static struct rb_root_cached *cpc_non_mmio_tree(u8 space_id, u8 pcc_ss_id)
{
if (space_id == ACPI_ADR_SPACE_PLATFORM_COMM)
return &cpc_pcc_trees[pcc_ss_id];
+ if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+ return &cpc_sysio_tree;
return NULL;
}

@@ -607,7 +610,8 @@ static int cpc_validate_non_mmio_pair(const struct cpc_non_mmio_node *a,
a->last == b->last)
return 0;

- name = "PCC";
+ name = a->space_id == ACPI_ADR_SPACE_PLATFORM_COMM ?
+ "PCC" : "SystemIO";
pr_err("CPU%d: %s _CPC register %u conflicts with CPU%d register %u\n",
a->desc->cpu_id, name, a->reg_idx, b->desc->cpu_id,
b->reg_idx);
@@ -662,10 +666,11 @@ static int cpc_register_non_mmio_desc(struct cpc_desc *cpc_desc,
continue;

space_id = reg->cpc_entry.reg.space_id;
- if (space_id != ACPI_ADR_SPACE_PLATFORM_COMM)
+ if (space_id != ACPI_ADR_SPACE_PLATFORM_COMM &&
+ space_id != ACPI_ADR_SPACE_SYSTEM_IO)
continue;

- if (pcc_ss_id < 0) {
+ if (space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id < 0) {
ret = -EINVAL;
goto out_unregister;
}
@@ -677,7 +682,8 @@ static int cpc_register_non_mmio_desc(struct cpc_desc *cpc_desc,
node->desc = cpc_desc;
node->reg_idx = i;
node->space_id = space_id;
- node->pcc_ss_id = pcc_ss_id;
+ node->pcc_ss_id = space_id == ACPI_ADR_SPACE_PLATFORM_COMM ?
+ pcc_ss_id : 0;
tree = cpc_non_mmio_tree(space_id, node->pcc_ss_id);

match = cpc_non_mmio_itree_iter_first(tree, node->start,
--
2.34.1