Power management fixes for 6.17-rc3

- Prevent the menu cpuidle governor from selecting idle states with
    exit latency exceeding the current PM QoS limit after stopping the
    scheduler tick (Rafael Wysocki)
 
  - Make the set subcommand's -t option in the cpupower utility work as
    documented and allow it to control the CPU boost feature of cpufreq
    beyond x86 (Shinji Nomoto)
 -----BEGIN PGP SIGNATURE-----
 
 iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAminaMASHHJqd0Byand5
 c29ja2kubmV0AAoJEO5fvZ0v1OO18vwH/1LQoO0ibu40yBpfjVemwuNGn4jrFV1i
 lDnZ03njFGaZ01abjDEeNdggHCRybCmqWVQArEMGzWqCUGo/zmWzyi5apXic6d1A
 qSMvFfoZHXdExa2+nm4OHcSCFAHrz+81ACyWlTuObhoPGqo2Mvu/hf2e2kn7uPOG
 /HQE1E5sYqLaqBxLhQAfPU7CyfXiM2LL/8Fv7420Z5I85Tx9z6cHa7sUgrNveJxP
 BrEm9u9dRKKc/tHL0RGsdCf7Ddff9jF/npjJ0965eSNwJh6Wr3HbcGOKyQcI3Xjx
 S+UxijVz1CuZwMmyRHibYj+HV+fsYHbU6G9wQpez5wJBlHNbnI1/kzE=
 =DhR+
 -----END PGP SIGNATURE-----

Merge tag 'pm-6.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management fixes from Rafael Wysocki:
 "These fix a cpuidle menu governor issue and two issues in the cpupower
  utility:

   - Prevent the menu cpuidle governor from selecting idle states with
     exit latency exceeding the current PM QoS limit after stopping the
     scheduler tick (Rafael Wysocki)

   - Make the set subcommand's -t option in the cpupower utility work as
     documented and allow it to control the CPU boost feature of cpufreq
     beyond x86 (Shinji Nomoto)"

* tag 'pm-6.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  cpuidle: governors: menu: Avoid selecting states with too much latency
  cpupower: Allow control of boost feature on non-x86 based systems with boost support.
  cpupower: Fix a bug where the -t option of the set subcommand was not working.
This commit is contained in:
Linus Torvalds 2025-08-21 16:04:58 -04:00
commit 26d6ed49cd
6 changed files with 95 additions and 52 deletions

View File

@ -287,20 +287,15 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
return 0;
}
if (tick_nohz_tick_stopped()) {
/*
* If the tick is already stopped, the cost of possible short
* idle duration misprediction is much higher, because the CPU
* may be stuck in a shallow idle state for a long time as a
* result of it. In that case say we might mispredict and use
* the known time till the closest timer event for the idle
* state selection.
*/
if (predicted_ns < TICK_NSEC)
predicted_ns = data->next_timer_ns;
} else if (latency_req > predicted_ns) {
latency_req = predicted_ns;
}
/*
* If the tick is already stopped, the cost of possible short idle
* duration misprediction is much higher, because the CPU may be stuck
* in a shallow idle state for a long time as a result of it. In that
* case, say we might mispredict and use the known time till the closest
* timer event for the idle state selection.
*/
if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC)
predicted_ns = data->next_timer_ns;
/*
* Find the idle state with the lowest power while satisfying
@ -316,13 +311,15 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
if (idx == -1)
idx = i; /* first enabled state */
if (s->exit_latency_ns > latency_req)
break;
if (s->target_residency_ns > predicted_ns) {
/*
* Use a physical idle state, not busy polling, unless
* a timer is going to trigger soon enough.
*/
if ((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) &&
s->exit_latency_ns <= latency_req &&
s->target_residency_ns <= data->next_timer_ns) {
predicted_ns = s->target_residency_ns;
idx = i;
@ -354,8 +351,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
return idx;
}
if (s->exit_latency_ns > latency_req)
break;
idx = i;
}

View File

@ -81,10 +81,11 @@ Refer to the AMD P-State kernel documentation for further information.
.RE
.PP
\-\-turbo\-boost, \-t
\-\-turbo\-boost, \-\-boost, \-t
.RS 4
This option is used to enable or disable the turbo boost feature on
supported Intel and AMD processors.
This option is used to enable or disable the boost feature on
supported Intel and AMD processors, and other boost supported systems.
(The --boost option is an alias for the --turbo-boost option)
This option takes as parameter either \fB1\fP to enable, or \fB0\fP to disable the feature.

View File

