[PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf

Sumit Gupta posted 7 patches 1 week, 2 days ago
There is a newer version of this series
[PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Sumit Gupta 1 week, 2 days ago
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
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Rafael J. Wysocki 4 days, 21 hours ago
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
>
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Artem Bityutskiy 2 days, 21 hours ago
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.
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Rafael J. Wysocki 4 days, 21 hours ago
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.
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by zhenglifeng (A) 1 week, 1 day ago
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;
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Sumit Gupta 1 week ago
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;
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Russell Haley 5 days, 8 hours ago
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
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Sumit Gupta 5 days ago
>>> 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
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Rafael J. Wysocki 4 days, 21 hours ago
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).
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Rafael J. Wysocki 4 days, 21 hours ago
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?
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Sumit Gupta 4 days, 20 hours ago
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


Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Rafael J. Wysocki 4 days, 14 hours ago
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.
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Mario Limonciello 4 days, 14 hours ago
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.

Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Sumit Gupta 4 days ago
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


Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Rafael J. Wysocki 3 days, 21 hours ago
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/
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Sumit Gupta 2 days, 15 hours ago
>>>>>>>>>>> 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
Re: [PATCH v7 4/7] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Posted by Rafael J. Wysocki 2 days, 15 hours ago
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.