From: Sumit Gupta <sumitg@nvidia.com>
To: Ionela Voinescu <ionela.voinescu@arm.com>
Cc: rafael@kernel.org, viresh.kumar@linaro.org, lenb@kernel.org,
robert.moore@intel.com, corbet@lwn.net, pierre.gondois@arm.com,
zhenglifeng1@huawei.com, rdunlap@infradead.org,
ray.huang@amd.com, gautham.shenoy@amd.com,
mario.limonciello@amd.com, perry.yuan@amd.com,
linux-pm@vger.kernel.org, linux-acpi@vger.kernel.org,
linux-doc@vger.kernel.org, acpica-devel@lists.linux.dev,
linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
treding@nvidia.com, jonathanh@nvidia.com, vsethi@nvidia.com,
ksitaraman@nvidia.com, sanjayc@nvidia.com, bbasu@nvidia.com,
sumitg@nvidia.com
Subject: Re: [PATCH v3 4/8] ACPI: CPPC: add APIs and sysfs interface for min/max_perf
Date: Fri, 24 Oct 2025 18:52:51 +0530 [thread overview]
Message-ID: <80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com> (raw)
In-Reply-To: <aPi48fm+cMDmQBN9@arm.com>
On 22/10/25 16:28, Ionela Voinescu wrote:
> External email: Use caution opening links or attachments
>
>
> On Wednesday 01 Oct 2025 at 20:31:00 (+0530), Sumit Gupta wrote:
>> CPPC allows platforms to specify minimum and maximum performance
>> limits that constrain the operating range for CPU performance scaling
>> when Autonomous Selection is enabled. These limits can be dynamically
>> adjusted to implement power management policies or workload-specific
>> optimizations.
>>
>> Add cppc_get_min_perf() and cppc_set_min_perf() functions to read and
>> write the MIN_PERF register, allowing dynamic adjustment of the minimum
>> performance floor.
>>
>> Add cppc_get_max_perf() and cppc_set_max_perf() functions to read and
>> write the MAX_PERF register, enabling dynamic ceiling control for
>> maximum performance.
>>
>> Expose these capabilities through cpufreq sysfs attributes:
>> - /sys/.../cpufreq/policy*/min_perf: Read/write min performance limit
>> - /sys/.../cpufreq/policy*/max_perf: Read/write max performance limit
>>
>> Also update EPP constants for better clarity:
>> - Rename CPPC_ENERGY_PERF_MAX to CPPC_EPP_ENERGY_EFFICIENCY_PREF
>> - Add CPPC_EPP_PERFORMANCE_PREF for the performance-oriented setting
>>
>> Signed-off-by: Sumit Gupta <sumitg@nvidia.com>
>> ---
>> drivers/acpi/cppc_acpi.c | 55 +++++++++++++++-
>> drivers/cpufreq/cppc_cpufreq.c | 115 +++++++++++++++++++++++++++++++++
>> include/acpi/cppc_acpi.h | 23 ++++++-
>> 3 files changed, 191 insertions(+), 2 deletions(-)
>>
> [..]
>> diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
>> index 732f35096991..864978674efc 100644
>> --- a/drivers/cpufreq/cppc_cpufreq.c
>> +++ b/drivers/cpufreq/cppc_cpufreq.c
>> @@ -23,6 +23,7 @@
>> #include <uapi/linux/sched/types.h>
>>
>> #include <linux/unaligned.h>
>> +#include <linux/cleanup.h>
>>
>> #include <acpi/cppc_acpi.h>
>>
>> @@ -38,6 +39,8 @@ static enum {
>> module_param(fie_disabled, int, 0444);
>> MODULE_PARM_DESC(fie_disabled, "Disable Frequency Invariance Engine (FIE)");
>>
>> +static DEFINE_MUTEX(cppc_cpufreq_update_autosel_config_lock);
> Should this be under CONFIG_ACPI_CPPC_CPUFREQ_FIE?
Thank you for catching. Will move it outside in v4.
>> +
>> /* Frequency invariance support */
>> struct cppc_freq_invariance {
>> int cpu;
>> @@ -572,6 +575,70 @@ static void cppc_cpufreq_put_cpu_data(struct cpufreq_policy *policy)
>> policy->driver_data = NULL;
>> }
>>
>> +/**
>> + * cppc_cpufreq_set_mperf_limit - Generic function to set min/max performance limit
>> + * @policy: cpufreq policy
>> + * @val: performance value to set
>> + * @update_reg: whether to update hardware register
>> + * @update_policy: whether to update policy constraints
>> + * @is_min: true for min_perf, false for max_perf
>> + */
>> +static int cppc_cpufreq_set_mperf_limit(struct cpufreq_policy *policy, u64 val,
>> + bool update_reg, bool update_policy, 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;
>> + struct freq_qos_request *req;
>> + unsigned int freq;
>> + u32 perf;
>> + int ret;
>> +
>> + perf = clamp(val, caps->lowest_perf, caps->highest_perf);
>> + freq = cppc_perf_to_khz(caps, perf);
>> +
>> + pr_debug("cpu%d, %s_perf:%llu, update_reg:%d, update_policy:%d\n", cpu,
>> + is_min ? "min" : "max", (u64)perf, update_reg, update_policy);
>> +
>> + guard(mutex)(&cppc_cpufreq_update_autosel_config_lock);
>> +
>> + if (update_reg) {
>> + ret = is_min ? cppc_set_min_perf(cpu, perf) : cppc_set_max_perf(cpu, perf);
>> + if (ret == -EOPNOTSUPP)
>> + return 0;
> Should we return success here? The user will have no feedback that
> setting min/max performance limits is not supported.
Will do change in v4 to also return EOPNOTSUPP error code to the caller.
>> + if (ret) {
>> + pr_warn("Failed to set %s_perf (%llu) on CPU%d (%d)\n",
>> + is_min ? "min" : "max", (u64)perf, cpu, ret);
>> + return ret;
>> + }
>> +
>> + /* Update cached value only on success */
>> + if (is_min)
>> + cpu_data->perf_ctrls.min_perf = perf;
>> + else
>> + cpu_data->perf_ctrls.max_perf = perf;
>> + }
>> +
>> + if (update_policy) {
>> + req = is_min ? policy->min_freq_req : policy->max_freq_req;
>> +
>> + ret = freq_qos_update_request(req, freq);
>> + if (ret < 0) {
>> + pr_warn("Failed to update %s_freq constraint for CPU%d: %d\n",
>> + is_min ? "min" : "max", cpu, ret);
>> + return ret;
>> + }
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +#define cppc_cpufreq_set_min_perf(policy, val, update_reg, update_policy) \
>> + cppc_cpufreq_set_mperf_limit(policy, val, update_reg, update_policy, true)
>> +
>> +#define cppc_cpufreq_set_max_perf(policy, val, update_reg, update_policy) \
>> + cppc_cpufreq_set_mperf_limit(policy, val, update_reg, update_policy, false)
>> +
>> static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
>> {
>> unsigned int cpu = policy->cpu;
>> @@ -873,16 +940,64 @@ static ssize_t store_energy_performance_preference_val(struct cpufreq_policy *po
>> return cppc_cpufreq_sysfs_store_u64(buf, count, cppc_set_epp, policy->cpu);
>> }
>>
>> +static ssize_t show_min_perf(struct cpufreq_policy *policy, char *buf)
>> +{
>> + return cppc_cpufreq_sysfs_show_u64(policy->cpu, cppc_get_min_perf, buf);
>> +}
>> +
>> +static ssize_t store_min_perf(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_cpufreq_set_min_perf(policy, val, true, cpu_data->perf_caps.auto_sel);
>> + if (ret)
>> + return ret;
>> +
>> + return count;
>> +}
>> +
>> +static ssize_t show_max_perf(struct cpufreq_policy *policy, char *buf)
>> +{
>> + return cppc_cpufreq_sysfs_show_u64(policy->cpu, cppc_get_max_perf, buf);
>> +}
>> +
>> +static ssize_t store_max_perf(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_cpufreq_set_max_perf(policy, val, true, cpu_data->perf_caps.auto_sel);
> These "work" on the performance scale, so the values read are
> performance values and the values that should be provided should be
> performance values as well. How is the user supposed to know what that
> scale is and what is the range of values it can provide? All of the
> other sysfs interfaces work on the "frequency" scale and the lowest and
> highest performance values are never exposed to the user.
>
> Thanks,
> Ionela.
Can do the change in v4 for these nodes to get min/max freq value from
user, convert
that to perf with cppc_khz_to_perf() before write to min/max_perf
registers and vice-versa.
That will keep the scale same as other cpufreq sysfs interfaces.
>> + 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 3babc6d6e70a..fc7614eb9dcb 100644
>> --- a/include/acpi/cppc_acpi.h
>> +++ b/include/acpi/cppc_acpi.h
>> @@ -39,7 +39,8 @@
>> /* CPPC_AUTO_ACT_WINDOW_MAX_SIG is 127, so 128 and 129 will decay to 127 when writing */
>> #define CPPC_AUTO_ACT_WINDOW_SIG_CARRY_THRESH 129
>>
>> -#define CPPC_ENERGY_PERF_MAX (0xFF)
>> +#define CPPC_EPP_PERFORMANCE_PREF 0x00
>> +#define CPPC_EPP_ENERGY_EFFICIENCY_PREF 0xFF
>>
>> /* Each register has the folowing format. */
>> struct cpc_reg {
>> @@ -172,6 +173,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, u64 min_perf);
>> +extern int cppc_get_max_perf(int cpu, u64 *max_perf);
>> +extern int cppc_set_max_perf(int cpu, u64 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);
>> @@ -264,6 +269,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, u64 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, u64 max_perf)
>> +{
>> + return -EOPNOTSUPP;
>> +}
>> static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
>> {
>> return -ENODEV;
>> --
>> 2.34.1
>>
>>
next prev parent reply other threads:[~2025-10-24 13:23 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-01 15:00 [PATCH v3 0/8] Enhanced autonomous selection and improvements Sumit Gupta
2025-10-01 15:00 ` [PATCH v3 1/8] cpufreq: CPPC: Add generic helpers for sysfs show/store Sumit Gupta
2025-10-10 3:24 ` Jie Zhan
2025-10-13 12:51 ` Sumit Gupta
2025-10-01 15:00 ` [PATCH v3 2/8] ACPI: CPPC: Add cppc_get_perf() API to read performance controls Sumit Gupta
2025-10-01 15:00 ` [PATCH v3 3/8] ACPI: CPPC: extend APIs to support auto_sel and epp Sumit Gupta
2025-10-22 9:12 ` Ionela Voinescu
2025-10-24 13:12 ` Sumit Gupta
2025-10-01 15:01 ` [PATCH v3 4/8] ACPI: CPPC: add APIs and sysfs interface for min/max_perf Sumit Gupta
2025-10-22 10:58 ` Ionela Voinescu
2025-10-24 13:22 ` Sumit Gupta [this message]
2025-10-01 15:01 ` [PATCH v3 5/8] ACPI: CPPC: add APIs and sysfs interface for perf_limited register Sumit Gupta
2025-10-01 15:01 ` [PATCH v3 6/8] cpufreq: CPPC: Add sysfs for min/max_perf and perf_limited Sumit Gupta
2025-10-01 17:03 ` Mario Limonciello
2025-10-08 10:16 ` Sumit Gupta
2025-10-10 3:29 ` Jie Zhan
2025-10-13 11:59 ` Sumit Gupta
2025-10-22 12:02 ` Ionela Voinescu
2025-10-24 13:32 ` Sumit Gupta
2025-10-01 15:01 ` [PATCH v3 7/8] cpufreq: CPPC: update policy min/max when toggling auto_select Sumit Gupta
2025-10-01 15:01 ` [PATCH v3 8/8] cpufreq: CPPC: add autonomous mode boot parameter support Sumit Gupta
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=80e16de0-63e4-4ead-9577-4ebba9b1a02d@nvidia.com \
--to=sumitg@nvidia.com \
--cc=acpica-devel@lists.linux.dev \
--cc=bbasu@nvidia.com \
--cc=corbet@lwn.net \
--cc=gautham.shenoy@amd.com \
--cc=ionela.voinescu@arm.com \
--cc=jonathanh@nvidia.com \
--cc=ksitaraman@nvidia.com \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=mario.limonciello@amd.com \
--cc=perry.yuan@amd.com \
--cc=pierre.gondois@arm.com \
--cc=rafael@kernel.org \
--cc=ray.huang@amd.com \
--cc=rdunlap@infradead.org \
--cc=robert.moore@intel.com \
--cc=sanjayc@nvidia.com \
--cc=treding@nvidia.com \
--cc=viresh.kumar@linaro.org \
--cc=vsethi@nvidia.com \
--cc=zhenglifeng1@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox