* [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi
@ 2025-04-09 6:56 Lifeng Zheng
2025-04-09 6:56 ` [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional Lifeng Zheng
` (7 more replies)
0 siblings, 8 replies; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:56 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
The patch series is organized in two parts:
- patch 1-6 refactor out the general CPPC register get and set functions
in cppc_acpi.c
- patches 7-8 add functions for getting and setting values of auto_sel,
energy_perf and auto_act_window in cppc_acpi.c
Changelog:
v6:
- Remove the last patch, will resent it in the future after reaching an
agreement with Sumit
- split patch 3 into 2 smaller patches
- Remove the printing of reg_idx in cppc_get_reg_val() and
cppc_set_reg_val()
- Change the logic for determing whether a register is supported in
cppc_get_reg_val() and cppc_set_reg_val()
v5:
- add more explanation to the commit logs and comments
- change REG_OPTIONAL from bin to hex
- split patch 2 into 3 smaller patches
- remove CPPC_REG_VAL_READ() and CPPC_REG_VAL_WRITE() macros
- move the modification part in patch 5 into a separate patch
- rename the sysfs file from "energy_perf" to
energy_performance_preference_val
v4:
- add REG_OPTIONAL and IS_OPTIONAL_CPC_REG to judge if a cpc register is
an optional one
- check whether the register is optional before CPC_SUPPORTED check in
cppc_get_reg_val() and cppc_set_reg_val()
- check the register's type in cppc_set_reg_val()
- add macros to generally implement registers getting and setting
functions
- move some logic codes from cppc_cpufreq.c to cppc_acpi.c
- replace cppc_get_auto_sel_caps() by cppc_get_auto_sel()
v3:
- change cppc_get_reg() and cppc_set_reg() name to cppc_get_reg_val() and
cppc_set_reg_val()
- extract cppc_get_reg_val_in_pcc() and cppc_set_reg_val_in_pcc()
- return the result of cpc_read() in cppc_get_reg_val()
- add pr_debug() in cppc_get_reg_val_in_pcc() when pcc_ss_id < 0
- rename 'cpunum' to 'cpu' in cppc_get_reg_val()
- move some macros from drivers/cpufreq/cppc_cpufreq.c to
include/acpi/cppc_acpi.h with a CPPC_XXX prefix
v2:
- fix some incorrect placeholder
- change kstrtoul to kstrtobool in store_auto_select
---
Discussions of previous versions:
v1: https://lore.kernel.org/all/20241114084816.1128647-1-zhenglifeng1@huawei.com/
v2: https://lore.kernel.org/all/20241122062051.3658577-1-zhenglifeng1@huawei.com/
v3: https://lore.kernel.org/all/20241216091603.1247644-1-zhenglifeng1@huawei.com/
v4: https://lore.kernel.org/all/20250113122104.3870673-1-zhenglifeng1@huawei.com/
v5: https://lore.kernel.org/all/20250206131428.3261578-1-zhenglifeng1@huawei.com/
Lifeng Zheng (8):
ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is
optional
ACPI: CPPC: Optimize cppc_get_perf()
ACPI: CPPC: Rename cppc_get_perf() to cppc_get_reg_val()
ACPI: CPPC: Extract cppc_get_reg_val_in_pcc()
ACPI: CPPC: Add cppc_set_reg_val()
ACPI: CPPC: Refactor register value get and set ABIs
ACPI: CPPC: Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel()
ACPI: CPPC: Add three functions related to autonomous selection
drivers/acpi/cppc_acpi.c | 304 +++++++++++++++++++++--------------
drivers/cpufreq/amd-pstate.c | 3 +-
include/acpi/cppc_acpi.h | 30 +++-
3 files changed, 210 insertions(+), 127 deletions(-)
--
2.33.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
@ 2025-04-09 6:56 ` Lifeng Zheng
2025-04-09 18:53 ` Mario Limonciello
2025-04-09 6:56 ` [PATCH v6 2/8] ACPI: CPPC: Optimize cppc_get_perf() Lifeng Zheng
` (6 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:56 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
In ACPI 6.5, s8.4.6.1 _CPC (Continuous Performance Control), whether each
of the per-cpu cpc_regs[] is mendatory or optional is defined. Since the
CPC_SUPPORTED() check is only for optional cpc field, another macro to
check if the field is optional is needed.
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index f193e713825a..39f019e265da 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -129,6 +129,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
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v6 2/8] ACPI: CPPC: Optimize cppc_get_perf()
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
2025-04-09 6:56 ` [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional Lifeng Zheng
@ 2025-04-09 6:56 ` Lifeng Zheng
2025-04-09 17:10 ` Rafael J. Wysocki
2025-04-09 6:56 ` [PATCH v6 3/8] ACPI: CPPC: Rename cppc_get_perf() to cppc_get_reg_val() Lifeng Zheng
` (5 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:56 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
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 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.
3. Return the result of cpc_read() instead of 0.
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 39f019e265da..2f789d3b3cad 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1201,20 +1201,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) :
+ 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;
@@ -1223,9 +1232,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);
}
/**
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v6 3/8] ACPI: CPPC: Rename cppc_get_perf() to cppc_get_reg_val()
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
2025-04-09 6:56 ` [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional Lifeng Zheng
2025-04-09 6:56 ` [PATCH v6 2/8] ACPI: CPPC: Optimize cppc_get_perf() Lifeng Zheng
@ 2025-04-09 6:56 ` Lifeng Zheng
2025-04-09 6:56 ` [PATCH v6 4/8] ACPI: CPPC: Extract cppc_get_reg_val_in_pcc() Lifeng Zheng
` (4 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:56 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
Rename cppc_get_perf() to cppc_get_reg_val() as a generic function to read
cppc registers.
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 2f789d3b3cad..9e26f115e1a9 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1189,13 +1189,13 @@ 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 (!cpc_desc) {
- pr_debug("No CPC descriptor for CPU:%d\n", cpunum);
+ pr_debug("No CPC descriptor for CPU:%d\n", cpu);
return -ENODEV;
}
@@ -1209,7 +1209,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;
@@ -1223,7 +1223,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;
@@ -1232,7 +1232,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);
}
/**
@@ -1244,7 +1244,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);
@@ -1257,7 +1257,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);
}
/**
@@ -1269,7 +1269,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);
@@ -1282,7 +1282,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);
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v6 4/8] ACPI: CPPC: Extract cppc_get_reg_val_in_pcc()
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
` (2 preceding siblings ...)
2025-04-09 6:56 ` [PATCH v6 3/8] ACPI: CPPC: Rename cppc_get_perf() to cppc_get_reg_val() Lifeng Zheng
@ 2025-04-09 6:56 ` Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 5/8] ACPI: CPPC: Add cppc_set_reg_val() Lifeng Zheng
` (3 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:56 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
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 <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 50 ++++++++++++++++++++++------------------
1 file changed, 27 insertions(+), 23 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 9e26f115e1a9..d844d0715761 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1189,6 +1189,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);
@@ -1208,29 +1233,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);
}
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v6 5/8] ACPI: CPPC: Add cppc_set_reg_val()
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
` (3 preceding siblings ...)
2025-04-09 6:56 ` [PATCH v6 4/8] ACPI: CPPC: Extract cppc_get_reg_val_in_pcc() Lifeng Zheng
@ 2025-04-09 6:57 ` Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 6/8] ACPI: CPPC: Refactor register value get and set ABIs Lifeng Zheng
` (2 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:57 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
Add cppc_set_reg_val() as a generic function for setting cppc registers
value, 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 <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 49 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index d844d0715761..cd584ce2634a 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1239,6 +1239,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.
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v6 6/8] ACPI: CPPC: Refactor register value get and set ABIs
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
` (4 preceding siblings ...)
2025-04-09 6:57 ` [PATCH v6 5/8] ACPI: CPPC: Add cppc_set_reg_val() Lifeng Zheng
@ 2025-04-09 6:57 ` Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 7/8] ACPI: CPPC: Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel() Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 8/8] ACPI: CPPC: Add three functions related to autonomous selection Lifeng Zheng
7 siblings, 0 replies; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:57 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
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 <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 111 +++------------------------------------
1 file changed, 7 insertions(+), 104 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index cd584ce2634a..ab492c89b0d8 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1615,44 +1615,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);
@@ -1664,43 +1634,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);
@@ -1714,38 +1648,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);
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v6 7/8] ACPI: CPPC: Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel()
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
` (5 preceding siblings ...)
2025-04-09 6:57 ` [PATCH v6 6/8] ACPI: CPPC: Refactor register value get and set ABIs Lifeng Zheng
@ 2025-04-09 6:57 ` Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 8/8] ACPI: CPPC: Add three functions related to autonomous selection Lifeng Zheng
7 siblings, 0 replies; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:57 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel(). Using a
cppc_perf_caps to carry the value is unnecessary.
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 15 ++++++++-------
drivers/cpufreq/amd-pstate.c | 3 ++-
include/acpi/cppc_acpi.h | 6 +++---
3 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index ab492c89b0d8..ef2394c074e3 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1609,23 +1609,24 @@ 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);
+ 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.
diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c
index 6789eed1bb5b..9cd54d8630cd 100644
--- a/drivers/cpufreq/amd-pstate.c
+++ b/drivers/cpufreq/amd-pstate.c
@@ -417,6 +417,7 @@ static int shmem_init_perf(struct amd_cpudata *cpudata)
struct cppc_perf_caps cppc_perf;
union perf_cached perf = READ_ONCE(cpudata->perf);
u64 numerator;
+ bool auto_sel;
int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
if (ret)
@@ -438,7 +439,7 @@ static int shmem_init_perf(struct amd_cpudata *cpudata)
if (cppc_state == AMD_PSTATE_ACTIVE)
return 0;
- ret = cppc_get_auto_sel_caps(cpudata->cpu, &cppc_perf);
+ ret = cppc_get_auto_sel(cpudata->cpu, &auto_sel);
if (ret) {
pr_warn("failed to get auto_sel, ret: %d\n", ret);
return 0;
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 62d368bcd9ec..31767c65be20 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -159,7 +159,7 @@ extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
-extern int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps);
+extern int cppc_get_auto_sel(int cpu, bool *enable);
extern int cppc_set_auto_sel(int cpu, bool enable);
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
@@ -229,11 +229,11 @@ static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
{
return -EOPNOTSUPP;
}
-static inline int cppc_set_auto_sel(int cpu, bool enable)
+static inline int cppc_get_auto_sel(int cpu, bool *enable)
{
return -EOPNOTSUPP;
}
-static inline int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps)
+static inline int cppc_set_auto_sel(int cpu, bool enable)
{
return -EOPNOTSUPP;
}
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v6 8/8] ACPI: CPPC: Add three functions related to autonomous selection
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
` (6 preceding siblings ...)
2025-04-09 6:57 ` [PATCH v6 7/8] ACPI: CPPC: Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel() Lifeng Zheng
@ 2025-04-09 6:57 ` Lifeng Zheng
2025-04-09 18:59 ` Mario Limonciello
7 siblings, 1 reply; 15+ messages in thread
From: Lifeng Zheng @ 2025-04-09 6:57 UTC (permalink / raw)
To: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, zhenglifeng1,
hepeng68
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 <pierre.gondois@arm.com>
Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
---
drivers/acpi/cppc_acpi.c | 80 ++++++++++++++++++++++++++++++++++++++++
include/acpi/cppc_acpi.h | 24 ++++++++++++
2 files changed, 104 insertions(+)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index ef2394c074e3..3d5eace44af5 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1608,6 +1608,86 @@ 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;
+
+ 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 stroe 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.
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 31767c65be20..325e9543e08f 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -32,6 +32,15 @@
#define CMD_READ 0
#define CMD_WRITE 1
+#define CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE (7)
+#define CPPC_AUTO_ACT_WINDOW_EXP_BIT_SIZE (3)
+#define CPPC_AUTO_ACT_WINDOW_MAX_SIG ((1 << CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE) - 1)
+#define CPPC_AUTO_ACT_WINDOW_MAX_EXP ((1 << CPPC_AUTO_ACT_WINDOW_EXP_BIT_SIZE) - 1)
+/* CPPC_AUTO_ACT_WINDOW_MAX_SIG is 127, so 128 and 129 will decay to 127 when writing */
+#define CPPC_AUTO_ACT_WINDOW_SIG_CARRY_THRESH 129
+
+#define CPPC_ENERGY_PERF_MAX (0xFF)
+
/* Each register has the folowing format. */
struct cpc_reg {
u8 descriptor;
@@ -159,6 +168,9 @@ extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
+extern int cppc_set_epp(int cpu, u64 epp_val);
+extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window);
+extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window);
extern int cppc_get_auto_sel(int cpu, bool *enable);
extern int cppc_set_auto_sel(int cpu, bool enable);
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
@@ -229,6 +241,18 @@ static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
{
return -EOPNOTSUPP;
}
+static inline int cppc_set_epp(int cpu, u64 epp_val)
+{
+ return -EOPNOTSUPP;
+}
+static inline int cppc_get_auto_act_window(int cpu, u64 *auto_act_window)
+{
+ return -EOPNOTSUPP;
+}
+static inline int cppc_set_auto_act_window(int cpu, u64 auto_act_window)
+{
+ return -EOPNOTSUPP;
+}
static inline int cppc_get_auto_sel(int cpu, bool *enable)
{
return -EOPNOTSUPP;
--
2.33.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v6 2/8] ACPI: CPPC: Optimize cppc_get_perf()
2025-04-09 6:56 ` [PATCH v6 2/8] ACPI: CPPC: Optimize cppc_get_perf() Lifeng Zheng
@ 2025-04-09 17:10 ` Rafael J. Wysocki
2025-04-10 8:23 ` zhenglifeng (A)
0 siblings, 1 reply; 15+ messages in thread
From: Rafael J. Wysocki @ 2025-04-09 17:10 UTC (permalink / raw)
To: Lifeng Zheng
Cc: rafael, lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois,
acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, hepeng68
On Wed, Apr 9, 2025 at 8:57 AM Lifeng Zheng <zhenglifeng1@huawei.com> wrote:
>
> 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 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.
>
> 3. Return the result of cpc_read() instead of 0.
>
> Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
> Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
> ---
> drivers/acpi/cppc_acpi.c | 21 ++++++++++++++-------
> 1 file changed, 14 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 39f019e265da..2f789d3b3cad 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1201,20 +1201,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) :
> + IS_NULL_REG(®->cpc_entry.reg)) {
Please avoid using the ternary operator in any new kernel code.
Why not write it this way
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;
>
> @@ -1223,9 +1232,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);
> }
>
> /**
> --
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional
2025-04-09 6:56 ` [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional Lifeng Zheng
@ 2025-04-09 18:53 ` Mario Limonciello
2025-04-10 8:21 ` zhenglifeng (A)
0 siblings, 1 reply; 15+ messages in thread
From: Mario Limonciello @ 2025-04-09 18:53 UTC (permalink / raw)
To: Lifeng Zheng, rafael, lenb, robert.moore, viresh.kumar,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, hepeng68
On 4/9/2025 1:56 AM, Lifeng Zheng wrote:
> In ACPI 6.5, s8.4.6.1 _CPC (Continuous Performance Control), whether each
> of the per-cpu cpc_regs[] is mendatory or optional is defined. Since the
mandatory
> CPC_SUPPORTED() check is only for optional cpc field, another macro to
> check if the field is optional is needed.
>
> Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
> Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
> ---
> drivers/acpi/cppc_acpi.c | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index f193e713825a..39f019e265da 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -129,6 +129,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
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v6 8/8] ACPI: CPPC: Add three functions related to autonomous selection
2025-04-09 6:57 ` [PATCH v6 8/8] ACPI: CPPC: Add three functions related to autonomous selection Lifeng Zheng
@ 2025-04-09 18:59 ` Mario Limonciello
2025-04-10 8:31 ` zhenglifeng (A)
0 siblings, 1 reply; 15+ messages in thread
From: Mario Limonciello @ 2025-04-09 18:59 UTC (permalink / raw)
To: Lifeng Zheng, rafael, lenb, robert.moore, viresh.kumar,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, hepeng68
On 4/9/2025 1:57 AM, Lifeng Zheng wrote:
> 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 <pierre.gondois@arm.com>
> Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
> ---
> drivers/acpi/cppc_acpi.c | 80 ++++++++++++++++++++++++++++++++++++++++
> include/acpi/cppc_acpi.h | 24 ++++++++++++
> 2 files changed, 104 insertions(+)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index ef2394c074e3..3d5eace44af5 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1608,6 +1608,86 @@ 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)
Any reason this is a u64 argument when the biggest value you can support
is 0xFF? Presumably you could drop the the bounds check below if you
limited the variable size.
> +{
> + 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;
> +
> + 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);
Since this is exported code, do you perhaps want a check that
auto_act_window is not NULL to avoid a possible accidental NULL pointer
dereference?
> +
> +/**
> + * 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 stroe is 1270000000 */
store
> + 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.
> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
> index 31767c65be20..325e9543e08f 100644
> --- a/include/acpi/cppc_acpi.h
> +++ b/include/acpi/cppc_acpi.h
> @@ -32,6 +32,15 @@
> #define CMD_READ 0
> #define CMD_WRITE 1
>
> +#define CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE (7)
> +#define CPPC_AUTO_ACT_WINDOW_EXP_BIT_SIZE (3)
> +#define CPPC_AUTO_ACT_WINDOW_MAX_SIG ((1 << CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE) - 1)
> +#define CPPC_AUTO_ACT_WINDOW_MAX_EXP ((1 << CPPC_AUTO_ACT_WINDOW_EXP_BIT_SIZE) - 1)
> +/* CPPC_AUTO_ACT_WINDOW_MAX_SIG is 127, so 128 and 129 will decay to 127 when writing */
> +#define CPPC_AUTO_ACT_WINDOW_SIG_CARRY_THRESH 129
> +
> +#define CPPC_ENERGY_PERF_MAX (0xFF)
> +
> /* Each register has the folowing format. */
> struct cpc_reg {
> u8 descriptor;
> @@ -159,6 +168,9 @@ extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
> extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
> extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
> extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
> +extern int cppc_set_epp(int cpu, u64 epp_val);
> +extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window);
> +extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window);
> extern int cppc_get_auto_sel(int cpu, bool *enable);
> extern int cppc_set_auto_sel(int cpu, bool enable);
> extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
> @@ -229,6 +241,18 @@ static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
> {
> return -EOPNOTSUPP;
> }
> +static inline int cppc_set_epp(int cpu, u64 epp_val)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_get_auto_act_window(int cpu, u64 *auto_act_window)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_set_auto_act_window(int cpu, u64 auto_act_window)
> +{
> + return -EOPNOTSUPP;
> +}
> static inline int cppc_get_auto_sel(int cpu, bool *enable)
> {
> return -EOPNOTSUPP;
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional
2025-04-09 18:53 ` Mario Limonciello
@ 2025-04-10 8:21 ` zhenglifeng (A)
0 siblings, 0 replies; 15+ messages in thread
From: zhenglifeng (A) @ 2025-04-10 8:21 UTC (permalink / raw)
To: Mario Limonciello, rafael, lenb, robert.moore, viresh.kumar,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, hepeng68
On 2025/4/10 2:53, Mario Limonciello wrote:
> On 4/9/2025 1:56 AM, Lifeng Zheng wrote:
>> In ACPI 6.5, s8.4.6.1 _CPC (Continuous Performance Control), whether each
>> of the per-cpu cpc_regs[] is mendatory or optional is defined. Since the
> mandatory
Thanks!
>> CPC_SUPPORTED() check is only for optional cpc field, another macro to
>> check if the field is optional is needed.
>>
>> Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
>> Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
>> ---
>> drivers/acpi/cppc_acpi.c | 14 ++++++++++++++
>> 1 file changed, 14 insertions(+)
>>
>> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
>> index f193e713825a..39f019e265da 100644
>> --- a/drivers/acpi/cppc_acpi.c
>> +++ b/drivers/acpi/cppc_acpi.c
>> @@ -129,6 +129,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
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v6 2/8] ACPI: CPPC: Optimize cppc_get_perf()
2025-04-09 17:10 ` Rafael J. Wysocki
@ 2025-04-10 8:23 ` zhenglifeng (A)
0 siblings, 0 replies; 15+ messages in thread
From: zhenglifeng (A) @ 2025-04-10 8:23 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: lenb, robert.moore, viresh.kumar, mario.limonciello,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois,
acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, hepeng68
On 2025/4/10 1:10, Rafael J. Wysocki wrote:
> On Wed, Apr 9, 2025 at 8:57 AM Lifeng Zheng <zhenglifeng1@huawei.com> wrote:
>>
>> 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 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.
>>
>> 3. Return the result of cpc_read() instead of 0.
>>
>> Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
>> Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
>> ---
>> drivers/acpi/cppc_acpi.c | 21 ++++++++++++++-------
>> 1 file changed, 14 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
>> index 39f019e265da..2f789d3b3cad 100644
>> --- a/drivers/acpi/cppc_acpi.c
>> +++ b/drivers/acpi/cppc_acpi.c
>> @@ -1201,20 +1201,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) :
>> + IS_NULL_REG(®->cpc_entry.reg)) {
>
> Please avoid using the ternary operator in any new kernel code.
>
> Why not write it this way
>
> 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)) {
OK. Will replace it. Thanks!
>
>> + 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;
>>
>> @@ -1223,9 +1232,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);
>> }
>>
>> /**
>> --
>
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v6 8/8] ACPI: CPPC: Add three functions related to autonomous selection
2025-04-09 18:59 ` Mario Limonciello
@ 2025-04-10 8:31 ` zhenglifeng (A)
0 siblings, 0 replies; 15+ messages in thread
From: zhenglifeng (A) @ 2025-04-10 8:31 UTC (permalink / raw)
To: Mario Limonciello, rafael, lenb, robert.moore, viresh.kumar,
gautham.shenoy, ray.huang, perry.yuan, pierre.gondois
Cc: acpica-devel, linux-acpi, linux-kernel, linux-pm, linuxarm,
jonathan.cameron, zhanjie9, lihuisong, cenxinghai, hepeng68
On 2025/4/10 2:59, Mario Limonciello wrote:
> On 4/9/2025 1:57 AM, Lifeng Zheng wrote:
>> 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 <pierre.gondois@arm.com>
>> Signed-off-by: Lifeng Zheng <zhenglifeng1@huawei.com>
>> ---
>> drivers/acpi/cppc_acpi.c | 80 ++++++++++++++++++++++++++++++++++++++++
>> include/acpi/cppc_acpi.h | 24 ++++++++++++
>> 2 files changed, 104 insertions(+)
>>
>> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
>> index ef2394c074e3..3d5eace44af5 100644
>> --- a/drivers/acpi/cppc_acpi.c
>> +++ b/drivers/acpi/cppc_acpi.c
>> @@ -1608,6 +1608,86 @@ 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)
>
> Any reason this is a u64 argument when the biggest value you can support is 0xFF? Presumably you could drop the the bounds check below if you limited the variable size.
cppc_get_epp_perf() uses u64, so I think it is better to keep the same.
>
>> +{
>> + 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;
>> +
>> + 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);
>
> Since this is exported code, do you perhaps want a check that auto_act_window is not NULL to avoid a possible accidental NULL pointer dereference?
Yes. Make sense. Thanks!
>
>> +
>> +/**
>> + * 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 stroe is 1270000000 */
>
> store
Thanks!
>
>> + 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.
>> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
>> index 31767c65be20..325e9543e08f 100644
>> --- a/include/acpi/cppc_acpi.h
>> +++ b/include/acpi/cppc_acpi.h
>> @@ -32,6 +32,15 @@
>> #define CMD_READ 0
>> #define CMD_WRITE 1
>> +#define CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE (7)
>> +#define CPPC_AUTO_ACT_WINDOW_EXP_BIT_SIZE (3)
>> +#define CPPC_AUTO_ACT_WINDOW_MAX_SIG ((1 << CPPC_AUTO_ACT_WINDOW_SIG_BIT_SIZE) - 1)
>> +#define CPPC_AUTO_ACT_WINDOW_MAX_EXP ((1 << CPPC_AUTO_ACT_WINDOW_EXP_BIT_SIZE) - 1)
>> +/* CPPC_AUTO_ACT_WINDOW_MAX_SIG is 127, so 128 and 129 will decay to 127 when writing */
>> +#define CPPC_AUTO_ACT_WINDOW_SIG_CARRY_THRESH 129
>> +
>> +#define CPPC_ENERGY_PERF_MAX (0xFF)
>> +
>> /* Each register has the folowing format. */
>> struct cpc_reg {
>> u8 descriptor;
>> @@ -159,6 +168,9 @@ extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
>> extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
>> extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
>> extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
>> +extern int cppc_set_epp(int cpu, u64 epp_val);
>> +extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window);
>> +extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window);
>> extern int cppc_get_auto_sel(int cpu, bool *enable);
>> extern int cppc_set_auto_sel(int cpu, bool enable);
>> extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
>> @@ -229,6 +241,18 @@ static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
>> {
>> return -EOPNOTSUPP;
>> }
>> +static inline int cppc_set_epp(int cpu, u64 epp_val)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> +static inline int cppc_get_auto_act_window(int cpu, u64 *auto_act_window)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> +static inline int cppc_set_auto_act_window(int cpu, u64 auto_act_window)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> static inline int cppc_get_auto_sel(int cpu, bool *enable)
>> {
>> return -EOPNOTSUPP;
>
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-04-10 8:31 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-09 6:56 [PATCH v6 0/8] Add functions for getting and setting registers related to autonomous selection in cppc_acpi Lifeng Zheng
2025-04-09 6:56 ` [PATCH v6 1/8] ACPI: CPPC: Add IS_OPTIONAL_CPC_REG macro to judge if a cpc_reg is optional Lifeng Zheng
2025-04-09 18:53 ` Mario Limonciello
2025-04-10 8:21 ` zhenglifeng (A)
2025-04-09 6:56 ` [PATCH v6 2/8] ACPI: CPPC: Optimize cppc_get_perf() Lifeng Zheng
2025-04-09 17:10 ` Rafael J. Wysocki
2025-04-10 8:23 ` zhenglifeng (A)
2025-04-09 6:56 ` [PATCH v6 3/8] ACPI: CPPC: Rename cppc_get_perf() to cppc_get_reg_val() Lifeng Zheng
2025-04-09 6:56 ` [PATCH v6 4/8] ACPI: CPPC: Extract cppc_get_reg_val_in_pcc() Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 5/8] ACPI: CPPC: Add cppc_set_reg_val() Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 6/8] ACPI: CPPC: Refactor register value get and set ABIs Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 7/8] ACPI: CPPC: Modify cppc_get_auto_sel_caps() to cppc_get_auto_sel() Lifeng Zheng
2025-04-09 6:57 ` [PATCH v6 8/8] ACPI: CPPC: Add three functions related to autonomous selection Lifeng Zheng
2025-04-09 18:59 ` Mario Limonciello
2025-04-10 8:31 ` zhenglifeng (A)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).