[PATCH 3/8] ACPI: CPPC: Refactor resource cleanup into free_reg_resource()

From: Lifeng Zheng

Date: Thu Jul 16 2026 - 22:47:15 EST


Both the error path of acpi_cppc_processor_probe() and the normal
cleanup in acpi_cppc_processor_exit() iterate over the cpc_regs[]
array and iounmap() any SystemMemory virtual addresses that were
set up during probe.

CPPC v4 adds Package-type entries that own dynamically allocated
sub-elements which also need to be freed. Inlining this recursive
cleanup at every call-site would be error-prone and repetitive.

Extract the per-register cleanup logic into free_reg_resource(),
which releases any iomapped address and, for Package-type entries,
recursively frees all child elements and the elements array itself.
Convert both the probe error path and _exit() to use the new helper.

No functional change for existing Integer / Buffer entries.

Signed-off-by: Lifeng Zheng <zhenglifeng1@xxxxxxxxxx>
---
drivers/acpi/cppc_acpi.c | 41 ++++++++++++++++++++++++++++------------
1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index ac4d4d002d40..bad959f46f90 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -759,6 +759,30 @@ static int parse_cpc_element(union acpi_object *cpc_obj,
return 0;
}

+/**
+ * free_reg_resource - Free resources held by a CPC register resource.
+ * @cpc_reg: Pointer to the CPC register resource to clean up.
+ *
+ * Releases any iomapped SystemMemory address and, for Package-type
+ * resources, recursively frees all nested elements before freeing the
+ * elements array itself.
+ */
+static void free_reg_resource(struct cpc_register_resource *cpc_reg)
+{
+ void __iomem *addr = cpc_reg->sys_mem_vaddr;
+ int i;
+
+ if (addr)
+ iounmap(addr);
+
+ if (cpc_reg->type == ACPI_TYPE_PACKAGE) {
+ for (i = 0; i < cpc_reg->cpc_entry.package.count; i++)
+ free_reg_resource(&cpc_reg->cpc_entry.package.elements[i]);
+
+ kfree(cpc_reg->cpc_entry.package.elements);
+ }
+}
+
/*
* An example CPC table looks like the following.
*
@@ -972,12 +996,9 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)

out_free:
/* Free all the mapped sys mem areas for this CPU */
- for (i = 2; i < cpc_ptr->num_entries; i++) {
- void __iomem *addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr;
+ for (i = 2; i < cpc_ptr->num_entries; i++)
+ free_reg_resource(&cpc_ptr->cpc_regs[i-2]);

- if (addr)
- iounmap(addr);
- }
kfree(cpc_ptr);

out_buf_free:
@@ -996,7 +1017,6 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
{
struct cpc_desc *cpc_ptr;
unsigned int i;
- void __iomem *addr;
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, pr->id);

if (pcc_ss_id >= 0 && pcc_data[pcc_ss_id]) {
@@ -1014,12 +1034,9 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
if (!cpc_ptr)
return;

- /* Free all the mapped sys mem areas for this CPU */
- for (i = 2; i < cpc_ptr->num_entries; i++) {
- addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr;
- if (addr)
- iounmap(addr);
- }
+ /* Free all the mapped sys mem areas and nested package resources for this CPU */
+ for (i = 2; i < cpc_ptr->num_entries; i++)
+ free_reg_resource(&cpc_ptr->cpc_regs[i-2]);

kobject_put(&cpc_ptr->kobj);
kfree(cpc_ptr);
--
2.33.0