[PATCH 2/8] ACPI: CPPC: Refactor element parsing into parse_cpc_element()
Lifeng Zheng <[email protected]> Fri, 17 Jul 2026 10:44:56 +0800
| Newsgroups | dev.linux.lists.acpica-devel,org.kernel.vger.linux-acpi,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pm |
|---|---|
| Message-ID | <[email protected]> |
acpi_cppc_processor_probe() contains a large inline block (~70 lines) that handles ACPI_TYPE_INTEGER and ACPI_TYPE_BUFFER entries in the _CPC package. This block will need to be reused for parsing individual elements inside the nested RESOURCE_PRIORITY sub-packages that CPPC v4 defines (Section 8.4.6.1.2.7). Extract the Integer / Buffer handling into a standalone parse_cpc_element() helper so that both the top-level _CPC loop and the upcoming package parser can share the same logic for register validation, PCC subspace tracking, SystemMemory ioremap, and SystemIO / FFH checks. No functional change; the new function reproduces the original behaviour exactly. Signed-off-by: Lifeng Zheng <[email protected]> --- drivers/acpi/cppc_acpi.c | 186 +++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 78 deletions(-) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index d7e654f2a66c..ac4d4d002d40 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -656,6 +656,109 @@ static int pcc_data_alloc(int pcc_ss_id) return 0; } +/** + * parse_cpc_element - Parse a single CPC element into a cpc_register_resource. + * @cpc_obj: Pointer to the ACPI object representing the CPC element. + * @cpc_reg: Output CPC register resource to populate. + * @pcc_subspace_id: In/out pointer to PCC subspace ID; extracted once on first + * PCC-type register and validated for consistency thereafter. + * @cpu: CPU number, used for debug messages. + * @entry_num: Index within the CPC table entries, used for diagnostics. + * + * Handles ACPI_TYPE_INTEGER (static value) and ACPI_TYPE_BUFFER (register + * descriptor). Sets up PCC subspace tracking, ioremap for SystemMemory, + * and validates SystemIO / FFH register parameters. + * + * Return: 0 on success, -ENODATA on invalid or unsupported data. + */ +static int parse_cpc_element(union acpi_object *cpc_obj, + struct cpc_register_resource *cpc_reg, + int *pcc_subspace_id, u32 cpu, unsigned int entry_num) +{ + struct cpc_reg *gas_t; + + if (cpc_obj->type == ACPI_TYPE_INTEGER) { + cpc_reg->type = ACPI_TYPE_INTEGER; + cpc_reg->cpc_entry.int_value = cpc_obj->integer.value; + } else if (cpc_obj->type == ACPI_TYPE_BUFFER) { + gas_t = (struct cpc_reg *)cpc_obj->buffer.pointer; + + /* + * The PCC Subspace index is encoded inside + * the CPC table entries. The same PCC index + * will be used for all the PCC entries, + * so extract it only once. + */ + if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { + if (*pcc_subspace_id < 0) { + *pcc_subspace_id = gas_t->access_width; + if (pcc_data_alloc(*pcc_subspace_id)) + return -ENODATA; + } else if (*pcc_subspace_id != gas_t->access_width) { + pr_debug("Mismatched PCC ids in _CPC for CPU:%d\n", + cpu); + return -ENODATA; + } + } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + if (gas_t->address) { + void __iomem *addr; + size_t access_width; + + if (!osc_cpc_flexible_adr_space_confirmed) { + pr_debug("Flexible address space capability not supported\n"); + if (!cpc_supported_by_cpu()) + return -ENODATA; + } + + access_width = GET_BIT_WIDTH(gas_t) / 8; + addr = ioremap(gas_t->address, access_width); + if (!addr) + return -ENODATA; + cpc_reg->sys_mem_vaddr = addr; + } + } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + if (gas_t->access_width < 1 || gas_t->access_width > 3) { + /* + * 1 = 8-bit, 2 = 16-bit, and 3 = 32-bit. + * SystemIO doesn't implement 64-bit + * registers. + */ + pr_debug("Invalid access width %d for SystemIO register in _CPC\n", + gas_t->access_width); + return -ENODATA; + } + if (gas_t->address & OVER_16BTS_MASK) { + /* SystemIO registers use 16-bit integer addresses */ + pr_debug("Invalid IO port %llu for SystemIO register in _CPC\n", + gas_t->address); + return -ENODATA; + } + if (!osc_cpc_flexible_adr_space_confirmed) { + pr_debug("Flexible address space capability not supported\n"); + if (!cpc_supported_by_cpu()) + return -ENODATA; + } + } else { + if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || + !cpc_ffh_supported()) { + /* Support only PCC, SystemMemory, SystemIO, and FFH type regs. */ + pr_debug("Unsupported register type (%d) in _CPC\n", + gas_t->space_id); + return -ENODATA; + } + } + + cpc_reg->type = ACPI_TYPE_BUFFER; + memcpy(&cpc_reg->cpc_entry.reg, gas_t, sizeof(*gas_t)); + } else { + pr_debug("Invalid entry type (%d) in _CPC for CPU:%d\n", + entry_num, cpu); + return -ENODATA; + } + + return 0; +} + /* * An example CPC table looks like the following. * @@ -696,7 +799,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *out_obj, *cpc_obj; struct cpc_desc *cpc_ptr; - struct cpc_reg *gas_t; struct device *cpu_dev; acpi_handle handle = pr->handle; unsigned int num_ent, i, cpc_rev; @@ -784,80 +886,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) for (i = 2; i < num_ent; i++) { cpc_obj = &out_obj->package.elements[i]; - if (cpc_obj->type == ACPI_TYPE_INTEGER) { - cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_INTEGER; - cpc_ptr->cpc_regs[i-2].cpc_entry.int_value = cpc_obj->integer.value; - } else if (cpc_obj->type == ACPI_TYPE_BUFFER) { - gas_t = (struct cpc_reg *) - cpc_obj->buffer.pointer; - - /* - * The PCC Subspace index is encoded inside - * the CPC table entries. The same PCC index - * will be used for all the PCC entries, - * so extract it only once. - */ - if (gas_t->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { - if (pcc_subspace_id < 0) { - pcc_subspace_id = gas_t->access_width; - if (pcc_data_alloc(pcc_subspace_id)) - goto out_free; - } else if (pcc_subspace_id != gas_t->access_width) { - pr_debug("Mismatched PCC ids in _CPC for CPU:%d\n", - pr->id); - goto out_free; - } - } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - if (gas_t->address) { - void __iomem *addr; - size_t access_width; - - if (!osc_cpc_flexible_adr_space_confirmed) { - pr_debug("Flexible address space capability not supported\n"); - if (!cpc_supported_by_cpu()) - goto out_free; - } - - access_width = GET_BIT_WIDTH(gas_t) / 8; - addr = ioremap(gas_t->address, access_width); - if (!addr) - goto out_free; - cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr; - } - } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { - if (gas_t->access_width < 1 || gas_t->access_width > 3) { - /* - * 1 = 8-bit, 2 = 16-bit, and 3 = 32-bit. - * SystemIO doesn't implement 64-bit - * registers. - */ - pr_debug("Invalid access width %d for SystemIO register in _CPC\n", - gas_t->access_width); - goto out_free; - } - if (gas_t->address & OVER_16BTS_MASK) { - /* SystemIO registers use 16-bit integer addresses */ - pr_debug("Invalid IO port %llu for SystemIO register in _CPC\n", - gas_t->address); - goto out_free; - } - if (!osc_cpc_flexible_adr_space_confirmed) { - pr_debug("Flexible address space capability not supported\n"); - if (!cpc_supported_by_cpu()) - goto out_free; - } - } else { - if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || !cpc_ffh_supported()) { - /* Support only PCC, SystemMemory, SystemIO, and FFH type regs. */ - pr_debug("Unsupported register type (%d) in _CPC\n", - gas_t->space_id); - goto out_free; - } - } - - 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 && (i - 2) == RESOURCE_PRIORITY) { + 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. @@ -869,9 +898,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) cpc_ptr->cpc_regs[i-2].cpc_entry.package.count = 0; cpc_ptr->cpc_regs[i-2].cpc_entry.package.elements = NULL; } else { - pr_debug("Invalid entry type (%d) in _CPC for CPU:%d\n", - i, pr->id); - goto out_free; + ret = parse_cpc_element(cpc_obj, &cpc_ptr->cpc_regs[i-2], + &pcc_subspace_id, pr->id, i); + if (ret) + goto out_free; } } per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id; -- 2.33.0