Skip to content

Commit d0356d5

Browse files
Sumit GuptajamieNguyenNVIDIA
authored andcommitted
ACPI: CPPC: add APIs and sysfs interface for perf_limited
Add sysfs interface to read/write the Performance Limited register. The Performance Limited register indicates to the OS that an unpredictable event (like thermal throttling) has limited processor performance. It contains two sticky bits set by the platform: - Bit 0 (Desired_Excursion): Set when delivered performance is constrained below desired performance. Not used when Autonomous Selection is enabled. - Bit 1 (Minimum_Excursion): Set when delivered performance is constrained below minimum performance. These bits remain set until OSPM explicitly clears them. The write operation accepts a bitmask of bits to clear: - Write 0x1 to clear bit 0 - Write 0x2 to clear bit 1 - Write 0x3 to clear both bits This enables users to detect if platform throttling impacted a workload. Users clear the register before execution, run the workload, then check afterward - if set, hardware throttling occurred during that time window. The interface is exposed as: /sys/devices/system/cpu/cpuX/cpufreq/perf_limited Signed-off-by: Sumit Gupta <sumitg@nvidia.com> Reviewed-by: Pierre Gondois <pierre.gondois@arm.com> Reviewed-by: Lifeng Zheng <zhenglifeng1@huawei.com> (backported from commit 13c45a2) [jamien: adapted for tree without CPPC_CPUFREQ_ATTR_RW_U64 macro - used explicit show/store functions instead] Signed-off-by: Jamie Nguyen <jamien@nvidia.com>
1 parent 08680e0 commit d0356d5

3 files changed

Lines changed: 106 additions & 0 deletions

File tree

drivers/acpi/cppc_acpi.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,6 +1972,62 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
19721972
}
19731973
EXPORT_SYMBOL_GPL(cppc_set_perf);
19741974