@ -128,7 +128,7 @@ static int get_boost_mode_x86(unsigned int cpu)
/* ToDo: Make this more global */
unsigned long pstates[MAX_HW_PSTATES] = {0,};
ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
ret = cpufreq_has_x86_boost_support(cpu, &support, &active, &b_states);
if (ret) {
printf(_("Error while evaluating Boost Capabilities"
" on CPU %d -- are you root?\n"), cpu);
@ -204,6 +204,18 @@ static int get_boost_mode_x86(unsigned int cpu)
return 0;
}
static int get_boost_mode_generic(unsigned int cpu)
{
bool active;
if (!cpufreq_has_generic_boost_support(&active)) {
printf(_(" boost state support:\n"));
printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
}
return 0;
}
/* --boost / -b */
static int get_boost_mode(unsigned int cpu)
@ -214,6 +226,8 @@ static int get_boost_mode(unsigned int cpu)
cpupower_cpu_info.vendor == X86_VENDOR_HYGON ||
cpupower_cpu_info.vendor == X86_VENDOR_INTEL)
return get_boost_mode_x86(cpu);
else
get_boost_mode_generic(cpu);
freqs = cpufreq_get_boost_frequencies(cpu);
if (freqs) {

View File

@ -21,6 +21,7 @@ static struct option set_opts[] = {
{"epp", required_argument, NULL, 'e'},
{"amd-pstate-mode", required_argument, NULL, 'm'},
{"turbo-boost", required_argument, NULL, 't'},
{"boost", required_argument, NULL, 't'},
{ },
};
@ -62,8 +63,8 @@ int cmd_set(int argc, char **argv)
params.params = 0;
/* parameter parsing */
while ((ret = getopt_long(argc, argv, "b:e:m:",
set_opts, NULL)) != -1) {
while ((ret = getopt_long(argc, argv, "b:e:m:t:",
set_opts, NULL)) != -1) {
switch (ret) {
case 'b':
if (params.perf_bias)

View File

@ -103,6 +103,9 @@ extern struct cpupower_cpu_info cpupower_cpu_info;
/* cpuid and cpuinfo helpers **************************/
int cpufreq_has_generic_boost_support(bool *active);
int cpupower_set_turbo_boost(int turbo_boost);
/* X86 ONLY ****************************************/
#if defined(__i386__) || defined(__x86_64__)
@ -118,7 +121,6 @@ extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu);
extern int cpupower_set_epp(unsigned int cpu, char *epp);
extern int cpupower_set_amd_pstate_mode(char *mode);
extern int cpupower_set_turbo_boost(int turbo_boost);
/* Read/Write msr ****************************/
@ -139,8 +141,8 @@ extern int decode_pstates(unsigned int cpu, int boost_states,
/* AMD HW pstate decoding **************************/
extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
int *active, int * states);
int cpufreq_has_x86_boost_support(unsigned int cpu, int *support,
int *active, int *states);
/* AMD P-State stuff **************************/
bool cpupower_amd_pstate_enabled(void);
@ -181,13 +183,11 @@ static inline int cpupower_set_epp(unsigned int cpu, char *epp)
{ return -1; };
static inline int cpupower_set_amd_pstate_mode(char *mode)
{ return -1; };
static inline int cpupower_set_turbo_boost(int turbo_boost)
{ return -1; };
/* Read/Write msr ****************************/
static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
int *active, int * states)
static inline int cpufreq_has_x86_boost_support(unsigned int cpu, int *support,
int *active, int *states)
{ return -1; }
static inline bool cpupower_amd_pstate_enabled(void)

View File

@ -8,15 +8,14 @@
#include "helpers/helpers.h"
#include "helpers/sysfs.h"
#include "cpufreq.h"
#include "cpupower_intern.h"
#if defined(__i386__) || defined(__x86_64__)
#include "cpupower_intern.h"
#define MSR_AMD_HWCR 0xc0010015
int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active,
int *states)
int cpufreq_has_x86_boost_support(unsigned int cpu, int *support, int *active,
int *states)
{
int ret;
unsigned long long val;
@ -124,24 +123,6 @@ int cpupower_set_amd_pstate_mode(char *mode)
return 0;
}
int cpupower_set_turbo_boost(int turbo_boost)
{
char path[SYSFS_PATH_MAX];
char linebuf[2] = {};
snprintf(path, sizeof(path), PATH_TO_CPU "cpufreq/boost");
if (!is_valid_path(path))
return -1;
snprintf(linebuf, sizeof(linebuf), "%d", turbo_boost);
if (cpupower_write_sysfs(path, linebuf, 2) <= 0)
return -1;
return 0;
}
bool cpupower_amd_pstate_enabled(void)
{
char *driver = cpufreq_get_driver(0);
@ -160,6 +141,39 @@ bool cpupower_amd_pstate_enabled(void)
#endif /* #if defined(__i386__) || defined(__x86_64__) */
int cpufreq_has_generic_boost_support(bool *active)
{
char path[SYSFS_PATH_MAX];
char linebuf[2] = {};
unsigned long val;
char *endp;
snprintf(path, sizeof(path), PATH_TO_CPU "cpufreq/boost");
if (!is_valid_path(path))
return -EACCES;
if (cpupower_read_sysfs(path, linebuf, 2) <= 0)
return -EINVAL;
val = strtoul(linebuf, &endp, 0);
if (endp == linebuf || errno == ERANGE)
return -EINVAL;
switch (val) {
case 0:
*active = false;
break;
case 1:
*active = true;
break;
default:
return -EINVAL;
}
return 0;
}
/* get_cpustate
*
* Gather the information of all online CPUs into bitmask struct
@ -259,3 +273,21 @@ void print_speed(unsigned long speed, int no_rounding)
}
}
}
int cpupower_set_turbo_boost(int turbo_boost)
{
char path[SYSFS_PATH_MAX];
char linebuf[2] = {};
snprintf(path, sizeof(path), PATH_TO_CPU "cpufreq/boost");
if (!is_valid_path(path))
return -1;
snprintf(linebuf, sizeof(linebuf), "%d", turbo_boost);
if (cpupower_write_sysfs(path, linebuf, 2) <= 0)
return -1;
return 0;
}