From 3a3ce10e7adcc02b333ffebbc414162e5d22fd16 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Fri, 11 Apr 2025 12:31:44 +0100 Subject: ACPI: CPPC: Simplify PCC shared memory region handling The PCC driver now handles mapping and unmapping of shared memory areas as part of pcc_mbox_{request,free}_channel(). Without these before, this ACPI CPPC driver did handling of those mappings like several other PCC mailbox client drivers. There were redundant operations, leading to unnecessary code. Maintaining the consistency across these driver was harder due to scattered handling of shmem. Just use the mapped shmem and remove all redundant operations from this driver. Signed-off-by: Sudeep Holla Link: https://patch.msgid.link/20250411113144.1151094-2-sudeep.holla@arm.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index f193e713825a..d972157a79b6 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -47,7 +47,6 @@ struct cppc_pcc_data { struct pcc_mbox_chan *pcc_channel; - void __iomem *pcc_comm_addr; bool pcc_channel_acquired; unsigned int deadline_us; unsigned int pcc_mpar, pcc_mrtt, pcc_nominal; @@ -95,7 +94,7 @@ static DEFINE_PER_CPU(int, cpu_pcc_subspace_idx); static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); /* pcc mapped address + header size + offset within PCC subspace */ -#define GET_PCC_VADDR(offs, pcc_ss_id) (pcc_data[pcc_ss_id]->pcc_comm_addr + \ +#define GET_PCC_VADDR(offs, pcc_ss_id) (pcc_data[pcc_ss_id]->pcc_channel->shmem + \ 0x8 + (offs)) /* Check if a CPC register is in PCC */ @@ -223,7 +222,7 @@ static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit) int ret, status; struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; struct acpi_pcct_shared_memory __iomem *generic_comm_base = - pcc_ss_data->pcc_comm_addr; + pcc_ss_data->pcc_channel->shmem; if (!pcc_ss_data->platform_owns_pcc) return 0; @@ -258,7 +257,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd) int ret = -EIO, i; struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; struct acpi_pcct_shared_memory __iomem *generic_comm_base = - pcc_ss_data->pcc_comm_addr; + pcc_ss_data->pcc_channel->shmem; unsigned int time_delta; /* @@ -571,15 +570,6 @@ static int register_pcc_channel(int pcc_ss_idx) pcc_data[pcc_ss_idx]->pcc_mpar = pcc_chan->max_access_rate; pcc_data[pcc_ss_idx]->pcc_nominal = pcc_chan->latency; - pcc_data[pcc_ss_idx]->pcc_comm_addr = - acpi_os_ioremap(pcc_chan->shmem_base_addr, - pcc_chan->shmem_size); - if (!pcc_data[pcc_ss_idx]->pcc_comm_addr) { - pr_err("Failed to ioremap PCC comm region mem for %d\n", - pcc_ss_idx); - return -ENOMEM; - } - /* Set flag so that we don't come here for each CPU. */ pcc_data[pcc_ss_idx]->pcc_channel_acquired = true; } -- cgit From e3d7935a6c6138da51626d2b956a079dd0e6671b Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:48 +0800 Subject: ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional In ACPI 6.5, s8.4.6.1 _CPC (Continuous Performance Control), whether each of the per-cpu cpc_regs[] is mandatory or optional is defined. Since the CPC_SUPPORTED() check is only for optional _CPC fields, another macro to check if the field is optional is needed. Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-2-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index d972157a79b6..34df03755699 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -128,6 +128,20 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); #define CPC_SUPPORTED(cpc) ((cpc)->type == ACPI_TYPE_INTEGER ? \ !!(cpc)->cpc_entry.int_value : \ !IS_NULL_REG(&(cpc)->cpc_entry.reg)) + +/* + * Each bit indicates the optionality of the register in per-cpu + * cpc_regs[] with the corresponding index. 0 means mandatory and 1 + * means optional. + */ +#define REG_OPTIONAL (0x1FC7D0) + +/* + * Use the index of the register in per-cpu cpc_regs[] to check if + * it's an optional one. + */ +#define IS_OPTIONAL_CPC_REG(reg_idx) (REG_OPTIONAL & (1U << (reg_idx))) + /* * Arbitrary Retries in case the remote processor is slow to respond * to PCC commands. Keeping it high enough to cover emulators where -- cgit From 45f3763a2122553e548fa0430b77605dc23f00cc Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:49 +0800 Subject: ACPI: CPPC: Optimize cppc_get_perf() Optimize cppc_get_perf() with three changes: 1. Change the error kind to "no such device" when pcc_ss_id < 0, as other register value getting functions. 2. Add a check to ensure the pointer 'perf' is no null. 3. Add a check to verify if the register is supported to be read before using it. The logic is: (1) If the register is of the integer type, check whether the register is optional and its value is 0. If yes, the register is not supported. (2) If the register is of other types, a null one is not supported. 4. Return the result of cpc_read() instead of 0. Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-3-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 34df03755699..a0774517642f 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1184,6 +1184,9 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *reg; + if (perf == NULL) + return -EINVAL; + if (!cpc_desc) { pr_debug("No CPC descriptor for CPU:%d\n", cpunum); return -ENODEV; @@ -1191,20 +1194,29 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) reg = &cpc_desc->cpc_regs[reg_idx]; + if ((reg->type == ACPI_TYPE_INTEGER && IS_OPTIONAL_CPC_REG(reg_idx) && + !reg->cpc_entry.int_value) || (reg->type != ACPI_TYPE_INTEGER && + IS_NULL_REG(®->cpc_entry.reg))) { + pr_debug("CPC register is not supported\n"); + return -EOPNOTSUPP; + } + if (CPC_IN_PCC(reg)) { int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); struct cppc_pcc_data *pcc_ss_data = NULL; - int ret = 0; + int ret; - if (pcc_ss_id < 0) - return -EIO; + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } pcc_ss_data = pcc_data[pcc_ss_id]; down_write(&pcc_ss_data->pcc_lock); if (send_pcc_cmd(pcc_ss_id, CMD_READ) >= 0) - cpc_read(cpunum, reg, perf); + ret = cpc_read(cpunum, reg, perf); else ret = -EIO; @@ -1213,9 +1225,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) return ret; } - cpc_read(cpunum, reg, perf); - - return 0; + return cpc_read(cpunum, reg, perf); } /** -- cgit From 714d103ce868cd0718d0e5262cbc76384a2eb03a Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:50 +0800 Subject: ACPI: CPPC: Rename cppc_get_perf() to cppc_get_reg_val() Rename cppc_get_perf() to cppc_get_reg_val() as a generic function to read CPPC registers. Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-4-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index a0774517642f..c460272b86c3 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1179,16 +1179,16 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) return ret_val; } -static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) +static int cppc_get_reg_val(int cpu, enum cppc_regs reg_idx, u64 *val) { - struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); struct cpc_register_resource *reg; - if (perf == NULL) + if (val == NULL) return -EINVAL; if (!cpc_desc) { - pr_debug("No CPC descriptor for CPU:%d\n", cpunum); + pr_debug("No CPC descriptor for CPU:%d\n", cpu); return -ENODEV; } @@ -1202,7 +1202,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) } if (CPC_IN_PCC(reg)) { - int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); + int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); struct cppc_pcc_data *pcc_ss_data = NULL; int ret; @@ -1216,7 +1216,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) down_write(&pcc_ss_data->pcc_lock); if (send_pcc_cmd(pcc_ss_id, CMD_READ) >= 0) - ret = cpc_read(cpunum, reg, perf); + ret = cpc_read(cpu, reg, val); else ret = -EIO; @@ -1225,7 +1225,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) return ret; } - return cpc_read(cpunum, reg, perf); + return cpc_read(cpu, reg, val); } /** @@ -1237,7 +1237,7 @@ static int cppc_get_perf(int cpunum, enum cppc_regs reg_idx, u64 *perf) */ int cppc_get_desired_perf(int cpunum, u64 *desired_perf) { - return cppc_get_perf(cpunum, DESIRED_PERF, desired_perf); + return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf); } EXPORT_SYMBOL_GPL(cppc_get_desired_perf); @@ -1250,7 +1250,7 @@ EXPORT_SYMBOL_GPL(cppc_get_desired_perf); */ int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf) { - return cppc_get_perf(cpunum, NOMINAL_PERF, nominal_perf); + return cppc_get_reg_val(cpunum, NOMINAL_PERF, nominal_perf); } /** @@ -1262,7 +1262,7 @@ int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf) */ int cppc_get_highest_perf(int cpunum, u64 *highest_perf) { - return cppc_get_perf(cpunum, HIGHEST_PERF, highest_perf); + return cppc_get_reg_val(cpunum, HIGHEST_PERF, highest_perf); } EXPORT_SYMBOL_GPL(cppc_get_highest_perf); @@ -1275,7 +1275,7 @@ EXPORT_SYMBOL_GPL(cppc_get_highest_perf); */ int cppc_get_epp_perf(int cpunum, u64 *epp_perf) { - return cppc_get_perf(cpunum, ENERGY_PERF, epp_perf); + return cppc_get_reg_val(cpunum, ENERGY_PERF, epp_perf); } EXPORT_SYMBOL_GPL(cppc_get_epp_perf); -- cgit From b5ef45e6a1777fe4e857a1cd48631dc14064eae4 Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:51 +0800 Subject: ACPI: CPPC: Extract cppc_get_reg_val_in_pcc() Extract the operations if register is in pcc out from cppc_get_reg_val() as cppc_get_reg_val_in_pcc(). Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-5-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 50 ++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index c460272b86c3..14dd206b4454 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1179,6 +1179,31 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) return ret_val; } +static int cppc_get_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; + int ret; + + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + + pcc_ss_data = pcc_data[pcc_ss_id]; + + down_write(&pcc_ss_data->pcc_lock); + + if (send_pcc_cmd(pcc_ss_id, CMD_READ) >= 0) + ret = cpc_read(cpu, reg, val); + else + ret = -EIO; + + up_write(&pcc_ss_data->pcc_lock); + + return ret; +} + static int cppc_get_reg_val(int cpu, enum cppc_regs reg_idx, u64 *val) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); @@ -1201,29 +1226,8 @@ static int cppc_get_reg_val(int cpu, enum cppc_regs reg_idx, u64 *val) return -EOPNOTSUPP; } - if (CPC_IN_PCC(reg)) { - int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); - struct cppc_pcc_data *pcc_ss_data = NULL; - int ret; - - if (pcc_ss_id < 0) { - pr_debug("Invalid pcc_ss_id\n"); - return -ENODEV; - } - - pcc_ss_data = pcc_data[pcc_ss_id]; - - down_write(&pcc_ss_data->pcc_lock); - - if (send_pcc_cmd(pcc_ss_id, CMD_READ) >= 0) - ret = cpc_read(cpu, reg, val); - else - ret = -EIO; - - up_write(&pcc_ss_data->pcc_lock); - - return ret; - } + if (CPC_IN_PCC(reg)) + return cppc_get_reg_val_in_pcc(cpu, reg, val); return cpc_read(cpu, reg, val); } -- cgit From e05c75072c2eaa6e0b152a558b3be5cbcf79a587 Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:52 +0800 Subject: ACPI: CPPC: Add cppc_set_reg_val() Add cppc_set_reg_val() as a generic function for setting CPPC register values, with this features: 1. Check register. If a register is writeable, it must be a buffer and can not be null. 2. Extract the operations if register is in PCC out as cppc_set_reg_val_in_pcc(). This function can be used to reduce some existing code duplication. Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-6-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 14dd206b4454..e8236ec0fd0d 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1232,6 +1232,55 @@ static int cppc_get_reg_val(int cpu, enum cppc_regs reg_idx, u64 *val) return cpc_read(cpu, reg, 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; + int ret; + + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id\n"); + return -ENODEV; + } + + ret = cpc_write(cpu, reg, val); + if (ret) + return ret; + + pcc_ss_data = pcc_data[pcc_ss_id]; + + down_write(&pcc_ss_data->pcc_lock); + /* after writing CPC, transfer the ownership of PCC to platform */ + ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE); + up_write(&pcc_ss_data->pcc_lock); + + return ret; +} + +static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val) +{ + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); + struct cpc_register_resource *reg; + + if (!cpc_desc) { + pr_debug("No CPC descriptor for CPU:%d\n", cpu); + return -ENODEV; + } + + reg = &cpc_desc->cpc_regs[reg_idx]; + + /* if a register is writeable, it must be a buffer and not null */ + if ((reg->type != ACPI_TYPE_BUFFER) || IS_NULL_REG(®->cpc_entry.reg)) { + pr_debug("CPC register is not supported\n"); + return -EOPNOTSUPP; + } + + if (CPC_IN_PCC(reg)) + return cppc_set_reg_val_in_pcc(cpu, reg, val); + + return cpc_write(cpu, reg, val); +} + /** * cppc_get_desired_perf - Get the desired performance register value. * @cpunum: CPU from which to get desired performance. -- cgit From ab482f1bac6b128b8fe910b6663a4f74a3a9796c Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:53 +0800 Subject: ACPI: CPPC: Refactor register value get and set ABIs Refactor register value get and set ABIs by using cppc_get_reg_val(), cppc_set_reg_val() and CPPC_REG_VAL_READ(). Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-7-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 111 +++-------------------------------------------- 1 file changed, 7 insertions(+), 104 deletions(-) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index e8236ec0fd0d..62c4673c3ef8 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1608,44 +1608,14 @@ EXPORT_SYMBOL_GPL(cppc_set_epp_perf); */ int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps) { - struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); - struct cpc_register_resource *auto_sel_reg; - u64 auto_sel; - - if (!cpc_desc) { - pr_debug("No CPC descriptor for CPU:%d\n", cpunum); - return -ENODEV; - } - - auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE]; - - if (!CPC_SUPPORTED(auto_sel_reg)) - pr_warn_once("Autonomous mode is not unsupported!\n"); - - if (CPC_IN_PCC(auto_sel_reg)) { - int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); - struct cppc_pcc_data *pcc_ss_data = NULL; - int ret = 0; - - if (pcc_ss_id < 0) - return -ENODEV; - - pcc_ss_data = pcc_data[pcc_ss_id]; - - down_write(&pcc_ss_data->pcc_lock); - - if (send_pcc_cmd(pcc_ss_id, CMD_READ) >= 0) { - cpc_read(cpunum, auto_sel_reg, &auto_sel); - perf_caps->auto_sel = (bool)auto_sel; - } else { - ret = -EIO; - } - - up_write(&pcc_ss_data->pcc_lock); + u64 auto_sel; + int ret; + ret = cppc_get_reg_val(cpunum, AUTO_SEL_ENABLE, &auto_sel); + if (ret) return ret; - } + perf_caps->auto_sel = (bool)auto_sel; return 0; } EXPORT_SYMBOL_GPL(cppc_get_auto_sel_caps); @@ -1657,43 +1627,7 @@ EXPORT_SYMBOL_GPL(cppc_get_auto_sel_caps); */ int cppc_set_auto_sel(int cpu, bool enable) { - int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); - struct cpc_register_resource *auto_sel_reg; - struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); - struct cppc_pcc_data *pcc_ss_data = NULL; - int ret = -EINVAL; - - if (!cpc_desc) { - pr_debug("No CPC descriptor for CPU:%d\n", cpu); - return -ENODEV; - } - - auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE]; - - if (CPC_IN_PCC(auto_sel_reg)) { - if (pcc_ss_id < 0) { - pr_debug("Invalid pcc_ss_id\n"); - return -ENODEV; - } - - if (CPC_SUPPORTED(auto_sel_reg)) { - ret = cpc_write(cpu, auto_sel_reg, enable); - if (ret) - return ret; - } - - pcc_ss_data = pcc_data[pcc_ss_id]; - - down_write(&pcc_ss_data->pcc_lock); - /* after writing CPC, transfer the ownership of PCC to platform */ - ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE); - up_write(&pcc_ss_data->pcc_lock); - } else { - ret = -ENOTSUPP; - pr_debug("_CPC in PCC is not supported\n"); - } - - return ret; + return cppc_set_reg_val(cpu, AUTO_SEL_ENABLE, enable); } EXPORT_SYMBOL_GPL(cppc_set_auto_sel); @@ -1707,38 +1641,7 @@ EXPORT_SYMBOL_GPL(cppc_set_auto_sel); */ int cppc_set_enable(int cpu, bool enable) { - int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); - struct cpc_register_resource *enable_reg; - struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); - struct cppc_pcc_data *pcc_ss_data = NULL; - int ret = -EINVAL; - - if (!cpc_desc) { - pr_debug("No CPC descriptor for CPU:%d\n", cpu); - return -EINVAL; - } - - enable_reg = &cpc_desc->cpc_regs[ENABLE]; - - if (CPC_IN_PCC(enable_reg)) { - - if (pcc_ss_id < 0) - return -EIO; - - ret = cpc_write(cpu, enable_reg, enable); - if (ret) - return ret; - - pcc_ss_data = pcc_data[pcc_ss_id]; - - down_write(&pcc_ss_data->pcc_lock); - /* after writing CPC, transfer the ownership of PCC to platfrom */ - ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE); - up_write(&pcc_ss_data->pcc_lock); - return ret; - } - - return cpc_write(cpu, enable_reg, enable); + return cppc_set_reg_val(cpu, ENABLE, enable); } EXPORT_SYMBOL_GPL(cppc_set_enable); -- cgit From 2605e4ab6615ef43361b18fc6d08dd884896aad8 Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:54 +0800 Subject: ACPI: CPPC: Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel() Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel(). Using a cppc_perf_caps to carry the value is unnecessary. Add a check to ensure the pointer 'enable' is not null. Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-8-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 62c4673c3ef8..6163831b8c19 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1602,23 +1602,27 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable) EXPORT_SYMBOL_GPL(cppc_set_epp_perf); /** - * cppc_get_auto_sel_caps - Read autonomous selection register. - * @cpunum : CPU from which to read register. - * @perf_caps : struct where autonomous selection register value is updated. + * cppc_get_auto_sel() - Read autonomous selection register. + * @cpu: CPU from which to read register. + * @enable: Return address. */ -int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps) +int cppc_get_auto_sel(int cpu, bool *enable) { u64 auto_sel; int ret; - ret = cppc_get_reg_val(cpunum, AUTO_SEL_ENABLE, &auto_sel); + if (enable == NULL) + return -EINVAL; + + ret = cppc_get_reg_val(cpu, AUTO_SEL_ENABLE, &auto_sel); if (ret) return ret; - perf_caps->auto_sel = (bool)auto_sel; + *enable = (bool)auto_sel; + return 0; } -EXPORT_SYMBOL_GPL(cppc_get_auto_sel_caps); +EXPORT_SYMBOL_GPL(cppc_get_auto_sel); /** * cppc_set_auto_sel - Write autonomous selection register. -- cgit From f35e5b3ccfd3516bc36b08e101678b036309397c Mon Sep 17 00:00:00 2001 From: Lifeng Zheng Date: Fri, 11 Apr 2025 17:38:55 +0800 Subject: ACPI: CPPC: Add three functions related to autonomous selection cppc_set_epp() - write energy performance preference register value, based on ACPI 6.5, s8.4.6.1.7 cppc_get_auto_act_window() - read autonomous activity window register value, based on ACPI 6.5, s8.4.6.1.6 cppc_set_auto_act_window() - write autonomous activity window register value, based on ACPI 6.5, s8.4.6.1.6 Reviewed-by: Pierre Gondois Signed-off-by: Lifeng Zheng Reviewed-by: Mario Limonciello Link: https://patch.msgid.link/20250411093855.982491-9-zhenglifeng1@huawei.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'drivers/acpi/cppc_acpi.c') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 6163831b8c19..a9ae2fd62863 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -1601,6 +1601,89 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable) } EXPORT_SYMBOL_GPL(cppc_set_epp_perf); +/** + * cppc_set_epp() - Write the EPP register. + * @cpu: CPU on which to write register. + * @epp_val: Value to write to the EPP register. + */ +int cppc_set_epp(int cpu, u64 epp_val) +{ + if (epp_val > CPPC_ENERGY_PERF_MAX) + return -EINVAL; + + return cppc_set_reg_val(cpu, ENERGY_PERF, epp_val); +} +EXPORT_SYMBOL_GPL(cppc_set_epp); + +/** + * cppc_get_auto_act_window() - Read autonomous activity window register. + * @cpu: CPU from which to read register. + * @auto_act_window: Return address. + * + * According to ACPI 6.5, s8.4.6.1.6, the value read from the autonomous + * activity window register consists of two parts: a 7 bits value indicate + * significand and a 3 bits value indicate exponent. + */ +int cppc_get_auto_act_window(int cpu, u64 *auto_act_window) +{ + unsigned int exp; + u64 val, sig; + int ret; + + if (auto_act_window == NULL) + return -EINVAL; + + ret = cppc_get_reg_val(cpu, AUTO_ACT_WINDOW, &val); + if (ret) + return ret; + + sig = val & CPPC_AUTO_ACT_WINDOW_MAX_SIG; + exp = (val >> CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE) & CPPC_AUTO_ACT_WINDOW_MAX_EXP; + *auto_act_window = sig * int_pow(10, exp); + + return 0; +} +EXPORT_SYMBOL_GPL(cppc_get_auto_act_window); + +/** + * cppc_set_auto_act_window() - Write autonomous activity window register. + * @cpu: CPU on which to write register. + * @auto_act_window: usec value to write to the autonomous activity window register. + * + * According to ACPI 6.5, s8.4.6.1.6, the value to write to the autonomous + * activity window register consists of two parts: a 7 bits value indicate + * significand and a 3 bits value indicate exponent. + */ +int cppc_set_auto_act_window(int cpu, u64 auto_act_window) +{ + /* The max value to store is 1270000000 */ + u64 max_val = CPPC_AUTO_ACT_WINDOW_MAX_SIG * int_pow(10, CPPC_AUTO_ACT_WINDOW_MAX_EXP); + int exp = 0; + u64 val; + + if (auto_act_window > max_val) + return -EINVAL; + + /* + * The max significand is 127, when auto_act_window is larger than + * 129, discard the precision of the last digit and increase the + * exponent by 1. + */ + while (auto_act_window > CPPC_AUTO_ACT_WINDOW_SIG_CARRY_THRESH) { + auto_act_window /= 10; + exp += 1; + } + + /* For 128 and 129, cut it to 127. */ + if (auto_act_window > CPPC_AUTO_ACT_WINDOW_MAX_SIG) + auto_act_window = CPPC_AUTO_ACT_WINDOW_MAX_SIG; + + val = (exp << CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE) + auto_act_window; + + return cppc_set_reg_val(cpu, AUTO_ACT_WINDOW, val); +} +EXPORT_SYMBOL_GPL(cppc_set_auto_act_window); + /** * cppc_get_auto_sel() - Read autonomous selection register. * @cpu: CPU from which to read register. -- cgit