1975+
/**
1976+
* cppc_get_perf_limited - Get the Performance Limited register value.
1977+
* @cpu: CPU from which to get Performance Limited register.
1978+
* @perf_limited: Pointer to store the Performance Limited value.
1979+
*
1980+
* The returned value contains sticky status bits indicating platform-imposed
1981+
* performance limitations.
1982+
*
1983+
* Return: 0 for success, -EIO on failure, -EOPNOTSUPP if not supported.
1984+
*/
1985+
int cppc_get_perf_limited(int cpu, u64 *perf_limited)
1986+
{
1987+
return cppc_get_reg_val(cpu, PERF_LIMITED, perf_limited);
1988+
}
1989+
EXPORT_SYMBOL_GPL(cppc_get_perf_limited);
1990+
1991+
/**
1992+
* cppc_set_perf_limited() - Clear bits in the Performance Limited register.
1993+
* @cpu: CPU on which to write register.
1994+
* @bits_to_clear: Bitmask of bits to clear in the perf_limited register.
1995+
*
1996+
* The Performance Limited register contains two sticky bits set by platform:
1997+
* - Bit 0 (Desired_Excursion): Set when delivered performance is constrained
1998+
* below desired performance. Not used when Autonomous Selection is enabled.
1999+
* - Bit 1 (Minimum_Excursion): Set when delivered performance is constrained
2000+
* below minimum performance.
2001+
*
2002+
* These bits are sticky and remain set until OSPM explicitly clears them.
2003+
* This function only allows clearing bits (the platform sets them).
2004+
*
2005+
* Return: 0 for success, -EINVAL for invalid bits, -EIO on register
2006+
* access failure, -EOPNOTSUPP if not supported.
2007+
*/
2008+
int cppc_set_perf_limited(int cpu, u64 bits_to_clear)
2009+
{
2010+
u64 current_val, new_val;
2011+
int ret;
2012+
2013+
/* Only bits 0 and 1 are valid */
2014+
if (bits_to_clear & ~CPPC_PERF_LIMITED_MASK)
2015+
return -EINVAL;
2016+
2017+
if (!bits_to_clear)
2018+
return 0;
2019+
2020+
ret = cppc_get_perf_limited(cpu, &current_val);
2021+
if (ret)
2022+
return ret;
2023+
2024+
/* Clear the specified bits */
2025+
new_val = current_val & ~bits_to_clear;
2026+
2027+
return cppc_set_reg_val(cpu, PERF_LIMITED, new_val);
2028+
}
2029+
EXPORT_SYMBOL_GPL(cppc_set_perf_limited);
2030+
19752031
/**
19762032
* cppc_get_transition_latency - returns frequency transition latency in ns
19772033
* @cpu_num: CPU number for per_cpu().

drivers/cpufreq/cppc_cpufreq.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,16 +957,51 @@ static ssize_t store_energy_performance_preference_val(struct cpufreq_policy *po
957957
return count;
958958
}
959959

960+
static ssize_t show_perf_limited(struct cpufreq_policy *policy, char *buf)
961+
{
962+
u64 val;
963+
int ret;
964+
965+
ret = cppc_get_perf_limited(policy->cpu, &val);
966+
967+
if (ret == -EOPNOTSUPP)
968+
return sysfs_emit(buf, "<unsupported>\n");
969+
970+
if (ret)
971+
return ret;
972+
973+
return sysfs_emit(buf, "%llu\n", val);
974+
}
975+
976+
static ssize_t store_perf_limited(struct cpufreq_policy *policy,
977+
const char *buf, size_t count)
978+
{
979+
u64 val;
980+
int ret;
981+
982+
ret = kstrtou64(buf, 0, &val);
983+
if (ret)
984+
return ret;
985+
986+
ret = cppc_set_perf_limited(policy->cpu, val);
987+
if (ret)
988+
return ret;
989+
990+
return count;
991+
}
992+
960993
cpufreq_freq_attr_ro(freqdomain_cpus);
961994
cpufreq_freq_attr_rw(auto_select);
962995
cpufreq_freq_attr_rw(auto_act_window);
963996
cpufreq_freq_attr_rw(energy_performance_preference_val);
997+
cpufreq_freq_attr_rw(perf_limited);
964998

965999
static struct freq_attr *cppc_cpufreq_attr[] = {
9661000
&freqdomain_cpus,
9671001
&auto_select,
9681002
&auto_act_window,
9691003
&energy_performance_preference_val,
1004+
&perf_limited,
9701005
NULL,
9711006
};
9721007

include/acpi/cppc_acpi.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141

4242
#define CPPC_ENERGY_PERF_MAX (0xFF)
4343

44+
#define CPPC_PERF_LIMITED_DESIRED_EXCURSION BIT(0)
45+
#define CPPC_PERF_LIMITED_MINIMUM_EXCURSION BIT(1)
46+
#define CPPC_PERF_LIMITED_MASK (CPPC_PERF_LIMITED_DESIRED_EXCURSION | \
47+
CPPC_PERF_LIMITED_MINIMUM_EXCURSION)
48+
4449
/* Each register has the folowing format. */
4550
struct cpc_reg {
4651
u8 descriptor;
@@ -172,6 +177,8 @@ extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window);
172177
extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window);
173178
extern int cppc_get_auto_sel(int cpu, bool *enable);
174179
extern int cppc_set_auto_sel(int cpu, bool enable);
180+
extern int cppc_get_perf_limited(int cpu, u64 *perf_limited);
181+
extern int cppc_set_perf_limited(int cpu, u64 bits_to_clear);
175182
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
176183
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
177184
extern int amd_detect_prefcore(bool *detected);
@@ -264,6 +271,14 @@ static inline int cppc_set_auto_sel(int cpu, bool enable)
264271
{
265272
return -EOPNOTSUPP;
266273
}
274+
static inline int cppc_get_perf_limited(int cpu, u64 *perf_limited)
275+
{
276+
return -EOPNOTSUPP;
277+
}
278+
static inline int cppc_set_perf_limited(int cpu, u64 bits_to_clear)
279+
{
280+
return -EOPNOTSUPP;
281+
}
267282
static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
268283
{
269284
return -ENODEV;

0 commit comments

Comments
 (0)