* [PATCH v7 0/7] Enhanced autonomous selection and improvements
@ 2026-01-29 10:48 Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 1/7] ACPI: CPPC: Add cppc_get_perf() API to read performance controls Sumit Gupta
` (8 more replies)
0 siblings, 9 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
As discussed in [7], v5 was split into two parts. This is part 1.
- Patch 1-3 from v6: Applied by Rafael for 6.20.
- Remaining patches: Included in this v7 with review comments addressed.
Part 2 (v5 patches 8-11) will follow separately.
This patch series adds sysfs interfaces for CPPC min_perf, max_perf,
and perf_limited registers, along with supporting ACPI APIs and
improvements for the cppc_cpufreq driver.
CPPC autonomous mode (auto_sel) enables hardware-driven CPU performance
scaling using Energy Performance Preference (EPP) hints. Currently,
there's limited runtime control and visibility into CPPC performance
registers.
This series addresses these gaps by:
1. Exposing min_perf/max_perf registers via sysfs (as frequency in kHz)
to allow fine-grained performance bounds control in autonomous mode.
2. Exposing perf_limited register to detect and clear throttling events.
It also includes code improvements: new APIs for reading performance
controls, a warning for missing mandatory DESIRED_PERF register, and
extended epp_perf support.
The patches are grouped as below:
- Patch 1: Add cppc_get_perf() API (independent).
- Patch 2: Warn on missing mandatory DESIRED_PERF (independent).
- Patch 3: Extend cppc_set_epp_perf for FFH/SystemMemory (independent)
- Patch 4-5: APIs, sysfs for min/max_perf, perf_limited (independent)
- Patch 6: Doc for min/max_perf and perf_limited (depends on 4-5)
- Patch 7: Update cached perf_ctrls on sysfs write (independent).
---
v6[7] -> v7:
- patch 1-3 (v6): Dropped as they were applied by Rafael for 6.20.
- patch 2 (v7): Added new patch to warn on missing DESIRED_PERF as
suggested by Pierre.
- patch 4, 7 (v7): Removed mutex from sysfs store functions as
policy->rwsem already provides synchronization.
- patch 4 (v7): Added validation checks in store_min/max_perf.
Sumit Gupta (7):
ACPI: CPPC: Add cppc_get_perf() API to read performance controls
ACPI: CPPC: Warn on missing mandatory DESIRED_PERF register
ACPI: CPPC: Extend cppc_set_epp_perf() for FFH/SystemMemory
ACPI: CPPC: add APIs and sysfs interface for min/max_perf
ACPI: CPPC: add APIs and sysfs interface for perf_limited
cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited
cpufreq: CPPC: Update cached perf_ctrls on sysfs write
.../ABI/testing/sysfs-devices-system-cpu | 44 ++++
drivers/acpi/cppc_acpi.c | 214 +++++++++++++++++-
drivers/cpufreq/cppc_cpufreq.c | 207 ++++++++++++++++-
include/acpi/cppc_acpi.h | 40 ++++
4 files changed, 500 insertions(+), 5 deletions(-)
[1] https://lore.kernel.org/lkml/20250211103737.447704-1-sumitg@nvidia.com/
[2] https://lore.kernel.org/lkml/20250823200121.1320197-1-sumitg@nvidia.com/
[3] https://lore.kernel.org/lkml/20251001150104.1275188-1-sumitg@nvidia.com/
[4] https://lore.kernel.org/lkml/20251105113844.4086250-1-sumitg@nvidia.com/
[5] https://lore.kernel.org/lkml/20251223121307.711773-1-sumitg@nvidia.com/
[6] https://lore.kernel.org/lkml/20260120145623.2959636-1-sumitg@nvidia.com/
[7] https://lore.kernel.org/lkml/66f58f43-631b-40a0-8d42-4e90cd24b757@arm.com/
--
2.34.1
^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v7 1/7] ACPI: CPPC: Add cppc_get_perf() API to read performance controls
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
@ 2026-01-29 10:48 ` Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 2/7] ACPI: CPPC: Warn on missing mandatory DESIRED_PERF register Sumit Gupta
` (7 subsequent siblings)
8 siblings, 0 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
Add cppc_get_perf() function to read values of performance control
registers including desired_perf, min_perf, max_perf, energy_perf,
and auto_sel.
This provides a read interface to complement the existing
cppc_set_perf() write interface for performance control registers.
Note that auto_sel is read by cppc_get_perf() but not written by
cppc_set_perf() to avoid unintended mode changes during performance
updates. It can be updated with existing dedicated cppc_set_auto_sel()
API.
Use cppc_get_perf() in cppc_cpufreq_get_cpu_data() to initialize
perf_ctrls with current hardware register values during cpufreq
policy initialization.
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/acpi/cppc_acpi.c | 80 ++++++++++++++++++++++++++++++++++
drivers/cpufreq/cppc_cpufreq.c | 6 +++
include/acpi/cppc_acpi.h | 5 +++
3 files changed, 91 insertions(+)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index a09bdabaa804..de35aeb07833 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1739,6 +1739,86 @@ int cppc_set_enable(int cpu, bool enable)
}
EXPORT_SYMBOL_GPL(cppc_set_enable);
+/**
+ * cppc_get_perf - Get a CPU's performance controls.
+ * @cpu: CPU for which to get performance controls.
+ * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
+ *
+ * Return: 0 for success with perf_ctrls, -ERRNO otherwise.
+ */
+int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
+{
+ struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
+ struct cpc_register_resource *desired_perf_reg,
+ *min_perf_reg, *max_perf_reg,
+ *energy_perf_reg, *auto_sel_reg;
+ u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0;
+ int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu);
+ struct cppc_pcc_data *pcc_ss_data = NULL;
+ int ret = 0, regs_in_pcc = 0;
+
+ if (!cpc_desc) {
+ pr_debug("No CPC descriptor for CPU:%d\n", cpu);
+ return -ENODEV;
+ }
+
+ if (!perf_ctrls) {
+ pr_debug("Invalid perf_ctrls pointer\n");
+ return -EINVAL;
+ }
+
+ desired_perf_reg = &cpc_desc->cpc_regs[DESIRED_PERF];
+ min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF];
+ max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF];
+ energy_perf_reg = &cpc_desc->cpc_regs[ENERGY_PERF];
+ auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
+
+ /* Are any of the regs PCC ?*/
+ if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) ||
+ CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) ||
+ CPC_IN_PCC(auto_sel_reg)) {
+ if (pcc_ss_id < 0) {
+ pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
+ return -ENODEV;
+ }
+ pcc_ss_data = pcc_data[pcc_ss_id];
+ regs_in_pcc = 1;
+ down_write(&pcc_ss_data->pcc_lock);
+ /* Ring doorbell once to update PCC subspace */
+ if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) {
+ ret = -EIO;
+ goto out_err;
+ }
+ }
+
+ /* Read optional elements if present */
+ if (CPC_SUPPORTED(max_perf_reg))
+ cpc_read(cpu, max_perf_reg, &max);
+ perf_ctrls->max_perf = max;
+
+ if (CPC_SUPPORTED(min_perf_reg))
+ cpc_read(cpu, min_perf_reg, &min);
+ perf_ctrls->min_perf = min;
+
+ if (CPC_SUPPORTED(desired_perf_reg))
+ cpc_read(cpu, desired_perf_reg, &desired_perf);
+ perf_ctrls->desired_perf = desired_perf;
+
+ if (CPC_SUPPORTED(energy_perf_reg))
+ cpc_read(cpu, energy_perf_reg, &energy_perf);
+ perf_ctrls->energy_perf = energy_perf;
+
+ if (CPC_SUPPORTED(auto_sel_reg))
+ cpc_read(cpu, auto_sel_reg, &auto_sel);
+ perf_ctrls->auto_sel = (bool)auto_sel;
+
+out_err:
+ if (regs_in_pcc)
+ up_write(&pcc_ss_data->pcc_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cppc_get_perf);
+
/**
* cppc_set_perf - Set a CPU's performance controls.
* @cpu: CPU for which to set performance controls.
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 7e8042efedd1..1421f30e87e4 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -594,6 +594,12 @@ static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu)
goto free_mask;
}
+ ret = cppc_get_perf(cpu, &cpu_data->perf_ctrls);
+ if (ret) {
+ pr_debug("Err reading CPU%d perf ctrls: ret:%d\n", cpu, ret);
+ goto free_mask;
+ }
+
return cpu_data;
free_mask:
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 4d644f03098e..3fc796c0d902 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -151,6 +151,7 @@ extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf);
extern int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf);
extern int cppc_get_highest_perf(int cpunum, u64 *highest_perf);
extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
+extern int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
extern int cppc_set_enable(int cpu, bool enable);
extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
@@ -193,6 +194,10 @@ static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_
{
return -EOPNOTSUPP;
}
+static inline int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
+{
+ return -EOPNOTSUPP;
+}
static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
{
return -EOPNOTSUPP;
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 2/7] ACPI: CPPC: Warn on missing mandatory DESIRED_PERF register
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 1/7] ACPI: CPPC: Add cppc_get_perf() API to read performance controls Sumit Gupta
@ 2026-01-29 10:48 ` Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 3/7] ACPI: CPPC: Extend cppc_set_epp_perf() for FFH/SystemMemory Sumit Gupta
` (6 subsequent siblings)
8 siblings, 0 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
Add a warning during CPPC processor probe if the Desired Performance
register is not supported when it should be.
As per 8.4.6.1.2.3 section of ACPI 6.6 specification,
"The Desired Performance Register is optional only when OSPM indicates
support for CPPC2 in the platform-wide _OSC capabilities and the
Autonomous Selection Enable field is encoded as an Integer with a
value of 1."
In other words:
- In CPPC v1, DESIRED_PERF is mandatory
- In CPPC v2, it becomes optional only when AUTO_SEL_ENABLE is supported
This helps detect firmware configuration issues early during boot.
Link: https://lore.kernel.org/lkml/9fa21599-004a-4af8-acc2-190fd0404e35@nvidia.com/
Suggested-by: Pierre Gondois <pierre.gondois@arm.com>
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/acpi/cppc_acpi.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index de35aeb07833..0eb1a6d54e88 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -854,6 +854,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
}
per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id;
+ /*
+ * In CPPC v1, DESIRED_PERF is mandatory. In CPPC v2, it is optional
+ * only when AUTO_SEL_ENABLE is supported.
+ */
+ if (!CPC_SUPPORTED(&cpc_ptr->cpc_regs[DESIRED_PERF]) &&
+ (!osc_sb_cppc2_support_acked ||
+ !CPC_SUPPORTED(&cpc_ptr->cpc_regs[AUTO_SEL_ENABLE])))
+ pr_warn("Desired perf. register is mandatory if CPPC v2 is not supported "
+ "or autonomous selection is disabled\n");
+
/*
* Initialize the remaining cpc_regs as unsupported.
* Example: In case FW exposes CPPC v2, the below loop will initialize
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 3/7] ACPI: CPPC: Extend cppc_set_epp_perf() for FFH/SystemMemory
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 1/7] ACPI: CPPC: Add cppc_get_perf() API to read performance controls Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 2/7] ACPI: CPPC: Warn on missing mandatory DESIRED_PERF register Sumit Gupta
@ 2026-01-29 10:48 ` Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf Sumit Gupta
` (5 subsequent siblings)
8 siblings, 0 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
Extend cppc_set_epp_perf() to write both auto_sel and energy_perf
registers when they are in FFH or SystemMemory address space.
This keeps the behavior consistent with PCC case where both registers
are already updated together, but was missing for FFH/SystemMemory.
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/acpi/cppc_acpi.c | 24 +++++++++++++++++++++---
1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 0eb1a6d54e88..08e62b58eb83 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1572,6 +1572,8 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
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;
+ bool autosel_ffh_sysmem;
+ bool epp_ffh_sysmem;
int ret;
if (!cpc_desc) {
@@ -1582,6 +1584,11 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
epp_set_reg = &cpc_desc->cpc_regs[ENERGY_PERF];
+ epp_ffh_sysmem = CPC_SUPPORTED(epp_set_reg) &&
+ (CPC_IN_FFH(epp_set_reg) || CPC_IN_SYSTEM_MEMORY(epp_set_reg));
+ autosel_ffh_sysmem = CPC_SUPPORTED(auto_sel_reg) &&
+ (CPC_IN_FFH(auto_sel_reg) || CPC_IN_SYSTEM_MEMORY(auto_sel_reg));
+
if (CPC_IN_PCC(epp_set_reg) || CPC_IN_PCC(auto_sel_reg)) {
if (pcc_ss_id < 0) {
pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
@@ -1607,11 +1614,22 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
up_write(&pcc_ss_data->pcc_lock);
} else if (osc_cpc_flexible_adr_space_confirmed &&
- CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) {
- ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf);
+ (epp_ffh_sysmem || autosel_ffh_sysmem)) {
+ if (autosel_ffh_sysmem) {
+ ret = cpc_write(cpu, auto_sel_reg, enable);
+ if (ret)
+ return ret;
+ }
+
+ if (epp_ffh_sysmem) {
+ ret = cpc_write(cpu, epp_set_reg,
+ perf_ctrls->energy_perf);
+ if (ret)
+ return ret;
+ }
} else {
ret = -ENOTSUPP;
- pr_debug("_CPC in PCC and _CPC in FFH are not supported\n");
+ pr_debug("_CPC in PCC/FFH/SystemMemory are not supported\n");
}
return ret;
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
` (2 preceding siblings ...)
2026-01-29 10:48 ` [PATCH v7 3/7] ACPI: CPPC: Extend cppc_set_epp_perf() for FFH/SystemMemory Sumit Gupta
@ 2026-01-29 10:48 ` Sumit Gupta
2026-01-31 4:06 ` zhenglifeng (A)
2026-02-03 12:43 ` Rafael J. Wysocki
2026-01-29 10:48 ` [PATCH v7 5/7] ACPI: CPPC: add APIs and sysfs interface for perf_limited Sumit Gupta
` (4 subsequent siblings)
8 siblings, 2 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
Add cppc_get/set_min_perf() and cppc_get/set_max_perf() APIs to read and
write the MIN_PERF and MAX_PERF registers.
Also add sysfs interfaces (min_perf, max_perf) in cppc_cpufreq driver
to expose these controls to userspace. The sysfs values are in frequency
(kHz) for consistency with other cpufreq sysfs files.
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/acpi/cppc_acpi.c | 44 +++++++++
drivers/cpufreq/cppc_cpufreq.c | 165 +++++++++++++++++++++++++++++++++
include/acpi/cppc_acpi.h | 20 ++++
3 files changed, 229 insertions(+)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 08e62b58eb83..b2b8daab69ed 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1753,6 +1753,50 @@ int cppc_set_auto_sel(int cpu, bool enable)
}
EXPORT_SYMBOL_GPL(cppc_set_auto_sel);
+/**
+ * cppc_get_min_perf - Read minimum performance register.
+ * @cpu: CPU from which to read register.
+ * @min_perf: Return address.
+ */
+int cppc_get_min_perf(int cpu, u64 *min_perf)
+{
+ return cppc_get_reg_val(cpu, MIN_PERF, min_perf);
+}
+EXPORT_SYMBOL_GPL(cppc_get_min_perf);
+
+/**
+ * cppc_set_min_perf - Write minimum performance register.
+ * @cpu: CPU to which to write register.
+ * @min_perf: the desired minimum performance value to be updated.
+ */
+int cppc_set_min_perf(int cpu, u32 min_perf)
+{
+ return cppc_set_reg_val(cpu, MIN_PERF, min_perf);
+}
+EXPORT_SYMBOL_GPL(cppc_set_min_perf);
+
+/**
+ * cppc_get_max_perf - Read maximum performance register.
+ * @cpu: CPU from which to read register.
+ * @max_perf: Return address.
+ */
+int cppc_get_max_perf(int cpu, u64 *max_perf)
+{
+ return cppc_get_reg_val(cpu, MAX_PERF, max_perf);
+}
+EXPORT_SYMBOL_GPL(cppc_get_max_perf);
+
+/**
+ * cppc_set_max_perf - Write maximum performance register.
+ * @cpu: CPU to which to write register.
+ * @max_perf: the desired maximum performance value to be updated.
+ */
+int cppc_set_max_perf(int cpu, u32 max_perf)
+{
+ return cppc_set_reg_val(cpu, MAX_PERF, max_perf);
+}
+EXPORT_SYMBOL_GPL(cppc_set_max_perf);
+
/**
* cppc_set_enable - Set to enable CPPC on the processor by writing the
* Continuous Performance Control package EnableRegister field.
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 1421f30e87e4..8787185cd8b0 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -570,6 +570,35 @@ static void populate_efficiency_class(void)
}
#endif
+/* Set min/max performance HW register and cache the value */
+static int cppc_cpufreq_set_mperf_reg(struct cpufreq_policy *policy,
+ u64 val, bool is_min)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ struct cppc_perf_caps *caps = &cpu_data->perf_caps;
+ unsigned int cpu = policy->cpu;
+ u32 perf;
+ int ret;
+
+ perf = clamp(val, caps->lowest_perf, caps->highest_perf);
+
+ ret = is_min ? cppc_set_min_perf(cpu, perf) :
+ cppc_set_max_perf(cpu, perf);
+ if (ret) {
+ if (ret != -EOPNOTSUPP)
+ pr_warn("CPU%d: set %s_perf=%u failed (%d)\n",
+ cpu, is_min ? "min" : "max", perf, ret);
+ return ret;
+ }
+
+ if (is_min)
+ cpu_data->perf_ctrls.min_perf = perf;
+ else
+ cpu_data->perf_ctrls.max_perf = perf;
+
+ return 0;
+}
+
static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu)
{
struct cppc_cpudata *cpu_data;
@@ -919,16 +948,152 @@ CPPC_CPUFREQ_ATTR_RW_U64(auto_act_window, cppc_get_auto_act_window,
CPPC_CPUFREQ_ATTR_RW_U64(energy_performance_preference_val,
cppc_get_epp_perf, cppc_set_epp)
+/**
+ * show_min_perf - Show minimum performance as frequency (kHz)
+ * @policy: cpufreq policy
+ * @buf: buffer to write the frequency value to
+ *
+ * Reads the MIN_PERF register and converts the performance value to
+ * frequency (kHz).
+ */
+static ssize_t show_min_perf(struct cpufreq_policy *policy, char *buf)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ struct cppc_perf_caps *caps = &cpu_data->perf_caps;
+ u64 perf;
+ int ret;
+
+ ret = cppc_get_min_perf(policy->cpu, &perf);
+ if (ret == -EOPNOTSUPP)
+ return sysfs_emit(buf, "<unsupported>\n");
+ if (ret)
+ return ret;
+
+ /* Use lowest_perf if register is uninitialized or out of range */
+ if (perf == 0 || perf < caps->lowest_perf)
+ perf = caps->lowest_perf;
+
+ /* Convert performance to frequency (kHz) for user */
+ return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
+}
+
+/**
+ * store_min_perf - Set minimum performance from frequency (kHz)
+ * @policy: cpufreq policy
+ * @buf: buffer containing the frequency value
+ * @count: size of @buf
+ *
+ * Converts the user-provided frequency (kHz) to a performance value
+ * and writes it to the MIN_PERF register.
+ */
+static ssize_t store_min_perf(struct cpufreq_policy *policy, const char *buf,
+ size_t count)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ unsigned int freq_khz;
+ u64 perf;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &freq_khz);
+ if (ret)
+ return ret;
+
+ /* Convert frequency (kHz) to performance value */
+ perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
+
+ /*
+ * min_perf must be less than or equal to max_perf.
+ * Skip check if max_perf is 0 (uninitialized).
+ */
+ if (cpu_data->perf_ctrls.max_perf &&
+ perf > cpu_data->perf_ctrls.max_perf)
+ return -EINVAL;
+
+ ret = cppc_cpufreq_set_mperf_reg(policy, perf, true);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/**
+ * show_max_perf - Show maximum performance as frequency (kHz)
+ * @policy: cpufreq policy
+ * @buf: buffer to write the frequency value to
+ *
+ * Reads the MAX_PERF register and converts the performance value to
+ * frequency (kHz).
+ */
+static ssize_t show_max_perf(struct cpufreq_policy *policy, char *buf)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ struct cppc_perf_caps *caps = &cpu_data->perf_caps;
+ u64 perf;
+ int ret;
+
+ ret = cppc_get_max_perf(policy->cpu, &perf);
+ if (ret == -EOPNOTSUPP)
+ return sysfs_emit(buf, "<unsupported>\n");
+ if (ret)
+ return ret;
+
+ /* Use highest_perf if register is uninitialized or out of range */
+ if (perf == 0 || perf > caps->highest_perf)
+ perf = caps->highest_perf;
+
+ /* Convert performance to frequency (kHz) for user */
+ return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
+}
+
+/**
+ * store_max_perf - Set maximum performance from frequency (kHz)
+ * @policy: cpufreq policy
+ * @buf: buffer containing the frequency value
+ * @count: size of @buf
+ *
+ * Converts the user-provided frequency (kHz) to a performance value
+ * and writes it to the MAX_PERF register.
+ */
+static ssize_t store_max_perf(struct cpufreq_policy *policy, const char *buf,
+ size_t count)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ unsigned int freq_khz;
+ u64 perf;
+ int ret;
+
+ ret = kstrtouint(buf, 0, &freq_khz);
+ if (ret)
+ return ret;
+
+ /* Convert frequency (kHz) to performance value */
+ perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
+
+ /* max_perf must be greater than or equal to min_perf */
+ if (perf < cpu_data->perf_ctrls.min_perf)
+ return -EINVAL;
+
+ ret = cppc_cpufreq_set_mperf_reg(policy, perf, false);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
cpufreq_freq_attr_ro(freqdomain_cpus);
cpufreq_freq_attr_rw(auto_select);
cpufreq_freq_attr_rw(auto_act_window);
cpufreq_freq_attr_rw(energy_performance_preference_val);
+cpufreq_freq_attr_rw(min_perf);
+cpufreq_freq_attr_rw(max_perf);
static struct freq_attr *cppc_cpufreq_attr[] = {
&freqdomain_cpus,
&auto_select,
&auto_act_window,
&energy_performance_preference_val,
+ &min_perf,
+ &max_perf,
NULL,
};
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 3fc796c0d902..b358440cd0e2 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -174,6 +174,10 @@ 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 cppc_get_min_perf(int cpu, u64 *min_perf);
+extern int cppc_set_min_perf(int cpu, u32 min_perf);
+extern int cppc_get_max_perf(int cpu, u64 *max_perf);
+extern int cppc_set_max_perf(int cpu, u32 max_perf);
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
extern int amd_detect_prefcore(bool *detected);
@@ -270,6 +274,22 @@ static inline int cppc_set_auto_sel(int cpu, bool enable)
{
return -EOPNOTSUPP;
}
+static inline int cppc_get_min_perf(int cpu, u64 *min_perf)
+{
+ return -EOPNOTSUPP;
+}
+static inline int cppc_set_min_perf(int cpu, u32 min_perf)
+{
+ return -EOPNOTSUPP;
+}
+static inline int cppc_get_max_perf(int cpu, u64 *max_perf)
+{
+ return -EOPNOTSUPP;
+}
+static inline int cppc_set_max_perf(int cpu, u32 max_perf)
+{
+ return -EOPNOTSUPP;
+}
static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
{
return -ENODEV;
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 5/7] ACPI: CPPC: add APIs and sysfs interface for perf_limited
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
` (3 preceding siblings ...)
2026-01-29 10:48 ` [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf Sumit Gupta
@ 2026-01-29 10:48 ` Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 6/7] cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited Sumit Gupta
` (3 subsequent siblings)
8 siblings, 0 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
Add sysfs interface to read/write the Performance Limited register.
The Performance Limited register indicates to the OS that an
unpredictable event (like thermal throttling) has limited processor
performance. It contains two sticky bits set by the platform:
- Bit 0 (Desired_Excursion): Set when delivered performance is
constrained below desired performance. Not used when Autonomous
Selection is enabled.
- Bit 1 (Minimum_Excursion): Set when delivered performance is
constrained below minimum performance.
These bits remain set until OSPM explicitly clears them. The write
operation accepts a bitmask of bits to clear:
- Write 0x1 to clear bit 0
- Write 0x2 to clear bit 1
- Write 0x3 to clear both bits
This enables users to detect if platform throttling impacted a workload.
Users clear the register before execution, run the workload, then check
afterward - if set, hardware throttling occurred during that time window.
The interface is exposed as:
/sys/devices/system/cpu/cpuX/cpufreq/perf_limited
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/acpi/cppc_acpi.c | 56 ++++++++++++++++++++++++++++++++++
drivers/cpufreq/cppc_cpufreq.c | 5 +++
include/acpi/cppc_acpi.h | 15 +++++++++
3 files changed, 76 insertions(+)
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index b2b8daab69ed..bf008fb80934 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -1797,6 +1797,62 @@ int cppc_set_max_perf(int cpu, u32 max_perf)
}
EXPORT_SYMBOL_GPL(cppc_set_max_perf);
+/**
+ * cppc_get_perf_limited - Get the Performance Limited register value.
+ * @cpu: CPU from which to get Performance Limited register.
+ * @perf_limited: Pointer to store the Performance Limited value.
+ *
+ * The returned value contains sticky status bits indicating platform-imposed
+ * performance limitations.
+ *
+ * Return: 0 for success, -EIO on failure, -EOPNOTSUPP if not supported.
+ */
+int cppc_get_perf_limited(int cpu, u64 *perf_limited)
+{
+ return cppc_get_reg_val(cpu, PERF_LIMITED, perf_limited);
+}
+EXPORT_SYMBOL_GPL(cppc_get_perf_limited);
+
+/**
+ * cppc_set_perf_limited() - Clear bits in the Performance Limited register.
+ * @cpu: CPU on which to write register.
+ * @bits_to_clear: Bitmask of bits to clear in the perf_limited register.
+ *
+ * The Performance Limited register contains two sticky bits set by platform:
+ * - Bit 0 (Desired_Excursion): Set when delivered performance is constrained
+ * below desired performance. Not used when Autonomous Selection is enabled.
+ * - Bit 1 (Minimum_Excursion): Set when delivered performance is constrained
+ * below minimum performance.
+ *
+ * These bits are sticky and remain set until OSPM explicitly clears them.
+ * This function only allows clearing bits (the platform sets them).
+ *
+ * Return: 0 for success, -EINVAL for invalid bits, -EIO on register
+ * access failure, -EOPNOTSUPP if not supported.
+ */
+int cppc_set_perf_limited(int cpu, u64 bits_to_clear)
+{
+ u64 current_val, new_val;
+ int ret;
+
+ /* Only bits 0 and 1 are valid */
+ if (bits_to_clear & ~CPPC_PERF_LIMITED_MASK)
+ return -EINVAL;
+
+ if (!bits_to_clear)
+ return 0;
+
+ ret = cppc_get_perf_limited(cpu, ¤t_val);
+ if (ret)
+ return ret;
+
+ /* Clear the specified bits */
+ new_val = current_val & ~bits_to_clear;
+
+ return cppc_set_reg_val(cpu, PERF_LIMITED, new_val);
+}
+EXPORT_SYMBOL_GPL(cppc_set_perf_limited);
+
/**
* cppc_set_enable - Set to enable CPPC on the processor by writing the
* Continuous Performance Control package EnableRegister field.
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 8787185cd8b0..ca49e25aba5d 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -1080,12 +1080,16 @@ static ssize_t store_max_perf(struct cpufreq_policy *policy, const char *buf,
return count;
}
+CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited,
+ cppc_set_perf_limited)
+
cpufreq_freq_attr_ro(freqdomain_cpus);
cpufreq_freq_attr_rw(auto_select);
cpufreq_freq_attr_rw(auto_act_window);
cpufreq_freq_attr_rw(energy_performance_preference_val);
cpufreq_freq_attr_rw(min_perf);
cpufreq_freq_attr_rw(max_perf);
+cpufreq_freq_attr_rw(perf_limited);
static struct freq_attr *cppc_cpufreq_attr[] = {
&freqdomain_cpus,
@@ -1094,6 +1098,7 @@ static struct freq_attr *cppc_cpufreq_attr[] = {
&energy_performance_preference_val,
&min_perf,
&max_perf,
+ &perf_limited,
NULL,
};
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index b358440cd0e2..f3a04ccd10b7 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -42,6 +42,11 @@
#define CPPC_EPP_PERFORMANCE_PREF 0x00
#define CPPC_EPP_ENERGY_EFFICIENCY_PREF 0xFF
+#define CPPC_PERF_LIMITED_DESIRED_EXCURSION BIT(0)
+#define CPPC_PERF_LIMITED_MINIMUM_EXCURSION BIT(1)
+#define CPPC_PERF_LIMITED_MASK (CPPC_PERF_LIMITED_DESIRED_EXCURSION | \
+ CPPC_PERF_LIMITED_MINIMUM_EXCURSION)
+
/* Each register has the folowing format. */
struct cpc_reg {
u8 descriptor;
@@ -178,6 +183,8 @@ extern int cppc_get_min_perf(int cpu, u64 *min_perf);
extern int cppc_set_min_perf(int cpu, u32 min_perf);
extern int cppc_get_max_perf(int cpu, u64 *max_perf);
extern int cppc_set_max_perf(int cpu, u32 max_perf);
+extern int cppc_get_perf_limited(int cpu, u64 *perf_limited);
+extern int cppc_set_perf_limited(int cpu, u64 perf_limited);
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
extern int amd_detect_prefcore(bool *detected);
@@ -290,6 +297,14 @@ static inline int cppc_set_max_perf(int cpu, u32 max_perf)
{
return -EOPNOTSUPP;
}
+static inline int cppc_get_perf_limited(int cpu, u64 *perf_limited)
+{
+ return -EOPNOTSUPP;
+}
+static inline int cppc_set_perf_limited(int cpu, u64 perf_limited)
+{
+ return -EOPNOTSUPP;
+}
static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
{
return -ENODEV;
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 6/7] cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
` (4 preceding siblings ...)
2026-01-29 10:48 ` [PATCH v7 5/7] ACPI: CPPC: add APIs and sysfs interface for perf_limited Sumit Gupta
@ 2026-01-29 10:48 ` Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 7/7] cpufreq: CPPC: Update cached perf_ctrls on sysfs write Sumit Gupta
` (2 subsequent siblings)
8 siblings, 0 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
Add sysfs interfaces for Minimum Performance, Maximum Performance
and Performance Limited Register in the cppc_cpufreq driver.
Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
.../ABI/testing/sysfs-devices-system-cpu | 44 +++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 3a05604c21bf..0b0c07c074bf 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -327,6 +327,50 @@ Description: Energy performance preference
This file is only present if the cppc-cpufreq driver is in use.
+What: /sys/devices/system/cpu/cpuX/cpufreq/min_perf
+Date: February 2026
+Contact: linux-pm@vger.kernel.org
+Description: Minimum Performance Frequency
+
+ Read/write a frequency value in kHz from/to this file. This
+ file sets the minimum performance level (as frequency) at
+ which the platform may run. The frequency value is internally
+ converted to a performance value and must be in the range
+ [cpuinfo_min_freq, cpuinfo_max_freq], inclusive.
+
+ This file is only present if the cppc-cpufreq driver is in use.
+
+What: /sys/devices/system/cpu/cpuX/cpufreq/max_perf
+Date: February 2026
+Contact: linux-pm@vger.kernel.org
+Description: Maximum Performance Frequency
+
+ Read/write a frequency value in kHz from/to this file. This
+ file sets the maximum performance level (as frequency) at
+ which the platform may run. The frequency value is internally
+ converted to a performance value and must be in the range
+ [cpuinfo_min_freq, cpuinfo_max_freq], inclusive.
+
+ This file is only present if the cppc-cpufreq driver is in use.
+
+What: /sys/devices/system/cpu/cpuX/cpufreq/perf_limited
+Date: February 2026
+Contact: linux-pm@vger.kernel.org
+Description: Performance Limited
+
+ Read to check if platform throttling (thermal/power/current
+ limits) caused delivered performance to fall below the
+ requested level. A non-zero value indicates throttling occurred.
+
+ Write the bitmask of bits to clear:
+
+ - 0x1 = clear bit 0 (desired performance excursion)
+ - 0x2 = clear bit 1 (minimum performance excursion)
+ - 0x3 = clear both bits
+
+ The platform sets these bits; OSPM can only clear them.
+
+ This file is only present if the cppc-cpufreq driver is in use.
What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
Date: August 2008
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v7 7/7] cpufreq: CPPC: Update cached perf_ctrls on sysfs write
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
` (5 preceding siblings ...)
2026-01-29 10:48 ` [PATCH v7 6/7] cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited Sumit Gupta
@ 2026-01-29 10:48 ` Sumit Gupta
2026-01-30 8:23 ` [PATCH v7 0/7] Enhanced autonomous selection and improvements Pierre Gondois
2026-01-31 2:58 ` zhenglifeng (A)
8 siblings, 0 replies; 26+ messages in thread
From: Sumit Gupta @ 2026-01-29 10:48 UTC (permalink / raw)
To: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu, sumitg
Update the cached perf_ctrls values when writing via sysfs to keep
them in sync with hardware registers:
- store_auto_select(): update perf_ctrls.auto_sel
- store_energy_performance_preference_val(): update perf_ctrls.energy_perf
This ensures consistent cached values after sysfs writes, which
complements the cppc_get_perf() initialization during policy setup.
Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
---
drivers/cpufreq/cppc_cpufreq.c | 31 +++++++++++++++++++++++++++++--
1 file changed, 29 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index ca49e25aba5d..cc04d91bb795 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -884,6 +884,7 @@ static ssize_t show_auto_select(struct cpufreq_policy *policy, char *buf)
static ssize_t store_auto_select(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
bool val;
int ret;
@@ -895,6 +896,8 @@ static ssize_t store_auto_select(struct cpufreq_policy *policy,
if (ret)
return ret;
+ cpu_data->perf_ctrls.auto_sel = val;
+
return count;
}
@@ -945,8 +948,32 @@ static ssize_t store_##_name(struct cpufreq_policy *policy, \
CPPC_CPUFREQ_ATTR_RW_U64(auto_act_window, cppc_get_auto_act_window,
cppc_set_auto_act_window)
-CPPC_CPUFREQ_ATTR_RW_U64(energy_performance_preference_val,
- cppc_get_epp_perf, cppc_set_epp)
+static ssize_t
+show_energy_performance_preference_val(struct cpufreq_policy *policy, char *buf)
+{
+ return cppc_cpufreq_sysfs_show_u64(policy->cpu, cppc_get_epp_perf, buf);
+}
+
+static ssize_t
+store_energy_performance_preference_val(struct cpufreq_policy *policy,
+ const char *buf, size_t count)
+{
+ struct cppc_cpudata *cpu_data = policy->driver_data;
+ u64 val;
+ int ret;
+
+ ret = kstrtou64(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ ret = cppc_set_epp(policy->cpu, val);
+ if (ret)
+ return ret;
+
+ cpu_data->perf_ctrls.energy_perf = val;
+
+ return count;
+}
/**
* show_min_perf - Show minimum performance as frequency (kHz)
--
2.34.1
^ permalink raw reply related [flat|nested] 26+ messages in thread
* Re: [PATCH v7 0/7] Enhanced autonomous selection and improvements
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
` (6 preceding siblings ...)
2026-01-29 10:48 ` [PATCH v7 7/7] cpufreq: CPPC: Update cached perf_ctrls on sysfs write Sumit Gupta
@ 2026-01-30 8:23 ` Pierre Gondois
2026-01-31 2:58 ` zhenglifeng (A)
8 siblings, 0 replies; 26+ messages in thread
From: Pierre Gondois @ 2026-01-30 8:23 UTC (permalink / raw)
To: Sumit Gupta, rafael, viresh.kumar, zhenglifeng1, ionela.voinescu,
lenb, robert.moore, corbet, rdunlap, ray.huang, gautham.shenoy,
mario.limonciello, perry.yuan, zhanjie9, linux-pm, linux-acpi,
linux-doc, acpica-devel, linux-kernel
Cc: linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu
Hi Sumit,
For the whole patch-set:
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
Thanks
On 1/29/26 11:48, Sumit Gupta wrote:
> As discussed in [7], v5 was split into two parts. This is part 1.
> - Patch 1-3 from v6: Applied by Rafael for 6.20.
> - Remaining patches: Included in this v7 with review comments addressed.
> Part 2 (v5 patches 8-11) will follow separately.
>
> This patch series adds sysfs interfaces for CPPC min_perf, max_perf,
> and perf_limited registers, along with supporting ACPI APIs and
> improvements for the cppc_cpufreq driver.
>
> CPPC autonomous mode (auto_sel) enables hardware-driven CPU performance
> scaling using Energy Performance Preference (EPP) hints. Currently,
> there's limited runtime control and visibility into CPPC performance
> registers.
>
> This series addresses these gaps by:
> 1. Exposing min_perf/max_perf registers via sysfs (as frequency in kHz)
> to allow fine-grained performance bounds control in autonomous mode.
> 2. Exposing perf_limited register to detect and clear throttling events.
>
> It also includes code improvements: new APIs for reading performance
> controls, a warning for missing mandatory DESIRED_PERF register, and
> extended epp_perf support.
>
> The patches are grouped as below:
> - Patch 1: Add cppc_get_perf() API (independent).
> - Patch 2: Warn on missing mandatory DESIRED_PERF (independent).
> - Patch 3: Extend cppc_set_epp_perf for FFH/SystemMemory (independent)
> - Patch 4-5: APIs, sysfs for min/max_perf, perf_limited (independent)
> - Patch 6: Doc for min/max_perf and perf_limited (depends on 4-5)
> - Patch 7: Update cached perf_ctrls on sysfs write (independent).
>
> ---
> v6[7] -> v7:
> - patch 1-3 (v6): Dropped as they were applied by Rafael for 6.20.
> - patch 2 (v7): Added new patch to warn on missing DESIRED_PERF as
> suggested by Pierre.
> - patch 4, 7 (v7): Removed mutex from sysfs store functions as
> policy->rwsem already provides synchronization.
> - patch 4 (v7): Added validation checks in store_min/max_perf.
>
> Sumit Gupta (7):
> ACPI: CPPC: Add cppc_get_perf() API to read performance controls
> ACPI: CPPC: Warn on missing mandatory DESIRED_PERF register
> ACPI: CPPC: Extend cppc_set_epp_perf() for FFH/SystemMemory
> ACPI: CPPC: add APIs and sysfs interface for min/max_perf
> ACPI: CPPC: add APIs and sysfs interface for perf_limited
> cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited
> cpufreq: CPPC: Update cached perf_ctrls on sysfs write
>
> .../ABI/testing/sysfs-devices-system-cpu | 44 ++++
> drivers/acpi/cppc_acpi.c | 214 +++++++++++++++++-
> drivers/cpufreq/cppc_cpufreq.c | 207 ++++++++++++++++-
> include/acpi/cppc_acpi.h | 40 ++++
> 4 files changed, 500 insertions(+), 5 deletions(-)
>
> [1] https://lore.kernel.org/lkml/20250211103737.447704-1-sumitg@nvidia.com/
> [2] https://lore.kernel.org/lkml/20250823200121.1320197-1-sumitg@nvidia.com/
> [3] https://lore.kernel.org/lkml/20251001150104.1275188-1-sumitg@nvidia.com/
> [4] https://lore.kernel.org/lkml/20251105113844.4086250-1-sumitg@nvidia.com/
> [5] https://lore.kernel.org/lkml/20251223121307.711773-1-sumitg@nvidia.com/
> [6] https://lore.kernel.org/lkml/20260120145623.2959636-1-sumitg@nvidia.com/
> [7] https://lore.kernel.org/lkml/66f58f43-631b-40a0-8d42-4e90cd24b757@arm.com/
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 0/7] Enhanced autonomous selection and improvements
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
` (7 preceding siblings ...)
2026-01-30 8:23 ` [PATCH v7 0/7] Enhanced autonomous selection and improvements Pierre Gondois
@ 2026-01-31 2:58 ` zhenglifeng (A)
8 siblings, 0 replies; 26+ messages in thread
From: zhenglifeng (A) @ 2026-01-31 2:58 UTC (permalink / raw)
To: Sumit Gupta, rafael, viresh.kumar, pierre.gondois
Cc: ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel, linux-tegra,
treding, jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu
Reviewed-by: Lifeng Zheng <zhenglifeng1@huawei.com>
On 2026/1/29 18:48, Sumit Gupta wrote:
> As discussed in [7], v5 was split into two parts. This is part 1.
> - Patch 1-3 from v6: Applied by Rafael for 6.20.
> - Remaining patches: Included in this v7 with review comments addressed.
> Part 2 (v5 patches 8-11) will follow separately.
>
> This patch series adds sysfs interfaces for CPPC min_perf, max_perf,
> and perf_limited registers, along with supporting ACPI APIs and
> improvements for the cppc_cpufreq driver.
>
> CPPC autonomous mode (auto_sel) enables hardware-driven CPU performance
> scaling using Energy Performance Preference (EPP) hints. Currently,
> there's limited runtime control and visibility into CPPC performance
> registers.
>
> This series addresses these gaps by:
> 1. Exposing min_perf/max_perf registers via sysfs (as frequency in kHz)
> to allow fine-grained performance bounds control in autonomous mode.
> 2. Exposing perf_limited register to detect and clear throttling events.
>
> It also includes code improvements: new APIs for reading performance
> controls, a warning for missing mandatory DESIRED_PERF register, and
> extended epp_perf support.
>
> The patches are grouped as below:
> - Patch 1: Add cppc_get_perf() API (independent).
> - Patch 2: Warn on missing mandatory DESIRED_PERF (independent).
> - Patch 3: Extend cppc_set_epp_perf for FFH/SystemMemory (independent)
> - Patch 4-5: APIs, sysfs for min/max_perf, perf_limited (independent)
> - Patch 6: Doc for min/max_perf and perf_limited (depends on 4-5)
> - Patch 7: Update cached perf_ctrls on sysfs write (independent).
>
> ---
> v6[7] -> v7:
> - patch 1-3 (v6): Dropped as they were applied by Rafael for 6.20.
> - patch 2 (v7): Added new patch to warn on missing DESIRED_PERF as
> suggested by Pierre.
> - patch 4, 7 (v7): Removed mutex from sysfs store functions as
> policy->rwsem already provides synchronization.
> - patch 4 (v7): Added validation checks in store_min/max_perf.
>
> Sumit Gupta (7):
> ACPI: CPPC: Add cppc_get_perf() API to read performance controls
> ACPI: CPPC: Warn on missing mandatory DESIRED_PERF register
> ACPI: CPPC: Extend cppc_set_epp_perf() for FFH/SystemMemory
> ACPI: CPPC: add APIs and sysfs interface for min/max_perf
> ACPI: CPPC: add APIs and sysfs interface for perf_limited
> cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited
> cpufreq: CPPC: Update cached perf_ctrls on sysfs write
>
> .../ABI/testing/sysfs-devices-system-cpu | 44 ++++
> drivers/acpi/cppc_acpi.c | 214 +++++++++++++++++-
> drivers/cpufreq/cppc_cpufreq.c | 207 ++++++++++++++++-
> include/acpi/cppc_acpi.h | 40 ++++
> 4 files changed, 500 insertions(+), 5 deletions(-)
>
> [1] https://lore.kernel.org/lkml/20250211103737.447704-1-sumitg@nvidia.com/
> [2] https://lore.kernel.org/lkml/20250823200121.1320197-1-sumitg@nvidia.com/
> [3] https://lore.kernel.org/lkml/20251001150104.1275188-1-sumitg@nvidia.com/
> [4] https://lore.kernel.org/lkml/20251105113844.4086250-1-sumitg@nvidia.com/
> [5] https://lore.kernel.org/lkml/20251223121307.711773-1-sumitg@nvidia.com/
> [6] https://lore.kernel.org/lkml/20260120145623.2959636-1-sumitg@nvidia.com/
> [7] https://lore.kernel.org/lkml/66f58f43-631b-40a0-8d42-4e90cd24b757@arm.com/
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-01-29 10:48 ` [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf Sumit Gupta
@ 2026-01-31 4:06 ` zhenglifeng (A)
2026-01-31 13:58 ` Sumit Gupta
2026-02-03 12:43 ` Rafael J. Wysocki
1 sibling, 1 reply; 26+ messages in thread
From: zhenglifeng (A) @ 2026-01-31 4:06 UTC (permalink / raw)
To: Sumit Gupta, pierre.gondois
Cc: rafael, viresh.kumar, ionela.voinescu, lenb, robert.moore, corbet,
rdunlap, ray.huang, gautham.shenoy, mario.limonciello, perry.yuan,
zhanjie9, linux-pm, linux-acpi, linux-doc, acpica-devel,
linux-kernel, linux-tegra, treding, jonathanh, vsethi, ksitaraman,
sanjayc, nhartman, bbasu
Hi Sumit,
I am thinking that maybe it is better to call these two sysfs interface
'min_freq' and 'max_freq' as users read and write khz instead of raw value.
On 2026/1/29 18:48, Sumit Gupta wrote:
> Add cppc_get/set_min_perf() and cppc_get/set_max_perf() APIs to read and
> write the MIN_PERF and MAX_PERF registers.
>
> Also add sysfs interfaces (min_perf, max_perf) in cppc_cpufreq driver
> to expose these controls to userspace. The sysfs values are in frequency
> (kHz) for consistency with other cpufreq sysfs files.
>
> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
> ---
> drivers/acpi/cppc_acpi.c | 44 +++++++++
> drivers/cpufreq/cppc_cpufreq.c | 165 +++++++++++++++++++++++++++++++++
> include/acpi/cppc_acpi.h | 20 ++++
> 3 files changed, 229 insertions(+)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 08e62b58eb83..b2b8daab69ed 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1753,6 +1753,50 @@ int cppc_set_auto_sel(int cpu, bool enable)
> }
> EXPORT_SYMBOL_GPL(cppc_set_auto_sel);
>
> +/**
> + * cppc_get_min_perf - Read minimum performance register.
> + * @cpu: CPU from which to read register.
> + * @min_perf: Return address.
> + */
> +int cppc_get_min_perf(int cpu, u64 *min_perf)
> +{
> + return cppc_get_reg_val(cpu, MIN_PERF, min_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_get_min_perf);
> +
> +/**
> + * cppc_set_min_perf - Write minimum performance register.
> + * @cpu: CPU to which to write register.
> + * @min_perf: the desired minimum performance value to be updated.
> + */
> +int cppc_set_min_perf(int cpu, u32 min_perf)
> +{
> + return cppc_set_reg_val(cpu, MIN_PERF, min_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_set_min_perf);
> +
> +/**
> + * cppc_get_max_perf - Read maximum performance register.
> + * @cpu: CPU from which to read register.
> + * @max_perf: Return address.
> + */
> +int cppc_get_max_perf(int cpu, u64 *max_perf)
> +{
> + return cppc_get_reg_val(cpu, MAX_PERF, max_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_get_max_perf);
> +
> +/**
> + * cppc_set_max_perf - Write maximum performance register.
> + * @cpu: CPU to which to write register.
> + * @max_perf: the desired maximum performance value to be updated.
> + */
> +int cppc_set_max_perf(int cpu, u32 max_perf)
> +{
> + return cppc_set_reg_val(cpu, MAX_PERF, max_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_set_max_perf);
> +
> /**
> * cppc_set_enable - Set to enable CPPC on the processor by writing the
> * Continuous Performance Control package EnableRegister field.
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index 1421f30e87e4..8787185cd8b0 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -570,6 +570,35 @@ static void populate_efficiency_class(void)
> }
> #endif
>
> +/* Set min/max performance HW register and cache the value */
> +static int cppc_cpufreq_set_mperf_reg(struct cpufreq_policy *policy,
> + u64 val, bool is_min)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
> + unsigned int cpu = policy->cpu;
> + u32 perf;
> + int ret;
> +
> + perf = clamp(val, caps->lowest_perf, caps->highest_perf);
> +
> + ret = is_min ? cppc_set_min_perf(cpu, perf) :
> + cppc_set_max_perf(cpu, perf);
> + if (ret) {
> + if (ret != -EOPNOTSUPP)
> + pr_warn("CPU%d: set %s_perf=%u failed (%d)\n",
> + cpu, is_min ? "min" : "max", perf, ret);
> + return ret;
> + }
> +
> + if (is_min)
> + cpu_data->perf_ctrls.min_perf = perf;
> + else
> + cpu_data->perf_ctrls.max_perf = perf;
> +
> + return 0;
> +}
> +
> static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu)
> {
> struct cppc_cpudata *cpu_data;
> @@ -919,16 +948,152 @@ CPPC_CPUFREQ_ATTR_RW_U64(auto_act_window, cppc_get_auto_act_window,
> CPPC_CPUFREQ_ATTR_RW_U64(energy_performance_preference_val,
> cppc_get_epp_perf, cppc_set_epp)
>
> +/**
> + * show_min_perf - Show minimum performance as frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer to write the frequency value to
> + *
> + * Reads the MIN_PERF register and converts the performance value to
> + * frequency (kHz).
> + */
> +static ssize_t show_min_perf(struct cpufreq_policy *policy, char *buf)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
> + u64 perf;
> + int ret;
> +
> + ret = cppc_get_min_perf(policy->cpu, &perf);
> + if (ret == -EOPNOTSUPP)
> + return sysfs_emit(buf, "<unsupported>\n");
> + if (ret)
> + return ret;
> +
> + /* Use lowest_perf if register is uninitialized or out of range */
> + if (perf == 0 || perf < caps->lowest_perf)
> + perf = caps->lowest_perf;
> +
> + /* Convert performance to frequency (kHz) for user */
> + return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
> +}
> +
> +/**
> + * store_min_perf - Set minimum performance from frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer containing the frequency value
> + * @count: size of @buf
> + *
> + * Converts the user-provided frequency (kHz) to a performance value
> + * and writes it to the MIN_PERF register.
> + */
> +static ssize_t store_min_perf(struct cpufreq_policy *policy, const char *buf,
> + size_t count)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + unsigned int freq_khz;
> + u64 perf;
> + int ret;
> +
> + ret = kstrtouint(buf, 0, &freq_khz);
> + if (ret)
> + return ret;
> +
> + /* Convert frequency (kHz) to performance value */
> + perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
> +
> + /*
> + * min_perf must be less than or equal to max_perf.
> + * Skip check if max_perf is 0 (uninitialized).
> + */
> + if (cpu_data->perf_ctrls.max_perf &&
> + perf > cpu_data->perf_ctrls.max_perf)
> + return -EINVAL;
> +
> + ret = cppc_cpufreq_set_mperf_reg(policy, perf, true);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> +/**
> + * show_max_perf - Show maximum performance as frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer to write the frequency value to
> + *
> + * Reads the MAX_PERF register and converts the performance value to
> + * frequency (kHz).
> + */
> +static ssize_t show_max_perf(struct cpufreq_policy *policy, char *buf)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
> + u64 perf;
> + int ret;
> +
> + ret = cppc_get_max_perf(policy->cpu, &perf);
> + if (ret == -EOPNOTSUPP)
> + return sysfs_emit(buf, "<unsupported>\n");
> + if (ret)
> + return ret;
> +
> + /* Use highest_perf if register is uninitialized or out of range */
> + if (perf == 0 || perf > caps->highest_perf)
> + perf = caps->highest_perf;
> +
> + /* Convert performance to frequency (kHz) for user */
> + return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
> +}
> +
> +/**
> + * store_max_perf - Set maximum performance from frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer containing the frequency value
> + * @count: size of @buf
> + *
> + * Converts the user-provided frequency (kHz) to a performance value
> + * and writes it to the MAX_PERF register.
> + */
> +static ssize_t store_max_perf(struct cpufreq_policy *policy, const char *buf,
> + size_t count)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + unsigned int freq_khz;
> + u64 perf;
> + int ret;
> +
> + ret = kstrtouint(buf, 0, &freq_khz);
> + if (ret)
> + return ret;
> +
> + /* Convert frequency (kHz) to performance value */
> + perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
> +
> + /* max_perf must be greater than or equal to min_perf */
> + if (perf < cpu_data->perf_ctrls.min_perf)
> + return -EINVAL;
> +
> + ret = cppc_cpufreq_set_mperf_reg(policy, perf, false);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> cpufreq_freq_attr_ro(freqdomain_cpus);
> cpufreq_freq_attr_rw(auto_select);
> cpufreq_freq_attr_rw(auto_act_window);
> cpufreq_freq_attr_rw(energy_performance_preference_val);
> +cpufreq_freq_attr_rw(min_perf);
> +cpufreq_freq_attr_rw(max_perf);
>
> static struct freq_attr *cppc_cpufreq_attr[] = {
> &freqdomain_cpus,
> &auto_select,
> &auto_act_window,
> &energy_performance_preference_val,
> + &min_perf,
> + &max_perf,
> NULL,
> };
>
> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
> index 3fc796c0d902..b358440cd0e2 100644
> --- a/include/acpi/cppc_acpi.h
> +++ b/include/acpi/cppc_acpi.h
> @@ -174,6 +174,10 @@ 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 cppc_get_min_perf(int cpu, u64 *min_perf);
> +extern int cppc_set_min_perf(int cpu, u32 min_perf);
> +extern int cppc_get_max_perf(int cpu, u64 *max_perf);
> +extern int cppc_set_max_perf(int cpu, u32 max_perf);
> extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
> extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
> extern int amd_detect_prefcore(bool *detected);
> @@ -270,6 +274,22 @@ static inline int cppc_set_auto_sel(int cpu, bool enable)
> {
> return -EOPNOTSUPP;
> }
> +static inline int cppc_get_min_perf(int cpu, u64 *min_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_set_min_perf(int cpu, u32 min_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_get_max_perf(int cpu, u64 *max_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_set_max_perf(int cpu, u32 max_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
> {
> return -ENODEV;
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-01-31 4:06 ` zhenglifeng (A)
@ 2026-01-31 13:58 ` Sumit Gupta
2026-02-03 1:36 ` Russell Haley
0 siblings, 1 reply; 26+ messages in thread
From: Sumit Gupta @ 2026-01-31 13:58 UTC (permalink / raw)
To: zhenglifeng (A), pierre.gondois
Cc: rafael, viresh.kumar, ionela.voinescu, lenb, robert.moore, corbet,
rdunlap, ray.huang, gautham.shenoy, mario.limonciello, perry.yuan,
zhanjie9, linux-pm, linux-acpi, linux-doc, acpica-devel,
linux-kernel, linux-tegra, treding, jonathanh, vsethi, ksitaraman,
sanjayc, nhartman, bbasu, sumitg
On 31/01/26 09:36, zhenglifeng (A) wrote:
> External email: Use caution opening links or attachments
>
>
> Hi Sumit,
>
> I am thinking that maybe it is better to call these two sysfs interface
> 'min_freq' and 'max_freq' as users read and write khz instead of raw value.
Thanks for the suggestion.
Kept min_perf/max_perf to match the CPPC register names
(MIN_PERF/MAX_PERF), making it clear to users familiar with
CPPC what's being controlled.
The kHz unit is documented in the ABI.
Thank you,
Sumit Gupta
>
> On 2026/1/29 18:48, Sumit Gupta wrote:
>> Add cppc_get/set_min_perf() and cppc_get/set_max_perf() APIs to read and
>> write the MIN_PERF and MAX_PERF registers.
>>
>> Also add sysfs interfaces (min_perf, max_perf) in cppc_cpufreq driver
>> to expose these controls to userspace. The sysfs values are in frequency
>> (kHz) for consistency with other cpufreq sysfs files.
>>
>> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
>> ---
>> drivers/acpi/cppc_acpi.c | 44 +++++++++
>> drivers/cpufreq/cppc_cpufreq.c | 165 +++++++++++++++++++++++++++++++++
>> include/acpi/cppc_acpi.h | 20 ++++
>> 3 files changed, 229 insertions(+)
>>
>> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
>> index 08e62b58eb83..b2b8daab69ed 100644
>> --- a/drivers/acpi/cppc_acpi.c
>> +++ b/drivers/acpi/cppc_acpi.c
>> @@ -1753,6 +1753,50 @@ int cppc_set_auto_sel(int cpu, bool enable)
>> }
>> EXPORT_SYMBOL_GPL(cppc_set_auto_sel);
>>
>> +/**
>> + * cppc_get_min_perf - Read minimum performance register.
>> + * @cpu: CPU from which to read register.
>> + * @min_perf: Return address.
>> + */
>> +int cppc_get_min_perf(int cpu, u64 *min_perf)
>> +{
>> + return cppc_get_reg_val(cpu, MIN_PERF, min_perf);
>> +}
>> +EXPORT_SYMBOL_GPL(cppc_get_min_perf);
>> +
>> +/**
>> + * cppc_set_min_perf - Write minimum performance register.
>> + * @cpu: CPU to which to write register.
>> + * @min_perf: the desired minimum performance value to be updated.
>> + */
>> +int cppc_set_min_perf(int cpu, u32 min_perf)
>> +{
>> + return cppc_set_reg_val(cpu, MIN_PERF, min_perf);
>> +}
>> +EXPORT_SYMBOL_GPL(cppc_set_min_perf);
>> +
>> +/**
>> + * cppc_get_max_perf - Read maximum performance register.
>> + * @cpu: CPU from which to read register.
>> + * @max_perf: Return address.
>> + */
>> +int cppc_get_max_perf(int cpu, u64 *max_perf)
>> +{
>> + return cppc_get_reg_val(cpu, MAX_PERF, max_perf);
>> +}
>> +EXPORT_SYMBOL_GPL(cppc_get_max_perf);
>> +
>> +/**
>> + * cppc_set_max_perf - Write maximum performance register.
>> + * @cpu: CPU to which to write register.
>> + * @max_perf: the desired maximum performance value to be updated.
>> + */
>> +int cppc_set_max_perf(int cpu, u32 max_perf)
>> +{
>> + return cppc_set_reg_val(cpu, MAX_PERF, max_perf);
>> +}
>> +EXPORT_SYMBOL_GPL(cppc_set_max_perf);
>> +
>> /**
>> * cppc_set_enable - Set to enable CPPC on the processor by writing the
>> * Continuous Performance Control package EnableRegister field.
>> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
>> index 1421f30e87e4..8787185cd8b0 100644
>> --- a/drivers/cpufreq/cppc_cpufreq.c
>> +++ b/drivers/cpufreq/cppc_cpufreq.c
>> @@ -570,6 +570,35 @@ static void populate_efficiency_class(void)
>> }
>> #endif
>>
>> +/* Set min/max performance HW register and cache the value */
>> +static int cppc_cpufreq_set_mperf_reg(struct cpufreq_policy *policy,
>> + u64 val, bool is_min)
>> +{
>> + struct cppc_cpudata *cpu_data = policy->driver_data;
>> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
>> + unsigned int cpu = policy->cpu;
>> + u32 perf;
>> + int ret;
>> +
>> + perf = clamp(val, caps->lowest_perf, caps->highest_perf);
>> +
>> + ret = is_min ? cppc_set_min_perf(cpu, perf) :
>> + cppc_set_max_perf(cpu, perf);
>> + if (ret) {
>> + if (ret != -EOPNOTSUPP)
>> + pr_warn("CPU%d: set %s_perf=%u failed (%d)\n",
>> + cpu, is_min ? "min" : "max", perf, ret);
>> + return ret;
>> + }
>> +
>> + if (is_min)
>> + cpu_data->perf_ctrls.min_perf = perf;
>> + else
>> + cpu_data->perf_ctrls.max_perf = perf;
>> +
>> + return 0;
>> +}
>> +
>> static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu)
>> {
>> struct cppc_cpudata *cpu_data;
>> @@ -919,16 +948,152 @@ CPPC_CPUFREQ_ATTR_RW_U64(auto_act_window, cppc_get_auto_act_window,
>> CPPC_CPUFREQ_ATTR_RW_U64(energy_performance_preference_val,
>> cppc_get_epp_perf, cppc_set_epp)
>>
>> +/**
>> + * show_min_perf - Show minimum performance as frequency (kHz)
>> + * @policy: cpufreq policy
>> + * @buf: buffer to write the frequency value to
>> + *
>> + * Reads the MIN_PERF register and converts the performance value to
>> + * frequency (kHz).
>> + */
>> +static ssize_t show_min_perf(struct cpufreq_policy *policy, char *buf)
>> +{
>> + struct cppc_cpudata *cpu_data = policy->driver_data;
>> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
>> + u64 perf;
>> + int ret;
>> +
>> + ret = cppc_get_min_perf(policy->cpu, &perf);
>> + if (ret == -EOPNOTSUPP)
>> + return sysfs_emit(buf, "<unsupported>\n");
>> + if (ret)
>> + return ret;
>> +
>> + /* Use lowest_perf if register is uninitialized or out of range */
>> + if (perf == 0 || perf < caps->lowest_perf)
>> + perf = caps->lowest_perf;
>> +
>> + /* Convert performance to frequency (kHz) for user */
>> + return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
>> +}
>> +
>> +/**
>> + * store_min_perf - Set minimum performance from frequency (kHz)
>> + * @policy: cpufreq policy
>> + * @buf: buffer containing the frequency value
>> + * @count: size of @buf
>> + *
>> + * Converts the user-provided frequency (kHz) to a performance value
>> + * and writes it to the MIN_PERF register.
>> + */
>> +static ssize_t store_min_perf(struct cpufreq_policy *policy, const char *buf,
>> + size_t count)
>> +{
>> + struct cppc_cpudata *cpu_data = policy->driver_data;
>> + unsigned int freq_khz;
>> + u64 perf;
>> + int ret;
>> +
>> + ret = kstrtouint(buf, 0, &freq_khz);
>> + if (ret)
>> + return ret;
>> +
>> + /* Convert frequency (kHz) to performance value */
>> + perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
>> +
>> + /*
>> + * min_perf must be less than or equal to max_perf.
>> + * Skip check if max_perf is 0 (uninitialized).
>> + */
>> + if (cpu_data->perf_ctrls.max_perf &&
>> + perf > cpu_data->perf_ctrls.max_perf)
>> + return -EINVAL;
>> +
>> + ret = cppc_cpufreq_set_mperf_reg(policy, perf, true);
>> + if (ret)
>> + return ret;
>> +
>> + return count;
>> +}
>> +
>> +/**
>> + * show_max_perf - Show maximum performance as frequency (kHz)
>> + * @policy: cpufreq policy
>> + * @buf: buffer to write the frequency value to
>> + *
>> + * Reads the MAX_PERF register and converts the performance value to
>> + * frequency (kHz).
>> + */
>> +static ssize_t show_max_perf(struct cpufreq_policy *policy, char *buf)
>> +{
>> + struct cppc_cpudata *cpu_data = policy->driver_data;
>> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
>> + u64 perf;
>> + int ret;
>> +
>> + ret = cppc_get_max_perf(policy->cpu, &perf);
>> + if (ret == -EOPNOTSUPP)
>> + return sysfs_emit(buf, "<unsupported>\n");
>> + if (ret)
>> + return ret;
>> +
>> + /* Use highest_perf if register is uninitialized or out of range */
>> + if (perf == 0 || perf > caps->highest_perf)
>> + perf = caps->highest_perf;
>> +
>> + /* Convert performance to frequency (kHz) for user */
>> + return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
>> +}
>> +
>> +/**
>> + * store_max_perf - Set maximum performance from frequency (kHz)
>> + * @policy: cpufreq policy
>> + * @buf: buffer containing the frequency value
>> + * @count: size of @buf
>> + *
>> + * Converts the user-provided frequency (kHz) to a performance value
>> + * and writes it to the MAX_PERF register.
>> + */
>> +static ssize_t store_max_perf(struct cpufreq_policy *policy, const char *buf,
>> + size_t count)
>> +{
>> + struct cppc_cpudata *cpu_data = policy->driver_data;
>> + unsigned int freq_khz;
>> + u64 perf;
>> + int ret;
>> +
>> + ret = kstrtouint(buf, 0, &freq_khz);
>> + if (ret)
>> + return ret;
>> +
>> + /* Convert frequency (kHz) to performance value */
>> + perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
>> +
>> + /* max_perf must be greater than or equal to min_perf */
>> + if (perf < cpu_data->perf_ctrls.min_perf)
>> + return -EINVAL;
>> +
>> + ret = cppc_cpufreq_set_mperf_reg(policy, perf, false);
>> + if (ret)
>> + return ret;
>> +
>> + return count;
>> +}
>> +
>> cpufreq_freq_attr_ro(freqdomain_cpus);
>> cpufreq_freq_attr_rw(auto_select);
>> cpufreq_freq_attr_rw(auto_act_window);
>> cpufreq_freq_attr_rw(energy_performance_preference_val);
>> +cpufreq_freq_attr_rw(min_perf);
>> +cpufreq_freq_attr_rw(max_perf);
>>
>> static struct freq_attr *cppc_cpufreq_attr[] = {
>> &freqdomain_cpus,
>> &auto_select,
>> &auto_act_window,
>> &energy_performance_preference_val,
>> + &min_perf,
>> + &max_perf,
>> NULL,
>> };
>>
>> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
>> index 3fc796c0d902..b358440cd0e2 100644
>> --- a/include/acpi/cppc_acpi.h
>> +++ b/include/acpi/cppc_acpi.h
>> @@ -174,6 +174,10 @@ 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 cppc_get_min_perf(int cpu, u64 *min_perf);
>> +extern int cppc_set_min_perf(int cpu, u32 min_perf);
>> +extern int cppc_get_max_perf(int cpu, u64 *max_perf);
>> +extern int cppc_set_max_perf(int cpu, u32 max_perf);
>> extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
>> extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
>> extern int amd_detect_prefcore(bool *detected);
>> @@ -270,6 +274,22 @@ static inline int cppc_set_auto_sel(int cpu, bool enable)
>> {
>> return -EOPNOTSUPP;
>> }
>> +static inline int cppc_get_min_perf(int cpu, u64 *min_perf)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> +static inline int cppc_set_min_perf(int cpu, u32 min_perf)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> +static inline int cppc_get_max_perf(int cpu, u64 *max_perf)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> +static inline int cppc_set_max_perf(int cpu, u32 max_perf)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
>> {
>> return -ENODEV;
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-01-31 13:58 ` Sumit Gupta
@ 2026-02-03 1:36 ` Russell Haley
2026-02-03 9:41 ` Sumit Gupta
0 siblings, 1 reply; 26+ messages in thread
From: Russell Haley @ 2026-02-03 1:36 UTC (permalink / raw)
To: Sumit Gupta, zhenglifeng (A), pierre.gondois
Cc: rafael, viresh.kumar, ionela.voinescu, lenb, robert.moore, corbet,
rdunlap, ray.huang, gautham.shenoy, mario.limonciello, perry.yuan,
zhanjie9, linux-pm, linux-acpi, linux-doc, acpica-devel,
linux-kernel, linux-tegra, treding, jonathanh, vsethi, ksitaraman,
sanjayc, nhartman, bbasu
On 1/31/26 7:58 AM, Sumit Gupta wrote:
>
> On 31/01/26 09:36, zhenglifeng (A) wrote:
>> External email: Use caution opening links or attachments
>>
>>
>> Hi Sumit,
>>
>> I am thinking that maybe it is better to call these two sysfs interface
>> 'min_freq' and 'max_freq' as users read and write khz instead of raw
>> value.
>
> Thanks for the suggestion.
> Kept min_perf/max_perf to match the CPPC register names
> (MIN_PERF/MAX_PERF), making it clear to users familiar with
> CPPC what's being controlled.
> The kHz unit is documented in the ABI.
>
> Thank you,
> Sumit Gupta
On my x86 machine with kernel 6.18.5, the kernel is exposing raw values:
> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
/sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
del:437439724183386
/sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
/sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
/sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
/sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
/sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
/sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
/sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
/sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
/sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
It would be surprising for a nearby sysfs interface with very similar
names to use kHz instead.
Thanks,
Russell Haley
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 1:36 ` Russell Haley
@ 2026-02-03 9:41 ` Sumit Gupta
2026-02-03 12:45 ` Rafael J. Wysocki
0 siblings, 1 reply; 26+ messages in thread
From: Sumit Gupta @ 2026-02-03 9:41 UTC (permalink / raw)
To: Russell Haley, zhenglifeng (A), pierre.gondois, Rafael J. Wysocki
Cc: rafael, viresh.kumar, ionela.voinescu, lenb, robert.moore, corbet,
rdunlap, ray.huang, gautham.shenoy, mario.limonciello, perry.yuan,
zhanjie9, linux-pm, linux-acpi, linux-doc, acpica-devel,
linux-kernel, linux-tegra, treding, jonathanh, vsethi, ksitaraman,
sanjayc, nhartman, bbasu, sumitg
>>> Hi Sumit,
>>>
>>> I am thinking that maybe it is better to call these two sysfs interface
>>> 'min_freq' and 'max_freq' as users read and write khz instead of raw
>>> value.
>> Thanks for the suggestion.
>> Kept min_perf/max_perf to match the CPPC register names
>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
>> CPPC what's being controlled.
>> The kHz unit is documented in the ABI.
>>
>> Thank you,
>> Sumit Gupta
> On my x86 machine with kernel 6.18.5, the kernel is exposing raw values:
>
>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
> del:437439724183386
> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
>
> It would be surprising for a nearby sysfs interface with very similar
> names to use kHz instead.
>
> Thanks,
>
> Russell Haley
I can rename to either of the below:
- min/max_freq: might be confused with scaling_min/max_freq.
- min/max_perf_freq: keeps the CPPC register association clear.
Rafael, Any preferences here?
Thank you,
Sumit Gupta
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-01-29 10:48 ` [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf Sumit Gupta
2026-01-31 4:06 ` zhenglifeng (A)
@ 2026-02-03 12:43 ` Rafael J. Wysocki
2026-02-03 12:50 ` Rafael J. Wysocki
2026-02-05 13:10 ` Artem Bityutskiy
1 sibling, 2 replies; 26+ messages in thread
From: Rafael J. Wysocki @ 2026-02-03 12:43 UTC (permalink / raw)
To: Sumit Gupta
Cc: rafael, viresh.kumar, pierre.gondois, zhenglifeng1,
ionela.voinescu, lenb, robert.moore, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel, linux-tegra,
treding, jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu
On Thu, Jan 29, 2026 at 11:49 AM Sumit Gupta <sumitg@nvidia.com> wrote:
>
> Add cppc_get/set_min_perf() and cppc_get/set_max_perf() APIs to read and
> write the MIN_PERF and MAX_PERF registers.
>
> Also add sysfs interfaces (min_perf, max_perf) in cppc_cpufreq driver
> to expose these controls to userspace. The sysfs values are in frequency
> (kHz) for consistency with other cpufreq sysfs files.
But this is not cpufreq and it is not consistent.
> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
> ---
> drivers/acpi/cppc_acpi.c | 44 +++++++++
> drivers/cpufreq/cppc_cpufreq.c | 165 +++++++++++++++++++++++++++++++++
> include/acpi/cppc_acpi.h | 20 ++++
> 3 files changed, 229 insertions(+)
>
> diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
> index 08e62b58eb83..b2b8daab69ed 100644
> --- a/drivers/acpi/cppc_acpi.c
> +++ b/drivers/acpi/cppc_acpi.c
> @@ -1753,6 +1753,50 @@ int cppc_set_auto_sel(int cpu, bool enable)
> }
> EXPORT_SYMBOL_GPL(cppc_set_auto_sel);
>
> +/**
> + * cppc_get_min_perf - Read minimum performance register.
> + * @cpu: CPU from which to read register.
> + * @min_perf: Return address.
> + */
> +int cppc_get_min_perf(int cpu, u64 *min_perf)
> +{
> + return cppc_get_reg_val(cpu, MIN_PERF, min_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_get_min_perf);
> +
> +/**
> + * cppc_set_min_perf - Write minimum performance register.
> + * @cpu: CPU to which to write register.
> + * @min_perf: the desired minimum performance value to be updated.
> + */
> +int cppc_set_min_perf(int cpu, u32 min_perf)
> +{
> + return cppc_set_reg_val(cpu, MIN_PERF, min_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_set_min_perf);
> +
> +/**
> + * cppc_get_max_perf - Read maximum performance register.
> + * @cpu: CPU from which to read register.
> + * @max_perf: Return address.
> + */
> +int cppc_get_max_perf(int cpu, u64 *max_perf)
> +{
> + return cppc_get_reg_val(cpu, MAX_PERF, max_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_get_max_perf);
> +
> +/**
> + * cppc_set_max_perf - Write maximum performance register.
> + * @cpu: CPU to which to write register.
> + * @max_perf: the desired maximum performance value to be updated.
> + */
> +int cppc_set_max_perf(int cpu, u32 max_perf)
> +{
> + return cppc_set_reg_val(cpu, MAX_PERF, max_perf);
> +}
> +EXPORT_SYMBOL_GPL(cppc_set_max_perf);
> +
> /**
> * cppc_set_enable - Set to enable CPPC on the processor by writing the
> * Continuous Performance Control package EnableRegister field.
> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
> index 1421f30e87e4..8787185cd8b0 100644
> --- a/drivers/cpufreq/cppc_cpufreq.c
> +++ b/drivers/cpufreq/cppc_cpufreq.c
> @@ -570,6 +570,35 @@ static void populate_efficiency_class(void)
> }
> #endif
>
> +/* Set min/max performance HW register and cache the value */
> +static int cppc_cpufreq_set_mperf_reg(struct cpufreq_policy *policy,
> + u64 val, bool is_min)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
> + unsigned int cpu = policy->cpu;
> + u32 perf;
> + int ret;
> +
> + perf = clamp(val, caps->lowest_perf, caps->highest_perf);
> +
> + ret = is_min ? cppc_set_min_perf(cpu, perf) :
> + cppc_set_max_perf(cpu, perf);
> + if (ret) {
> + if (ret != -EOPNOTSUPP)
> + pr_warn("CPU%d: set %s_perf=%u failed (%d)\n",
> + cpu, is_min ? "min" : "max", perf, ret);
> + return ret;
> + }
> +
> + if (is_min)
> + cpu_data->perf_ctrls.min_perf = perf;
> + else
> + cpu_data->perf_ctrls.max_perf = perf;
> +
> + return 0;
> +}
> +
> static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu)
> {
> struct cppc_cpudata *cpu_data;
> @@ -919,16 +948,152 @@ CPPC_CPUFREQ_ATTR_RW_U64(auto_act_window, cppc_get_auto_act_window,
> CPPC_CPUFREQ_ATTR_RW_U64(energy_performance_preference_val,
> cppc_get_epp_perf, cppc_set_epp)
>
> +/**
> + * show_min_perf - Show minimum performance as frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer to write the frequency value to
> + *
> + * Reads the MIN_PERF register and converts the performance value to
> + * frequency (kHz).
> + */
> +static ssize_t show_min_perf(struct cpufreq_policy *policy, char *buf)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
> + u64 perf;
> + int ret;
> +
> + ret = cppc_get_min_perf(policy->cpu, &perf);
> + if (ret == -EOPNOTSUPP)
> + return sysfs_emit(buf, "<unsupported>\n");
> + if (ret)
> + return ret;
> +
> + /* Use lowest_perf if register is uninitialized or out of range */
> + if (perf == 0 || perf < caps->lowest_perf)
> + perf = caps->lowest_perf;
> +
> + /* Convert performance to frequency (kHz) for user */
> + return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
> +}
> +
> +/**
> + * store_min_perf - Set minimum performance from frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer containing the frequency value
> + * @count: size of @buf
> + *
> + * Converts the user-provided frequency (kHz) to a performance value
> + * and writes it to the MIN_PERF register.
> + */
> +static ssize_t store_min_perf(struct cpufreq_policy *policy, const char *buf,
> + size_t count)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + unsigned int freq_khz;
> + u64 perf;
> + int ret;
> +
> + ret = kstrtouint(buf, 0, &freq_khz);
> + if (ret)
> + return ret;
> +
> + /* Convert frequency (kHz) to performance value */
> + perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
> +
> + /*
> + * min_perf must be less than or equal to max_perf.
> + * Skip check if max_perf is 0 (uninitialized).
> + */
> + if (cpu_data->perf_ctrls.max_perf &&
> + perf > cpu_data->perf_ctrls.max_perf)
> + return -EINVAL;
> +
> + ret = cppc_cpufreq_set_mperf_reg(policy, perf, true);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> +/**
> + * show_max_perf - Show maximum performance as frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer to write the frequency value to
> + *
> + * Reads the MAX_PERF register and converts the performance value to
> + * frequency (kHz).
> + */
> +static ssize_t show_max_perf(struct cpufreq_policy *policy, char *buf)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + struct cppc_perf_caps *caps = &cpu_data->perf_caps;
> + u64 perf;
> + int ret;
> +
> + ret = cppc_get_max_perf(policy->cpu, &perf);
> + if (ret == -EOPNOTSUPP)
> + return sysfs_emit(buf, "<unsupported>\n");
> + if (ret)
> + return ret;
> +
> + /* Use highest_perf if register is uninitialized or out of range */
> + if (perf == 0 || perf > caps->highest_perf)
> + perf = caps->highest_perf;
> +
> + /* Convert performance to frequency (kHz) for user */
> + return sysfs_emit(buf, "%u\n", cppc_perf_to_khz(caps, perf));
> +}
> +
> +/**
> + * store_max_perf - Set maximum performance from frequency (kHz)
> + * @policy: cpufreq policy
> + * @buf: buffer containing the frequency value
> + * @count: size of @buf
> + *
> + * Converts the user-provided frequency (kHz) to a performance value
> + * and writes it to the MAX_PERF register.
> + */
> +static ssize_t store_max_perf(struct cpufreq_policy *policy, const char *buf,
> + size_t count)
> +{
> + struct cppc_cpudata *cpu_data = policy->driver_data;
> + unsigned int freq_khz;
> + u64 perf;
> + int ret;
> +
> + ret = kstrtouint(buf, 0, &freq_khz);
> + if (ret)
> + return ret;
> +
> + /* Convert frequency (kHz) to performance value */
> + perf = cppc_khz_to_perf(&cpu_data->perf_caps, freq_khz);
> +
> + /* max_perf must be greater than or equal to min_perf */
> + if (perf < cpu_data->perf_ctrls.min_perf)
> + return -EINVAL;
> +
> + ret = cppc_cpufreq_set_mperf_reg(policy, perf, false);
> + if (ret)
> + return ret;
> +
> + return count;
> +}
> +
> cpufreq_freq_attr_ro(freqdomain_cpus);
> cpufreq_freq_attr_rw(auto_select);
> cpufreq_freq_attr_rw(auto_act_window);
> cpufreq_freq_attr_rw(energy_performance_preference_val);
> +cpufreq_freq_attr_rw(min_perf);
> +cpufreq_freq_attr_rw(max_perf);
>
> static struct freq_attr *cppc_cpufreq_attr[] = {
> &freqdomain_cpus,
> &auto_select,
> &auto_act_window,
> &energy_performance_preference_val,
> + &min_perf,
> + &max_perf,
> NULL,
> };
>
> diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
> index 3fc796c0d902..b358440cd0e2 100644
> --- a/include/acpi/cppc_acpi.h
> +++ b/include/acpi/cppc_acpi.h
> @@ -174,6 +174,10 @@ 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 cppc_get_min_perf(int cpu, u64 *min_perf);
> +extern int cppc_set_min_perf(int cpu, u32 min_perf);
> +extern int cppc_get_max_perf(int cpu, u64 *max_perf);
> +extern int cppc_set_max_perf(int cpu, u32 max_perf);
> extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
> extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
> extern int amd_detect_prefcore(bool *detected);
> @@ -270,6 +274,22 @@ static inline int cppc_set_auto_sel(int cpu, bool enable)
> {
> return -EOPNOTSUPP;
> }
> +static inline int cppc_get_min_perf(int cpu, u64 *min_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_set_min_perf(int cpu, u32 min_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_get_max_perf(int cpu, u64 *max_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int cppc_set_max_perf(int cpu, u32 max_perf)
> +{
> + return -EOPNOTSUPP;
> +}
> static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
> {
> return -ENODEV;
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 9:41 ` Sumit Gupta
@ 2026-02-03 12:45 ` Rafael J. Wysocki
2026-02-03 12:54 ` Rafael J. Wysocki
0 siblings, 1 reply; 26+ messages in thread
From: Rafael J. Wysocki @ 2026-02-03 12:45 UTC (permalink / raw)
To: Sumit Gupta
Cc: Russell Haley, zhenglifeng (A), pierre.gondois, Rafael J. Wysocki,
viresh.kumar, ionela.voinescu, lenb, robert.moore, corbet,
rdunlap, ray.huang, gautham.shenoy, mario.limonciello, perry.yuan,
zhanjie9, linux-pm, linux-acpi, linux-doc, acpica-devel,
linux-kernel, linux-tegra, treding, jonathanh, vsethi, ksitaraman,
sanjayc, nhartman, bbasu
On Tue, Feb 3, 2026 at 10:41 AM Sumit Gupta <sumitg@nvidia.com> wrote:
>
> >>> Hi Sumit,
> >>>
> >>> I am thinking that maybe it is better to call these two sysfs interface
> >>> 'min_freq' and 'max_freq' as users read and write khz instead of raw
> >>> value.
> >> Thanks for the suggestion.
> >> Kept min_perf/max_perf to match the CPPC register names
> >> (MIN_PERF/MAX_PERF), making it clear to users familiar with
> >> CPPC what's being controlled.
> >> The kHz unit is documented in the ABI.
> >>
> >> Thank you,
> >> Sumit Gupta
> > On my x86 machine with kernel 6.18.5, the kernel is exposing raw values:
> >
> >> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
> > /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
> > del:437439724183386
> > /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
> > /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
> > /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
> > /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
> > /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
> > /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
> > /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
> > /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
> > /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
> >
> > It would be surprising for a nearby sysfs interface with very similar
> > names to use kHz instead.
> >
> > Thanks,
> >
> > Russell Haley
>
> I can rename to either of the below:
> - min/max_freq: might be confused with scaling_min/max_freq.
> - min/max_perf_freq: keeps the CPPC register association clear.
>
> Rafael, Any preferences here?
On x86 the units in CPPC are not kHz and there is no easy reliable way
to convert them to kHz.
Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
in CPPC units, not kHz (unless, of course, kHz are CPPC units).
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 12:43 ` Rafael J. Wysocki
@ 2026-02-03 12:50 ` Rafael J. Wysocki
2026-02-05 13:10 ` Artem Bityutskiy
1 sibling, 0 replies; 26+ messages in thread
From: Rafael J. Wysocki @ 2026-02-03 12:50 UTC (permalink / raw)
To: Sumit Gupta
Cc: viresh.kumar, pierre.gondois, zhenglifeng1, ionela.voinescu, lenb,
robert.moore, corbet, rdunlap, ray.huang, gautham.shenoy,
mario.limonciello, perry.yuan, zhanjie9, linux-pm, linux-acpi,
linux-doc, acpica-devel, linux-kernel, linux-tegra, treding,
jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu
On Tue, Feb 3, 2026 at 1:43 PM Rafael J. Wysocki <rafael@kernel.org> wrote:
>
> On Thu, Jan 29, 2026 at 11:49 AM Sumit Gupta <sumitg@nvidia.com> wrote:
> >
> > Add cppc_get/set_min_perf() and cppc_get/set_max_perf() APIs to read and
> > write the MIN_PERF and MAX_PERF registers.
> >
> > Also add sysfs interfaces (min_perf, max_perf) in cppc_cpufreq driver
> > to expose these controls to userspace. The sysfs values are in frequency
> > (kHz) for consistency with other cpufreq sysfs files.
>
> But this is not cpufreq and it is not consistent.
Scratch this, sorry for the noise.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 12:45 ` Rafael J. Wysocki
@ 2026-02-03 12:54 ` Rafael J. Wysocki
2026-02-03 14:31 ` Sumit Gupta
0 siblings, 1 reply; 26+ messages in thread
From: Rafael J. Wysocki @ 2026-02-03 12:54 UTC (permalink / raw)
To: Sumit Gupta
Cc: Russell Haley, zhenglifeng (A), pierre.gondois, viresh.kumar,
ionela.voinescu, corbet, rdunlap, ray.huang, gautham.shenoy,
mario.limonciello, perry.yuan, zhanjie9, linux-pm, linux-acpi,
linux-doc, acpica-devel, linux-kernel, linux-tegra, treding,
jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu
On Tue, Feb 3, 2026 at 1:45 PM Rafael J. Wysocki <rafael@kernel.org> wrote:
>
> On Tue, Feb 3, 2026 at 10:41 AM Sumit Gupta <sumitg@nvidia.com> wrote:
> >
> > >>> Hi Sumit,
> > >>>
> > >>> I am thinking that maybe it is better to call these two sysfs interface
> > >>> 'min_freq' and 'max_freq' as users read and write khz instead of raw
> > >>> value.
> > >> Thanks for the suggestion.
> > >> Kept min_perf/max_perf to match the CPPC register names
> > >> (MIN_PERF/MAX_PERF), making it clear to users familiar with
> > >> CPPC what's being controlled.
> > >> The kHz unit is documented in the ABI.
> > >>
> > >> Thank you,
> > >> Sumit Gupta
> > > On my x86 machine with kernel 6.18.5, the kernel is exposing raw values:
> > >
> > >> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
> > > del:437439724183386
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
> > > /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
> > >
> > > It would be surprising for a nearby sysfs interface with very similar
> > > names to use kHz instead.
> > >
> > > Thanks,
> > >
> > > Russell Haley
> >
> > I can rename to either of the below:
> > - min/max_freq: might be confused with scaling_min/max_freq.
> > - min/max_perf_freq: keeps the CPPC register association clear.
> >
> > Rafael, Any preferences here?
>
> On x86 the units in CPPC are not kHz and there is no easy reliable way
> to convert them to kHz.
>
> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
That said, the new attributes will show up elsewhere.
So why do you need to add these things in the first place?
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 12:54 ` Rafael J. Wysocki
@ 2026-02-03 14:31 ` Sumit Gupta
2026-02-03 20:24 ` Rafael J. Wysocki
0 siblings, 1 reply; 26+ messages in thread
From: Sumit Gupta @ 2026-02-03 14:31 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Russell Haley, zhenglifeng (A), pierre.gondois, viresh.kumar,
ionela.voinescu, corbet, rdunlap, ray.huang, gautham.shenoy,
mario.limonciello, perry.yuan, zhanjie9, linux-pm, linux-acpi,
linux-doc, acpica-devel, linux-kernel, linux-tegra, treding,
jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu, sumitg
On 03/02/26 18:24, Rafael J. Wysocki wrote:
> External email: Use caution opening links or attachments
>
>
> On Tue, Feb 3, 2026 at 1:45 PM Rafael J. Wysocki <rafael@kernel.org> wrote:
>> On Tue, Feb 3, 2026 at 10:41 AM Sumit Gupta <sumitg@nvidia.com> wrote:
>>>>>> Hi Sumit,
>>>>>>
>>>>>> I am thinking that maybe it is better to call these two sysfs interface
>>>>>> 'min_freq' and 'max_freq' as users read and write khz instead of raw
>>>>>> value.
>>>>> Thanks for the suggestion.
>>>>> Kept min_perf/max_perf to match the CPPC register names
>>>>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
>>>>> CPPC what's being controlled.
>>>>> The kHz unit is documented in the ABI.
>>>>>
>>>>> Thank you,
>>>>> Sumit Gupta
>>>> On my x86 machine with kernel 6.18.5, the kernel is exposing raw values:
>>>>
>>>>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
>>>> del:437439724183386
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
>>>>
>>>> It would be surprising for a nearby sysfs interface with very similar
>>>> names to use kHz instead.
>>>>
>>>> Thanks,
>>>>
>>>> Russell Haley
>>> I can rename to either of the below:
>>> - min/max_freq: might be confused with scaling_min/max_freq.
>>> - min/max_perf_freq: keeps the CPPC register association clear.
>>>
>>> Rafael, Any preferences here?
>> On x86 the units in CPPC are not kHz and there is no easy reliable way
>> to convert them to kHz.
>>
>> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
>> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
In v1 [1], these controls were added under acpi_cppc sysfs.
After discussion, they were moved under cpufreq, and [2] was merged first.
The decision to use frequency scale instead of raw perf was made
for consistency with other cpufreq interfaces as per (v3 [3]).
CPPC units in our case are also not in kHz. The kHz conversion uses the
existing cppc_perf_to_khz()/cppc_khz_to_perf() helpers which are already
used in cppc_cpufreq attributes. So the conversion behavior is consistent
with existing cpufreq interfaces.
[1]
https://lore.kernel.org/lkml/076c199c-a081-4a7f-956c-f395f4d5e156@nvidia.com/
[2]
https://lore.kernel.org/all/20250507031941.2812701-1-zhenglifeng1@huawei.com/
[3]
https://lore.kernel.org/lkml/80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com/
> That said, the new attributes will show up elsewhere.
>
> So why do you need to add these things in the first place?
Currently there's no sysfs interface to dynamically control the
MIN_PERF/MAX_PERF bounds when using autonomous mode. This helps
users tune power and performance at runtime.
Thank you,
Sumit Gupta
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 14:31 ` Sumit Gupta
@ 2026-02-03 20:24 ` Rafael J. Wysocki
2026-02-03 20:28 ` Mario Limonciello
0 siblings, 1 reply; 26+ messages in thread
From: Rafael J. Wysocki @ 2026-02-03 20:24 UTC (permalink / raw)
To: Sumit Gupta
Cc: Rafael J. Wysocki, Russell Haley, zhenglifeng (A), pierre.gondois,
viresh.kumar, ionela.voinescu, corbet, rdunlap, ray.huang,
gautham.shenoy, mario.limonciello, perry.yuan, zhanjie9, linux-pm,
linux-acpi, linux-doc, acpica-devel, linux-kernel, linux-tegra,
treding, jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu
On Tue, Feb 3, 2026 at 3:32 PM Sumit Gupta <sumitg@nvidia.com> wrote:
>
>
> On 03/02/26 18:24, Rafael J. Wysocki wrote:
> > External email: Use caution opening links or attachments
> >
> >
> > On Tue, Feb 3, 2026 at 1:45 PM Rafael J. Wysocki <rafael@kernel.org> wrote:
> >> On Tue, Feb 3, 2026 at 10:41 AM Sumit Gupta <sumitg@nvidia.com> wrote:
> >>>>>> Hi Sumit,
> >>>>>>
> >>>>>> I am thinking that maybe it is better to call these two sysfs interface
> >>>>>> 'min_freq' and 'max_freq' as users read and write khz instead of raw
> >>>>>> value.
> >>>>> Thanks for the suggestion.
> >>>>> Kept min_perf/max_perf to match the CPPC register names
> >>>>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
> >>>>> CPPC what's being controlled.
> >>>>> The kHz unit is documented in the ABI.
> >>>>>
> >>>>> Thank you,
> >>>>> Sumit Gupta
> >>>> On my x86 machine with kernel 6.18.5, the kernel is exposing raw values:
> >>>>
> >>>>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
> >>>> del:437439724183386
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
> >>>> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
> >>>>
> >>>> It would be surprising for a nearby sysfs interface with very similar
> >>>> names to use kHz instead.
> >>>>
> >>>> Thanks,
> >>>>
> >>>> Russell Haley
> >>> I can rename to either of the below:
> >>> - min/max_freq: might be confused with scaling_min/max_freq.
> >>> - min/max_perf_freq: keeps the CPPC register association clear.
> >>>
> >>> Rafael, Any preferences here?
> >> On x86 the units in CPPC are not kHz and there is no easy reliable way
> >> to convert them to kHz.
> >>
> >> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
> >> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
>
>
> In v1 [1], these controls were added under acpi_cppc sysfs.
> After discussion, they were moved under cpufreq, and [2] was merged first.
> The decision to use frequency scale instead of raw perf was made
> for consistency with other cpufreq interfaces as per (v3 [3]).
>
> CPPC units in our case are also not in kHz. The kHz conversion uses the
> existing cppc_perf_to_khz()/cppc_khz_to_perf() helpers which are already
> used in cppc_cpufreq attributes. So the conversion behavior is consistent
> with existing cpufreq interfaces.
>
> [1]
> https://lore.kernel.org/lkml/076c199c-a081-4a7f-956c-f395f4d5e156@nvidia.com/
> [2]
> https://lore.kernel.org/all/20250507031941.2812701-1-zhenglifeng1@huawei.com/
> [3]
> https://lore.kernel.org/lkml/80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com/
>
> > That said, the new attributes will show up elsewhere.
> >
> > So why do you need to add these things in the first place?
>
> Currently there's no sysfs interface to dynamically control the
> MIN_PERF/MAX_PERF bounds when using autonomous mode. This helps
> users tune power and performance at runtime.
So what about scaling_min_freq and scaling_max_freq?
intel_pstate uses them for an analogous purpose.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 20:24 ` Rafael J. Wysocki
@ 2026-02-03 20:28 ` Mario Limonciello
2026-02-04 9:51 ` Sumit Gupta
0 siblings, 1 reply; 26+ messages in thread
From: Mario Limonciello @ 2026-02-03 20:28 UTC (permalink / raw)
To: Rafael J. Wysocki, Sumit Gupta
Cc: Russell Haley, zhenglifeng (A), pierre.gondois, viresh.kumar,
ionela.voinescu, corbet, rdunlap, ray.huang, gautham.shenoy,
perry.yuan, zhanjie9, linux-pm, linux-acpi, linux-doc,
acpica-devel, linux-kernel, linux-tegra, treding, jonathanh,
vsethi, ksitaraman, sanjayc, nhartman, bbasu
On 2/3/26 2:24 PM, Rafael J. Wysocki wrote:
> On Tue, Feb 3, 2026 at 3:32 PM Sumit Gupta <sumitg@nvidia.com> wrote:
>>
>>
>> On 03/02/26 18:24, Rafael J. Wysocki wrote:
>>> External email: Use caution opening links or attachments
>>>
>>>
>>> On Tue, Feb 3, 2026 at 1:45 PM Rafael J. Wysocki <rafael@kernel.org> wrote:
>>>> On Tue, Feb 3, 2026 at 10:41 AM Sumit Gupta <sumitg@nvidia.com> wrote:
>>>>>>>> Hi Sumit,
>>>>>>>>
>>>>>>>> I am thinking that maybe it is better to call these two sysfs interface
>>>>>>>> 'min_freq' and 'max_freq' as users read and write khz instead of raw
>>>>>>>> value.
>>>>>>> Thanks for the suggestion.
>>>>>>> Kept min_perf/max_perf to match the CPPC register names
>>>>>>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
>>>>>>> CPPC what's being controlled.
>>>>>>> The kHz unit is documented in the ABI.
>>>>>>>
>>>>>>> Thank you,
>>>>>>> Sumit Gupta
>>>>>> On my x86 machine with kernel 6.18.5, the kernel is exposing raw values:
>>>>>>
>>>>>>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
>>>>>> del:437439724183386
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
>>>>>>
>>>>>> It would be surprising for a nearby sysfs interface with very similar
>>>>>> names to use kHz instead.
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> Russell Haley
>>>>> I can rename to either of the below:
>>>>> - min/max_freq: might be confused with scaling_min/max_freq.
>>>>> - min/max_perf_freq: keeps the CPPC register association clear.
>>>>>
>>>>> Rafael, Any preferences here?
>>>> On x86 the units in CPPC are not kHz and there is no easy reliable way
>>>> to convert them to kHz.
>>>>
>>>> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
>>>> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
>>
>>
>> In v1 [1], these controls were added under acpi_cppc sysfs.
>> After discussion, they were moved under cpufreq, and [2] was merged first.
>> The decision to use frequency scale instead of raw perf was made
>> for consistency with other cpufreq interfaces as per (v3 [3]).
>>
>> CPPC units in our case are also not in kHz. The kHz conversion uses the
>> existing cppc_perf_to_khz()/cppc_khz_to_perf() helpers which are already
>> used in cppc_cpufreq attributes. So the conversion behavior is consistent
>> with existing cpufreq interfaces.
>>
>> [1]
>> https://lore.kernel.org/lkml/076c199c-a081-4a7f-956c-f395f4d5e156@nvidia.com/
>> [2]
>> https://lore.kernel.org/all/20250507031941.2812701-1-zhenglifeng1@huawei.com/
>> [3]
>> https://lore.kernel.org/lkml/80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com/
>>
>>> That said, the new attributes will show up elsewhere.
>>>
>>> So why do you need to add these things in the first place?
>>
>> Currently there's no sysfs interface to dynamically control the
>> MIN_PERF/MAX_PERF bounds when using autonomous mode. This helps
>> users tune power and performance at runtime.
>
> So what about scaling_min_freq and scaling_max_freq?
>
> intel_pstate uses them for an analogous purpose.
FWIW same thing for amd_pstate.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 20:28 ` Mario Limonciello
@ 2026-02-04 9:51 ` Sumit Gupta
2026-02-04 13:02 ` Rafael J. Wysocki
0 siblings, 1 reply; 26+ messages in thread
From: Sumit Gupta @ 2026-02-04 9:51 UTC (permalink / raw)
To: Mario Limonciello, Rafael J. Wysocki
Cc: Russell Haley, zhenglifeng (A), pierre.gondois, viresh.kumar,
ionela.voinescu, corbet, rdunlap, ray.huang, gautham.shenoy,
perry.yuan, zhanjie9, linux-pm, linux-acpi, linux-doc,
acpica-devel, linux-kernel, linux-tegra, treding, jonathanh,
vsethi, ksitaraman, sanjayc, nhartman, bbasu, sumitg
On 04/02/26 01:58, Mario Limonciello wrote:
> External email: Use caution opening links or attachments
>
>
> On 2/3/26 2:24 PM, Rafael J. Wysocki wrote:
>> On Tue, Feb 3, 2026 at 3:32 PM Sumit Gupta <sumitg@nvidia.com> wrote:
>>>
>>>
>>> On 03/02/26 18:24, Rafael J. Wysocki wrote:
>>>> External email: Use caution opening links or attachments
>>>>
>>>>
>>>> On Tue, Feb 3, 2026 at 1:45 PM Rafael J. Wysocki
>>>> <rafael@kernel.org> wrote:
>>>>> On Tue, Feb 3, 2026 at 10:41 AM Sumit Gupta <sumitg@nvidia.com>
>>>>> wrote:
>>>>>>>>> Hi Sumit,
>>>>>>>>>
>>>>>>>>> I am thinking that maybe it is better to call these two sysfs
>>>>>>>>> interface
>>>>>>>>> 'min_freq' and 'max_freq' as users read and write khz instead
>>>>>>>>> of raw
>>>>>>>>> value.
>>>>>>>> Thanks for the suggestion.
>>>>>>>> Kept min_perf/max_perf to match the CPPC register names
>>>>>>>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
>>>>>>>> CPPC what's being controlled.
>>>>>>>> The kHz unit is documented in the ABI.
>>>>>>>>
>>>>>>>> Thank you,
>>>>>>>> Sumit Gupta
>>>>>>> On my x86 machine with kernel 6.18.5, the kernel is exposing raw
>>>>>>> values:
>>>>>>>
>>>>>>>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
>>>>>>>
>>>>>>> del:437439724183386
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
>>>>>>>
>>>>>>>
>>>>>>> It would be surprising for a nearby sysfs interface with very
>>>>>>> similar
>>>>>>> names to use kHz instead.
>>>>>>>
>>>>>>> Thanks,
>>>>>>>
>>>>>>> Russell Haley
>>>>>> I can rename to either of the below:
>>>>>> - min/max_freq: might be confused with scaling_min/max_freq.
>>>>>> - min/max_perf_freq: keeps the CPPC register association clear.
>>>>>>
>>>>>> Rafael, Any preferences here?
>>>>> On x86 the units in CPPC are not kHz and there is no easy reliable
>>>>> way
>>>>> to convert them to kHz.
>>>>>
>>>>> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
>>>>> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
>>>
>>>
>>> In v1 [1], these controls were added under acpi_cppc sysfs.
>>> After discussion, they were moved under cpufreq, and [2] was merged
>>> first.
>>> The decision to use frequency scale instead of raw perf was made
>>> for consistency with other cpufreq interfaces as per (v3 [3]).
>>>
>>> CPPC units in our case are also not in kHz. The kHz conversion uses the
>>> existing cppc_perf_to_khz()/cppc_khz_to_perf() helpers which are
>>> already
>>> used in cppc_cpufreq attributes. So the conversion behavior is
>>> consistent
>>> with existing cpufreq interfaces.
>>>
>>> [1]
>>> https://lore.kernel.org/lkml/076c199c-a081-4a7f-956c-f395f4d5e156@nvidia.com/
>>>
>>> [2]
>>> https://lore.kernel.org/all/20250507031941.2812701-1-zhenglifeng1@huawei.com/
>>>
>>> [3]
>>> https://lore.kernel.org/lkml/80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com/
>>>
>>>
>>>> That said, the new attributes will show up elsewhere.
>>>>
>>>> So why do you need to add these things in the first place?
>>>
>>> Currently there's no sysfs interface to dynamically control the
>>> MIN_PERF/MAX_PERF bounds when using autonomous mode. This helps
>>> users tune power and performance at runtime.
>>
>> So what about scaling_min_freq and scaling_max_freq?
>>
>> intel_pstate uses them for an analogous purpose.
>
> FWIW same thing for amd_pstate.
>
intel_pstate and amd_pstate seem to use setpolicy() to update
scaling_min/max_freq and program MIN_PERF/MAX_PERF.
However, as discussed in v5 [1], cppc_cpufreq cannot switch to
a setpolicy based approach because:
- We need per-CPU control of auto_sel: With setpolicy, we can't
dynamically disable auto_sel for individual CPUs and return to the
target() (no target hook available).
intel_pstate and amd_pstate seem to set HW autonomous mode for
all CPUs, not per-CPU.
- We need to retain the target() callback - the CPPC spec allows
desired_perf to be used even when autonomous selection is enabled.
[1]
https://lore.kernel.org/lkml/66f58f43-631b-40a0-8d42-4e90cd24b757@arm.com/
Thank You,
Sumit Gupta
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-04 9:51 ` Sumit Gupta
@ 2026-02-04 13:02 ` Rafael J. Wysocki
2026-02-05 19:21 ` Sumit Gupta
0 siblings, 1 reply; 26+ messages in thread
From: Rafael J. Wysocki @ 2026-02-04 13:02 UTC (permalink / raw)
To: Sumit Gupta
Cc: Mario Limonciello, Rafael J. Wysocki, Russell Haley,
zhenglifeng (A), pierre.gondois, viresh.kumar, ionela.voinescu,
corbet, rdunlap, ray.huang, gautham.shenoy, perry.yuan, zhanjie9,
linux-pm, linux-acpi, linux-doc, acpica-devel, linux-kernel,
linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu
On Wed, Feb 4, 2026 at 10:51 AM Sumit Gupta <sumitg@nvidia.com> wrote:
>
>
> On 04/02/26 01:58, Mario Limonciello wrote:
> > External email: Use caution opening links or attachments
> >
> >
> > On 2/3/26 2:24 PM, Rafael J. Wysocki wrote:
> >> On Tue, Feb 3, 2026 at 3:32 PM Sumit Gupta <sumitg@nvidia.com> wrote:
> >>>
> >>>
> >>> On 03/02/26 18:24, Rafael J. Wysocki wrote:
> >>>> External email: Use caution opening links or attachments
> >>>>
> >>>>
> >>>> On Tue, Feb 3, 2026 at 1:45 PM Rafael J. Wysocki
> >>>> <rafael@kernel.org> wrote:
> >>>>> On Tue, Feb 3, 2026 at 10:41 AM Sumit Gupta <sumitg@nvidia.com>
> >>>>> wrote:
> >>>>>>>>> Hi Sumit,
> >>>>>>>>>
> >>>>>>>>> I am thinking that maybe it is better to call these two sysfs
> >>>>>>>>> interface
> >>>>>>>>> 'min_freq' and 'max_freq' as users read and write khz instead
> >>>>>>>>> of raw
> >>>>>>>>> value.
> >>>>>>>> Thanks for the suggestion.
> >>>>>>>> Kept min_perf/max_perf to match the CPPC register names
> >>>>>>>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
> >>>>>>>> CPPC what's being controlled.
> >>>>>>>> The kHz unit is documented in the ABI.
> >>>>>>>>
> >>>>>>>> Thank you,
> >>>>>>>> Sumit Gupta
> >>>>>>> On my x86 machine with kernel 6.18.5, the kernel is exposing raw
> >>>>>>> values:
> >>>>>>>
> >>>>>>>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
> >>>>>>>
> >>>>>>> del:437439724183386
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
> >>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
> >>>>>>>
> >>>>>>>
> >>>>>>> It would be surprising for a nearby sysfs interface with very
> >>>>>>> similar
> >>>>>>> names to use kHz instead.
> >>>>>>>
> >>>>>>> Thanks,
> >>>>>>>
> >>>>>>> Russell Haley
> >>>>>> I can rename to either of the below:
> >>>>>> - min/max_freq: might be confused with scaling_min/max_freq.
> >>>>>> - min/max_perf_freq: keeps the CPPC register association clear.
> >>>>>>
> >>>>>> Rafael, Any preferences here?
> >>>>> On x86 the units in CPPC are not kHz and there is no easy reliable
> >>>>> way
> >>>>> to convert them to kHz.
> >>>>>
> >>>>> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
> >>>>> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
> >>>
> >>>
> >>> In v1 [1], these controls were added under acpi_cppc sysfs.
> >>> After discussion, they were moved under cpufreq, and [2] was merged
> >>> first.
> >>> The decision to use frequency scale instead of raw perf was made
> >>> for consistency with other cpufreq interfaces as per (v3 [3]).
> >>>
> >>> CPPC units in our case are also not in kHz. The kHz conversion uses the
> >>> existing cppc_perf_to_khz()/cppc_khz_to_perf() helpers which are
> >>> already
> >>> used in cppc_cpufreq attributes. So the conversion behavior is
> >>> consistent
> >>> with existing cpufreq interfaces.
> >>>
> >>> [1]
> >>> https://lore.kernel.org/lkml/076c199c-a081-4a7f-956c-f395f4d5e156@nvidia.com/
> >>>
> >>> [2]
> >>> https://lore.kernel.org/all/20250507031941.2812701-1-zhenglifeng1@huawei.com/
> >>>
> >>> [3]
> >>> https://lore.kernel.org/lkml/80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com/
> >>>
> >>>
> >>>> That said, the new attributes will show up elsewhere.
> >>>>
> >>>> So why do you need to add these things in the first place?
> >>>
> >>> Currently there's no sysfs interface to dynamically control the
> >>> MIN_PERF/MAX_PERF bounds when using autonomous mode. This helps
> >>> users tune power and performance at runtime.
> >>
> >> So what about scaling_min_freq and scaling_max_freq?
> >>
> >> intel_pstate uses them for an analogous purpose.
> >
> > FWIW same thing for amd_pstate.
> >
>
> intel_pstate and amd_pstate seem to use setpolicy() to update
> scaling_min/max_freq and program MIN_PERF/MAX_PERF.
That's one possibility.
intel_pstate has a "cpufreq-compatible" mode (in which case it is
called intel_cpufreq) and still uses HWP (which is the underlying
mechanism for CPPC on Intel platforms).
> However, as discussed in v5 [1], cppc_cpufreq cannot switch to
> a setpolicy based approach because:
> - We need per-CPU control of auto_sel: With setpolicy, we can't
> dynamically disable auto_sel for individual CPUs and return to the
> target() (no target hook available).
> intel_pstate and amd_pstate seem to set HW autonomous mode for
> all CPUs, not per-CPU.
> - We need to retain the target() callback - the CPPC spec allows
> desired_perf to be used even when autonomous selection is enabled.
intel_pstate in the "cpufreq-compatible" mode updates its HWP min and
max limits when .target() (or .fast_switch() or .adjust_perf()) is
called.
I guess that would not be sufficient in cppc_cpufreq for some reason?
> [1]
> https://lore.kernel.org/lkml/66f58f43-631b-40a0-8d42-4e90cd24b757@arm.com/
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-03 12:43 ` Rafael J. Wysocki
2026-02-03 12:50 ` Rafael J. Wysocki
@ 2026-02-05 13:10 ` Artem Bityutskiy
1 sibling, 0 replies; 26+ messages in thread
From: Artem Bityutskiy @ 2026-02-05 13:10 UTC (permalink / raw)
To: Rafael J. Wysocki, Sumit Gupta
Cc: viresh.kumar, pierre.gondois, zhenglifeng1, ionela.voinescu, lenb,
robert.moore, corbet, rdunlap, ray.huang, gautham.shenoy,
mario.limonciello, perry.yuan, zhanjie9, linux-pm, linux-acpi,
linux-doc, acpica-devel, linux-kernel, linux-tegra, treding,
jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu
On Tue, 2026-02-03 at 13:43 +0100, Rafael J. Wysocki wrote:
> On Thu, Jan 29, 2026 at 11:49 AM Sumit Gupta <sumitg@nvidia.com> wrote:
> >
> > Add cppc_get/set_min_perf() and cppc_get/set_max_perf() APIs to read and
> > write the MIN_PERF and MAX_PERF registers.
> >
> > Also add sysfs interfaces (min_perf, max_perf) in cppc_cpufreq driver
> > to expose these controls to userspace. The sysfs values are in frequency
> > (kHz) for consistency with other cpufreq sysfs files.
>
> But this is not cpufreq and it is not consistent.
Just my 2 cents to add:
CPPC and Intel CPUs don't use kHz for performance scaling. We should
avoid introducing additional kHz-based interfaces where possible, since
the performance units <-> kHz translation may become more complex over
time than today. Future implementations could involve non-linear
relationships and reduced accuracy. Minimizing kHz interfaces now may
help reduce future work.
Thanks,
Artem.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-04 13:02 ` Rafael J. Wysocki
@ 2026-02-05 19:21 ` Sumit Gupta
2026-02-05 19:27 ` Rafael J. Wysocki
0 siblings, 1 reply; 26+ messages in thread
From: Sumit Gupta @ 2026-02-05 19:21 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Mario Limonciello, Russell Haley, zhenglifeng (A), pierre.gondois,
viresh.kumar, ionela.voinescu, corbet, rdunlap, ray.huang,
gautham.shenoy, perry.yuan, zhanjie9, linux-pm, linux-acpi,
linux-doc, acpica-devel, linux-kernel, linux-tegra, treding,
jonathanh, vsethi, ksitaraman, sanjayc, nhartman, bbasu, sumitg
>>>>>>>>>>> Hi Sumit,
>>>>>>>>>>>
>>>>>>>>>>> I am thinking that maybe it is better to call these two sysfs
>>>>>>>>>>> interface
>>>>>>>>>>> 'min_freq' and 'max_freq' as users read and write khz instead
>>>>>>>>>>> of raw
>>>>>>>>>>> value.
>>>>>>>>>> Thanks for the suggestion.
>>>>>>>>>> Kept min_perf/max_perf to match the CPPC register names
>>>>>>>>>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
>>>>>>>>>> CPPC what's being controlled.
>>>>>>>>>> The kHz unit is documented in the ABI.
>>>>>>>>>>
>>>>>>>>>> Thank you,
>>>>>>>>>> Sumit Gupta
>>>>>>>>> On my x86 machine with kernel 6.18.5, the kernel is exposing raw
>>>>>>>>> values:
>>>>>>>>>
>>>>>>>>>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
>>>>>>>>>
>>>>>>>>> del:437439724183386
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
>>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> It would be surprising for a nearby sysfs interface with very
>>>>>>>>> similar
>>>>>>>>> names to use kHz instead.
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>>
>>>>>>>>> Russell Haley
>>>>>>>> I can rename to either of the below:
>>>>>>>> - min/max_freq: might be confused with scaling_min/max_freq.
>>>>>>>> - min/max_perf_freq: keeps the CPPC register association clear.
>>>>>>>>
>>>>>>>> Rafael, Any preferences here?
>>>>>>> On x86 the units in CPPC are not kHz and there is no easy reliable
>>>>>>> way
>>>>>>> to convert them to kHz.
>>>>>>>
>>>>>>> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
>>>>>>> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
>>>>>
>>>>> In v1 [1], these controls were added under acpi_cppc sysfs.
>>>>> After discussion, they were moved under cpufreq, and [2] was merged
>>>>> first.
>>>>> The decision to use frequency scale instead of raw perf was made
>>>>> for consistency with other cpufreq interfaces as per (v3 [3]).
>>>>>
>>>>> CPPC units in our case are also not in kHz. The kHz conversion uses the
>>>>> existing cppc_perf_to_khz()/cppc_khz_to_perf() helpers which are
>>>>> already
>>>>> used in cppc_cpufreq attributes. So the conversion behavior is
>>>>> consistent
>>>>> with existing cpufreq interfaces.
>>>>>
>>>>> [1]
>>>>> https://lore.kernel.org/lkml/076c199c-a081-4a7f-956c-f395f4d5e156@nvidia.com/
>>>>>
>>>>> [2]
>>>>> https://lore.kernel.org/all/20250507031941.2812701-1-zhenglifeng1@huawei.com/
>>>>>
>>>>> [3]
>>>>> https://lore.kernel.org/lkml/80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com/
>>>>>
>>>>>
>>>>>> That said, the new attributes will show up elsewhere.
>>>>>>
>>>>>> So why do you need to add these things in the first place?
>>>>> Currently there's no sysfs interface to dynamically control the
>>>>> MIN_PERF/MAX_PERF bounds when using autonomous mode. This helps
>>>>> users tune power and performance at runtime.
>>>> So what about scaling_min_freq and scaling_max_freq?
>>>>
>>>> intel_pstate uses them for an analogous purpose.
>>> FWIW same thing for amd_pstate.
>>>
>> intel_pstate and amd_pstate seem to use setpolicy() to update
>> scaling_min/max_freq and program MIN_PERF/MAX_PERF.
> That's one possibility.
>
> intel_pstate has a "cpufreq-compatible" mode (in which case it is
> called intel_cpufreq) and still uses HWP (which is the underlying
> mechanism for CPPC on Intel platforms).
>
>> However, as discussed in v5 [1], cppc_cpufreq cannot switch to
>> a setpolicy based approach because:
>> - We need per-CPU control of auto_sel: With setpolicy, we can't
>> dynamically disable auto_sel for individual CPUs and return to the
>> target() (no target hook available).
>> intel_pstate and amd_pstate seem to set HW autonomous mode for
>> all CPUs, not per-CPU.
>> - We need to retain the target() callback - the CPPC spec allows
>> desired_perf to be used even when autonomous selection is enabled.
> intel_pstate in the "cpufreq-compatible" mode updates its HWP min and
> max limits when .target() (or .fast_switch() or .adjust_perf()) is
> called.
>
> I guess that would not be sufficient in cppc_cpufreq for some reason?
>
>> [1]
>> https://lore.kernel.org/lkml/66f58f43-631b-40a0-8d42-4e90cd24b757@arm.com/
We can do the same as intel_cpufreq. CPPC spec allows setting
MIN_PERF/MAX_PERF even when auto_selection is disabled, so we will
have to update them always from policy limits in target().
However, this would override BIOS-configured MIN_PERF/MAX_PERF values.
Since policy->min/max are set from hardware capabilities during init,
any governor would overwrite BIOS bounds with policy limits (hardware
capability bounds) on their first frequency request - even when user
hasn't explicitly changed scaling_min/max_freq.
Does intel_cpufreq also override BIOS-configured HWP min/max values?
Should we preserve BIOS-configured values until user explicitly changes
scaling_min/max_freq? Is there any mechanism in cpufreq core to detect
explicit user changes to scaling_min/max_freq?
Thank you,
Sumit Gupta
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
2026-02-05 19:21 ` Sumit Gupta
@ 2026-02-05 19:27 ` Rafael J. Wysocki
0 siblings, 0 replies; 26+ messages in thread
From: Rafael J. Wysocki @ 2026-02-05 19:27 UTC (permalink / raw)
To: Sumit Gupta
Cc: Rafael J. Wysocki, Mario Limonciello, Russell Haley,
zhenglifeng (A), pierre.gondois, viresh.kumar, ionela.voinescu,
corbet, rdunlap, ray.huang, gautham.shenoy, perry.yuan, zhanjie9,
linux-pm, linux-acpi, linux-doc, acpica-devel, linux-kernel,
linux-tegra, treding, jonathanh, vsethi, ksitaraman, sanjayc,
nhartman, bbasu
On Thu, Feb 5, 2026 at 8:21 PM Sumit Gupta <sumitg@nvidia.com> wrote:
>
> >>>>>>>>>>> Hi Sumit,
> >>>>>>>>>>>
> >>>>>>>>>>> I am thinking that maybe it is better to call these two sysfs
> >>>>>>>>>>> interface
> >>>>>>>>>>> 'min_freq' and 'max_freq' as users read and write khz instead
> >>>>>>>>>>> of raw
> >>>>>>>>>>> value.
> >>>>>>>>>> Thanks for the suggestion.
> >>>>>>>>>> Kept min_perf/max_perf to match the CPPC register names
> >>>>>>>>>> (MIN_PERF/MAX_PERF), making it clear to users familiar with
> >>>>>>>>>> CPPC what's being controlled.
> >>>>>>>>>> The kHz unit is documented in the ABI.
> >>>>>>>>>>
> >>>>>>>>>> Thank you,
> >>>>>>>>>> Sumit Gupta
> >>>>>>>>> On my x86 machine with kernel 6.18.5, the kernel is exposing raw
> >>>>>>>>> values:
> >>>>>>>>>
> >>>>>>>>>> grep . /sys/devices/system/cpu/cpu0/acpi_cppc/*
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/feedback_ctrs:ref:342904018856568
> >>>>>>>>>
> >>>>>>>>> del:437439724183386
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/guaranteed_perf:63
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/highest_perf:88
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_freq:0
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_nonlinear_perf:36
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/lowest_perf:1
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq:3900
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_perf:62
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/reference_perf:62
> >>>>>>>>> /sys/devices/system/cpu/cpu0/acpi_cppc/wraparound_time:18446744073709551615
> >>>>>>>>>
> >>>>>>>>>
> >>>>>>>>> It would be surprising for a nearby sysfs interface with very
> >>>>>>>>> similar
> >>>>>>>>> names to use kHz instead.
> >>>>>>>>>
> >>>>>>>>> Thanks,
> >>>>>>>>>
> >>>>>>>>> Russell Haley
> >>>>>>>> I can rename to either of the below:
> >>>>>>>> - min/max_freq: might be confused with scaling_min/max_freq.
> >>>>>>>> - min/max_perf_freq: keeps the CPPC register association clear.
> >>>>>>>>
> >>>>>>>> Rafael, Any preferences here?
> >>>>>>> On x86 the units in CPPC are not kHz and there is no easy reliable
> >>>>>>> way
> >>>>>>> to convert them to kHz.
> >>>>>>>
> >>>>>>> Everything under /sys/devices/system/cpu/cpu0/acpi_cppc/ needs to be
> >>>>>>> in CPPC units, not kHz (unless, of course, kHz are CPPC units).
> >>>>>
> >>>>> In v1 [1], these controls were added under acpi_cppc sysfs.
> >>>>> After discussion, they were moved under cpufreq, and [2] was merged
> >>>>> first.
> >>>>> The decision to use frequency scale instead of raw perf was made
> >>>>> for consistency with other cpufreq interfaces as per (v3 [3]).
> >>>>>
> >>>>> CPPC units in our case are also not in kHz. The kHz conversion uses the
> >>>>> existing cppc_perf_to_khz()/cppc_khz_to_perf() helpers which are
> >>>>> already
> >>>>> used in cppc_cpufreq attributes. So the conversion behavior is
> >>>>> consistent
> >>>>> with existing cpufreq interfaces.
> >>>>>
> >>>>> [1]
> >>>>> https://lore.kernel.org/lkml/076c199c-a081-4a7f-956c-f395f4d5e156@nvidia.com/
> >>>>>
> >>>>> [2]
> >>>>> https://lore.kernel.org/all/20250507031941.2812701-1-zhenglifeng1@huawei.com/
> >>>>>
> >>>>> [3]
> >>>>> https://lore.kernel.org/lkml/80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com/
> >>>>>
> >>>>>
> >>>>>> That said, the new attributes will show up elsewhere.
> >>>>>>
> >>>>>> So why do you need to add these things in the first place?
> >>>>> Currently there's no sysfs interface to dynamically control the
> >>>>> MIN_PERF/MAX_PERF bounds when using autonomous mode. This helps
> >>>>> users tune power and performance at runtime.
> >>>> So what about scaling_min_freq and scaling_max_freq?
> >>>>
> >>>> intel_pstate uses them for an analogous purpose.
> >>> FWIW same thing for amd_pstate.
> >>>
> >> intel_pstate and amd_pstate seem to use setpolicy() to update
> >> scaling_min/max_freq and program MIN_PERF/MAX_PERF.
> > That's one possibility.
> >
> > intel_pstate has a "cpufreq-compatible" mode (in which case it is
> > called intel_cpufreq) and still uses HWP (which is the underlying
> > mechanism for CPPC on Intel platforms).
> >
> >> However, as discussed in v5 [1], cppc_cpufreq cannot switch to
> >> a setpolicy based approach because:
> >> - We need per-CPU control of auto_sel: With setpolicy, we can't
> >> dynamically disable auto_sel for individual CPUs and return to the
> >> target() (no target hook available).
> >> intel_pstate and amd_pstate seem to set HW autonomous mode for
> >> all CPUs, not per-CPU.
> >> - We need to retain the target() callback - the CPPC spec allows
> >> desired_perf to be used even when autonomous selection is enabled.
> > intel_pstate in the "cpufreq-compatible" mode updates its HWP min and
> > max limits when .target() (or .fast_switch() or .adjust_perf()) is
> > called.
> >
> > I guess that would not be sufficient in cppc_cpufreq for some reason?
> >
> >> [1]
> >> https://lore.kernel.org/lkml/66f58f43-631b-40a0-8d42-4e90cd24b757@arm.com/
>
> We can do the same as intel_cpufreq. CPPC spec allows setting
> MIN_PERF/MAX_PERF even when auto_selection is disabled, so we will
> have to update them always from policy limits in target().
>
> However, this would override BIOS-configured MIN_PERF/MAX_PERF values.
> Since policy->min/max are set from hardware capabilities during init,
> any governor would overwrite BIOS bounds with policy limits (hardware
> capability bounds) on their first frequency request - even when user
> hasn't explicitly changed scaling_min/max_freq.
>
> Does intel_cpufreq also override BIOS-configured HWP min/max values?
Yes, it does.
> Should we preserve BIOS-configured values until user explicitly changes
> scaling_min/max_freq?
Why would that be useful?
> Is there any mechanism in cpufreq core to detect explicit user changes to scaling_min/max_freq?
Not today, but since scaling_min/max_freq have their own freq QoS
requests, it should be doable if need be.
In any case, I would very much prefer using the existing
scaling_min/max_freq interface, even if that would require some
additional plumbing, to adding new sysfs attributes pretty much for
the same purpose that would only be used by one driver.
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2026-02-05 19:27 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-29 10:48 [PATCH v7 0/7] Enhanced autonomous selection and improvements Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 1/7] ACPI: CPPC: Add cppc_get_perf() API to read performance controls Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 2/7] ACPI: CPPC: Warn on missing mandatory DESIRED_PERF register Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 3/7] ACPI: CPPC: Extend cppc_set_epp_perf() for FFH/SystemMemory Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf Sumit Gupta
2026-01-31 4:06 ` zhenglifeng (A)
2026-01-31 13:58 ` Sumit Gupta
2026-02-03 1:36 ` Russell Haley
2026-02-03 9:41 ` Sumit Gupta
2026-02-03 12:45 ` Rafael J. Wysocki
2026-02-03 12:54 ` Rafael J. Wysocki
2026-02-03 14:31 ` Sumit Gupta
2026-02-03 20:24 ` Rafael J. Wysocki
2026-02-03 20:28 ` Mario Limonciello
2026-02-04 9:51 ` Sumit Gupta
2026-02-04 13:02 ` Rafael J. Wysocki
2026-02-05 19:21 ` Sumit Gupta
2026-02-05 19:27 ` Rafael J. Wysocki
2026-02-03 12:43 ` Rafael J. Wysocki
2026-02-03 12:50 ` Rafael J. Wysocki
2026-02-05 13:10 ` Artem Bityutskiy
2026-01-29 10:48 ` [PATCH v7 5/7] ACPI: CPPC: add APIs and sysfs interface for perf_limited Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 6/7] cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited Sumit Gupta
2026-01-29 10:48 ` [PATCH v7 7/7] cpufreq: CPPC: Update cached perf_ctrls on sysfs write Sumit Gupta
2026-01-30 8:23 ` [PATCH v7 0/7] Enhanced autonomous selection and improvements Pierre Gondois
2026-01-31 2:58 ` zhenglifeng (A)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox