* [PATCH v2 1/6] cpufreq: intel_pstate: Fix setting minimum P-state at init time
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
@ 2026-06-19 17:32 ` Rafael J. Wysocki
2026-06-19 17:35 ` [PATCH v2 2/6] cpufreq: intel_pstate: Introduce intel_pstate_update_freq_limits() Rafael J. Wysocki
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-06-19 17:32 UTC (permalink / raw)
To: Linux PM; +Cc: LKML, Srinivas Pandruvada
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
If HWP is enabled, writes to MSR_IA32_PERF_CTL have no effect,
so intel_pstate_get_cpu_pstates() should not attempt to call
intel_pstate_set_min_pstate() to set the minimum P-state for the
given CPU in that case.
Accordingly, remove the intel_pstate_set_min_pstate()
call from intel_pstate_get_cpu_pstates() and make both
intel_pstate_cpu_init() and intel_cpufreq_cpu_init() call
that function in their non-HWP code paths.
The HWP code path in intel_pstate_cpu_init() does not need to update
the current P-state of the CPU directly at all because it is taken
care of the processor automatically, but the HWP code path of
intel_cpufreq_cpu_init() should update it in principle to
initialize the DESIRED_PERF field in MSR_HWP_REQUEST. For this
purpose, make it call intel_cpufreq_hwp_update() and pass
the minimum P-state limit to it as the current target value along
with the current minimum and maximum limits.
Fixes: f6ebbcf08f37 ("cpufreq: intel_pstate: Implement passive mode with HWP enabled")
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2: No changes
---
drivers/cpufreq/intel_pstate.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -2352,8 +2352,6 @@ static void intel_pstate_get_cpu_pstates
if (pstate_funcs.get_vid)
pstate_funcs.get_vid(cpu);
-
- intel_pstate_set_min_pstate(cpu);
}
/*
@@ -3059,6 +3057,7 @@ static int __intel_pstate_cpu_init(struc
static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
{
int ret = __intel_pstate_cpu_init(policy);
+ struct cpudata *cpu;
if (ret)
return ret;
@@ -3069,11 +3068,11 @@ static int intel_pstate_cpu_init(struct
*/
policy->policy = CPUFREQ_POLICY_POWERSAVE;
- if (hwp_active) {
- struct cpudata *cpu = all_cpu_data[policy->cpu];
-
+ cpu = all_cpu_data[policy->cpu];
+ if (hwp_active)
cpu->epp_cached = intel_pstate_get_epp(cpu, 0);
- }
+ else
+ intel_pstate_set_min_pstate(cpu);
return 0;
}
@@ -3304,8 +3303,6 @@ static int intel_cpufreq_cpu_init(struct
return ret;
policy->cpuinfo.transition_latency = INTEL_CPUFREQ_TRANSITION_LATENCY;
- /* This reflects the intel_pstate_get_cpu_pstates() setting. */
- policy->cur = policy->cpuinfo.min_freq;
req = kzalloc_objs(*req, 2);
if (!req) {
@@ -3326,9 +3323,15 @@ static int intel_cpufreq_cpu_init(struct
WRITE_ONCE(cpu->hwp_req_cached, value);
cpu->epp_cached = intel_pstate_get_epp(cpu, value);
+
+ intel_cpufreq_hwp_update(cpu, cpu->pstate.min_pstate,
+ cpu->pstate.max_pstate,
+ cpu->pstate.min_pstate, false);
} else {
policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY;
+ intel_pstate_set_min_pstate(cpu);
}
+ policy->cur = policy->cpuinfo.min_freq;
freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.min_perf_pct, 100);
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v2 2/6] cpufreq: intel_pstate: Introduce intel_pstate_update_freq_limits()
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
2026-06-19 17:32 ` [PATCH v2 1/6] cpufreq: intel_pstate: Fix setting minimum P-state at init time Rafael J. Wysocki
@ 2026-06-19 17:35 ` Rafael J. Wysocki
2026-06-19 17:40 ` [PATCH v2 3/6] cpufreq: intel_pstate: Set initial scaling_min_freq value Rafael J. Wysocki
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-06-19 17:35 UTC (permalink / raw)
To: Linux PM; +Cc: LKML, Srinivas Pandruvada
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Introduce a new helper function, intel_pstate_update_freq_limits(),
for updating the max and turbo frequency values for the given CPU after
updating the corresponding P-states.
Use it in intel_pstate_get_hwp_cap() and intel_pstate_get_cpu_pstates(),
in the latter case instead of the direct updates of the max and turbo
frequency values in intel_pstate_hybrid_hwp_adjust().
No intentional functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2: New patch
---
drivers/cpufreq/intel_pstate.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -587,11 +587,6 @@ static void intel_pstate_hybrid_hwp_adju
hwp_is_hybrid = true;
- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_pstate * scaling,
- perf_ctl_scaling);
- cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling,
- perf_ctl_scaling);
-
freq = perf_ctl_max_phys * perf_ctl_scaling;
cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
@@ -1181,6 +1176,22 @@ static bool hybrid_clear_max_perf_cpu(vo
return ret;
}
+static void intel_pstate_update_freq_limits(struct cpudata *cpu)
+{
+ int scaling = cpu->pstate.scaling;
+ unsigned int turbo_freq = cpu->pstate.turbo_pstate * scaling;
+ unsigned int max_freq = cpu->pstate.max_pstate * scaling;
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+
+ if (scaling != perf_ctl_scaling) {
+ turbo_freq = rounddown(turbo_freq, perf_ctl_scaling);
+ max_freq = rounddown(max_freq, perf_ctl_scaling);
+ }
+
+ cpu->pstate.turbo_freq = turbo_freq;
+ cpu->pstate.max_freq = max_freq;
+}
+
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
{
u64 cap;
@@ -1193,20 +1204,8 @@ static void __intel_pstate_get_hwp_cap(s
static void intel_pstate_get_hwp_cap(struct cpudata *cpu)
{
- int scaling = cpu->pstate.scaling;
-
__intel_pstate_get_hwp_cap(cpu);
-
- cpu->pstate.max_freq = cpu->pstate.max_pstate * scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * scaling;
- if (scaling != cpu->pstate.perf_ctl_scaling) {
- int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
-
- cpu->pstate.max_freq = rounddown(cpu->pstate.max_freq,
- perf_ctl_scaling);
- cpu->pstate.turbo_freq = rounddown(cpu->pstate.turbo_freq,
- perf_ctl_scaling);
- }
+ intel_pstate_update_freq_limits(cpu);
}
static void hybrid_update_capacity(struct cpudata *cpu)
@@ -2327,6 +2326,7 @@ static void intel_pstate_get_cpu_pstates
if (pstate_funcs.get_cpu_scaling) {
cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpu->cpu);
intel_pstate_hybrid_hwp_adjust(cpu);
+ intel_pstate_update_freq_limits(cpu);
} else {
cpu->pstate.scaling = perf_ctl_scaling;
}
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v2 3/6] cpufreq: intel_pstate: Set initial scaling_min_freq value
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
2026-06-19 17:32 ` [PATCH v2 1/6] cpufreq: intel_pstate: Fix setting minimum P-state at init time Rafael J. Wysocki
2026-06-19 17:35 ` [PATCH v2 2/6] cpufreq: intel_pstate: Introduce intel_pstate_update_freq_limits() Rafael J. Wysocki
@ 2026-06-19 17:40 ` Rafael J. Wysocki
2026-06-19 17:42 ` [PATCH v2 4/6] cpufreq: intel_pstate: Consolidate frequency values computation Rafael J. Wysocki
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-06-19 17:40 UTC (permalink / raw)
To: Linux PM; +Cc: LKML, Srinivas Pandruvada
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Currently, intel_pstate sets cpuinfo_min_freq to the minimum P-state
value retrieved from MSR_PLATFORM_INFO (bits 40:47) which prevents users
from setting scaling_min_freq below it. However, there are systems
where CPUs may actually run at P-states below that limit and the power
of the processor is then lower than when they run at the limit P-state,
even though running them at the limit P-state may still be more
energy-efficient.
To allow users to utilize the low P-states in question, notice that when
HWP is enabled, the LOWEST_PERF value from MSR_HWP_CAPABILITIES can be
used for setting cpuinfo_min_freq instead of the minimum P-state value
mentioned above, but in order to preserve the default behavior, use the
observation that after commit 8c83947c5dbb ("cpufreq: Use policy->min/max
init as QoS request"), cpufreq drivers can request the initial
scaling_min_freq values above cpuinfo_min_freq by setting policy->min to
those values in their .init() callbacks.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2:
* Rely on intel_pstate_update_freq_limits() to update the cached frequency
values and modify it to take the min frequency into account (based on
Sashiko feedback:
https://sashiko.dev/#/patchset/2381464.iZASKD2KPV%40rafael.j.wysocki)
* Minor tweaks in the changelog
---
drivers/cpufreq/intel_pstate.c | 32 ++++++++++++++++++++------------
1 file changed, 20 insertions(+), 12 deletions(-)
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -589,14 +589,6 @@ static void intel_pstate_hybrid_hwp_adju
freq = perf_ctl_max_phys * perf_ctl_scaling;
cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
-
- freq = cpu->pstate.min_pstate * perf_ctl_scaling;
- cpu->pstate.min_freq = freq;
- /*
- * Cast the min P-state value retrieved via pstate_funcs.get_min() to
- * the effective range of HWP performance levels.
- */
- cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq);
}
static bool turbo_is_disabled(void)
@@ -1181,15 +1173,21 @@ static void intel_pstate_update_freq_lim
int scaling = cpu->pstate.scaling;
unsigned int turbo_freq = cpu->pstate.turbo_pstate * scaling;
unsigned int max_freq = cpu->pstate.max_pstate * scaling;
+ unsigned int min_freq = cpu->pstate.min_pstate * scaling;
int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
if (scaling != perf_ctl_scaling) {
turbo_freq = rounddown(turbo_freq, perf_ctl_scaling);
max_freq = rounddown(max_freq, perf_ctl_scaling);
+ if (min_freq > perf_ctl_scaling)
+ min_freq = rounddown(min_freq, perf_ctl_scaling);
+ else
+ min_freq = perf_ctl_scaling;
}
cpu->pstate.turbo_freq = turbo_freq;
cpu->pstate.max_freq = max_freq;
+ cpu->pstate.min_freq = min_freq;
}
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
@@ -1198,6 +1196,7 @@ static void __intel_pstate_get_hwp_cap(s
rdmsrq_on_cpu(cpu->cpu, MSR_HWP_CAPABILITIES, &cap);
WRITE_ONCE(cpu->hwp_cap_cached, cap);
+ cpu->pstate.min_pstate = HWP_LOWEST_PERF(cap);
cpu->pstate.max_pstate = HWP_GUARANTEED_PERF(cap);
cpu->pstate.turbo_pstate = HWP_HIGHEST_PERF(cap);
}
@@ -2317,7 +2316,6 @@ static void intel_pstate_get_cpu_pstates
int perf_ctl_scaling = pstate_funcs.get_scaling();
cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical(cpu->cpu);
- cpu->pstate.min_pstate = pstate_funcs.get_min(cpu->cpu);
cpu->pstate.perf_ctl_scaling = perf_ctl_scaling;
if (hwp_active && !hwp_mode_bdw) {
@@ -2337,6 +2335,7 @@ static void intel_pstate_get_cpu_pstates
hybrid_update_capacity(cpu);
} else {
cpu->pstate.scaling = perf_ctl_scaling;
+ cpu->pstate.min_pstate = pstate_funcs.get_min(cpu->cpu);
cpu->pstate.max_pstate = pstate_funcs.get_max(cpu->cpu);
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
}
@@ -3047,6 +3046,13 @@ static int __intel_pstate_cpu_init(struc
policy->cpuinfo.max_freq = READ_ONCE(global.no_turbo) ?
cpu->pstate.max_freq : cpu->pstate.turbo_freq;
+ /*
+ * If policy->min is greater than policy->cpuinfo.min_freq, the cpufreq
+ * core will use this value for initializing scaling_min_freq.
+ */
+ if (hwp_active)
+ policy->min = pstate_funcs.get_min(cpu->cpu) * cpu->pstate.perf_ctl_scaling;
+
intel_pstate_init_acpi_perf_limits(policy);
policy->fast_switch_possible = true;
@@ -3313,6 +3319,7 @@ static int intel_cpufreq_cpu_init(struct
cpu = all_cpu_data[policy->cpu];
if (hwp_active) {
+ unsigned int hwp;
u64 value;
policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY_HWP;
@@ -3324,14 +3331,15 @@ static int intel_cpufreq_cpu_init(struct
cpu->epp_cached = intel_pstate_get_epp(cpu, value);
+ hwp = intel_pstate_freq_to_hwp(cpu, policy->min);
intel_cpufreq_hwp_update(cpu, cpu->pstate.min_pstate,
- cpu->pstate.max_pstate,
- cpu->pstate.min_pstate, false);
+ cpu->pstate.max_pstate, hwp, false);
+ policy->cur = policy->min;
} else {
policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY;
intel_pstate_set_min_pstate(cpu);
+ policy->cur = policy->cpuinfo.min_freq;
}
- policy->cur = policy->cpuinfo.min_freq;
freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.min_perf_pct, 100);
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v2 4/6] cpufreq: intel_pstate: Consolidate frequency values computation
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
` (2 preceding siblings ...)
2026-06-19 17:40 ` [PATCH v2 3/6] cpufreq: intel_pstate: Set initial scaling_min_freq value Rafael J. Wysocki
@ 2026-06-19 17:42 ` Rafael J. Wysocki
2026-06-19 17:44 ` [PATCH v2 5/6] cpufreq: intel_pstate: Consolidate HWP P-states initialization Rafael J. Wysocki
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-06-19 17:42 UTC (permalink / raw)
To: Linux PM; +Cc: LKML, Srinivas Pandruvada
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Update intel_pstate_get_cpu_pstates() to use
intel_pstate_update_freq_limits() for computing the max and
turbo frequency values in all cases, including non-hybrid HWP
and HWP disabled.
No intentional functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2: New patch
---
drivers/cpufreq/intel_pstate.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -2324,7 +2324,6 @@ static void intel_pstate_get_cpu_pstates
if (pstate_funcs.get_cpu_scaling) {
cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpu->cpu);
intel_pstate_hybrid_hwp_adjust(cpu);
- intel_pstate_update_freq_limits(cpu);
} else {
cpu->pstate.scaling = perf_ctl_scaling;
}
@@ -2340,11 +2339,7 @@ static void intel_pstate_get_cpu_pstates
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
}
- if (cpu->pstate.scaling == perf_ctl_scaling) {
- cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling;
- cpu->pstate.max_freq = cpu->pstate.max_pstate * perf_ctl_scaling;
- cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * perf_ctl_scaling;
- }
+ intel_pstate_update_freq_limits(cpu);
if (pstate_funcs.get_aperf_mperf_shift)
cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v2 5/6] cpufreq: intel_pstate: Consolidate HWP P-states initialization
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
` (3 preceding siblings ...)
2026-06-19 17:42 ` [PATCH v2 4/6] cpufreq: intel_pstate: Consolidate frequency values computation Rafael J. Wysocki
@ 2026-06-19 17:44 ` Rafael J. Wysocki
2026-06-19 17:45 ` [PATCH v2 6/6] cpufreq: intel_pstate: Move two functions closer to callers Rafael J. Wysocki
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-06-19 17:44 UTC (permalink / raw)
To: Linux PM; +Cc: LKML, Srinivas Pandruvada
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
After previous changes, intel_pstate_hybrid_hwp_adjust() does not do
much and its name and kerneldoc comment (which is not really necessary
becuase the function is static) have become a bit confusing. Moreover,
the initialization of P-states on systems with HWP enabled is divided
between it and a direct conditional statement branch in
intel_pstate_get_cpu_pstates() which is not super-easy to follow.
Address this by introducing intel_pstate_get_hwp_pstates() for the
entire HWP-specific initialization of P-states and moving the code from
intel_pstate_hybrid_hwp_adjust() into it along with some HWP-related
code from intel_pstate_get_cpu_pstates().
No intentional functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2: New patch
---
drivers/cpufreq/intel_pstate.c | 103 +++++++++++++++++++----------------------
1 file changed, 50 insertions(+), 53 deletions(-)
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -556,41 +556,6 @@ static int intel_pstate_freq_to_hwp(stru
return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L);
}
-/**
- * intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels.
- * @cpu: Target CPU.
- *
- * On hybrid processors, HWP may expose more performance levels than there are
- * P-states accessible through the PERF_CTL interface. If that happens, the
- * scaling factor between HWP performance levels and CPU frequency will be less
- * than the scaling factor between P-state values and CPU frequency.
- *
- * In that case, adjust the CPU parameters used in computations accordingly.
- */
-static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu)
-{
- int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
- int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
- int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu);
- int scaling = cpu->pstate.scaling;
- int freq;
-
- pr_debug("CPU%d: PERF_CTL max_phys = %d\n", cpu->cpu, perf_ctl_max_phys);
- pr_debug("CPU%d: PERF_CTL turbo = %d\n", cpu->cpu, perf_ctl_turbo);
- pr_debug("CPU%d: PERF_CTL scaling = %d\n", cpu->cpu, perf_ctl_scaling);
- pr_debug("CPU%d: HWP_CAP guaranteed = %d\n", cpu->cpu, cpu->pstate.max_pstate);
- pr_debug("CPU%d: HWP_CAP highest = %d\n", cpu->cpu, cpu->pstate.turbo_pstate);
- pr_debug("CPU%d: HWP-to-frequency scaling factor: %d\n", cpu->cpu, scaling);
-
- if (scaling == perf_ctl_scaling)
- return;
-
- hwp_is_hybrid = true;
-
- freq = perf_ctl_max_phys * perf_ctl_scaling;
- cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq);
-}
-
static bool turbo_is_disabled(void)
{
u64 misc_en;
@@ -2311,32 +2276,64 @@ static void intel_pstate_set_min_pstate(
intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
}
-static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
+static void intel_pstate_get_hwp_pstates(struct cpudata *cpu)
{
- int perf_ctl_scaling = pstate_funcs.get_scaling();
+ int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
+ int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling;
+ int perf_ctl_turbo = cpu->pstate.turbo_pstate;
+ int cpuid = cpu->cpu;
+
+ __intel_pstate_get_hwp_cap(cpu);
+
+ if (!pstate_funcs.get_cpu_scaling)
+ return;
+ pr_debug("CPU%d: PERF_CTL max_phys = %d\n", cpuid, perf_ctl_max_phys);
+ pr_debug("CPU%d: PERF_CTL turbo = %d\n", cpuid, perf_ctl_turbo);
+ pr_debug("CPU%d: PERF_CTL scaling = %d\n", cpuid, perf_ctl_scaling);
+ pr_debug("CPU%d: HWP_CAP lowest = %d\n", cpuid, cpu->pstate.min_pstate);
+ pr_debug("CPU%d: HWP_CAP guaranteed = %d\n", cpuid, cpu->pstate.max_pstate);
+ pr_debug("CPU%d: HWP_CAP highest = %d\n", cpuid, cpu->pstate.turbo_pstate);
+
+ cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpuid);
+
+ pr_debug("CPU%d: HWP-to-frequency scaling = %d\n", cpuid, cpu->pstate.scaling);
+
+ /*
+ * On hybrid processors, HWP may expose more performance levels than
+ * there are P-states accessible through the PERF_CTL interface. If
+ * that happens, the scaling between HWP performance levels and CPU
+ * frequency will be less than the scaling between P-state values and
+ * CPU frequency. In that case, update the maximum physical non-turbo
+ * performance level accordingly.
+ */
+ if (cpu->pstate.scaling != perf_ctl_scaling) {
+ int freq = perf_ctl_max_phys * perf_ctl_scaling;
+ unsigned int hwp = intel_pstate_freq_to_hwp(cpu, freq);
+
+ cpu->pstate.max_pstate_physical = hwp;
+
+ hwp_is_hybrid = true;
+ }
+ /*
+ * If the CPU is going online for the first time and it was offline
+ * initially, asym capacity scaling needs to be updated.
+ */
+ hybrid_update_capacity(cpu);
+}
+
+static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
+{
cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical(cpu->cpu);
- cpu->pstate.perf_ctl_scaling = perf_ctl_scaling;
+ cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
+ cpu->pstate.perf_ctl_scaling = pstate_funcs.get_scaling();
+ cpu->pstate.scaling = cpu->pstate.perf_ctl_scaling;
if (hwp_active && !hwp_mode_bdw) {
- __intel_pstate_get_hwp_cap(cpu);
-
- if (pstate_funcs.get_cpu_scaling) {
- cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpu->cpu);
- intel_pstate_hybrid_hwp_adjust(cpu);
- } else {
- cpu->pstate.scaling = perf_ctl_scaling;
- }
- /*
- * If the CPU is going online for the first time and it was
- * offline initially, asym capacity scaling needs to be updated.
- */
- hybrid_update_capacity(cpu);
+ intel_pstate_get_hwp_pstates(cpu);
} else {
- cpu->pstate.scaling = perf_ctl_scaling;
cpu->pstate.min_pstate = pstate_funcs.get_min(cpu->cpu);
cpu->pstate.max_pstate = pstate_funcs.get_max(cpu->cpu);
- cpu->pstate.turbo_pstate = pstate_funcs.get_turbo(cpu->cpu);
}
intel_pstate_update_freq_limits(cpu);
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v2 6/6] cpufreq: intel_pstate: Move two functions closer to callers
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
` (4 preceding siblings ...)
2026-06-19 17:44 ` [PATCH v2 5/6] cpufreq: intel_pstate: Consolidate HWP P-states initialization Rafael J. Wysocki
@ 2026-06-19 17:45 ` Rafael J. Wysocki
2026-06-21 21:50 ` [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups srinivas pandruvada
2026-06-21 23:34 ` Doug Smythies
7 siblings, 0 replies; 9+ messages in thread
From: Rafael J. Wysocki @ 2026-06-19 17:45 UTC (permalink / raw)
To: Linux PM; +Cc: LKML, Srinivas Pandruvada
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Move intel_pstate_set_pstate() and intel_pstate_set_min_pstate() that
are not used on systems with HWP enabled, closer to their first
callers.
No functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2: New patch
---
drivers/cpufreq/intel_pstate.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -2258,24 +2258,6 @@ static int hwp_get_cpu_scaling(int cpu)
return intel_pstate_cppc_get_scaling(cpu);
}
-static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
-{
- trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
- cpu->pstate.current_pstate = pstate;
- /*
- * Generally, there is no guarantee that this code will always run on
- * the CPU being updated, so force the register update to run on the
- * right CPU.
- */
- wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL,
- pstate_funcs.get_val(cpu, pstate));
-}
-
-static void intel_pstate_set_min_pstate(struct cpudata *cpu)
-{
- intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
-}
-
static void intel_pstate_get_hwp_pstates(struct cpudata *cpu)
{
int perf_ctl_max_phys = cpu->pstate.max_pstate_physical;
@@ -2869,6 +2851,19 @@ static void intel_pstate_update_perf_lim
cpu->min_perf_ratio);
}
+static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
+{
+ trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
+ cpu->pstate.current_pstate = pstate;
+ /*
+ * Generally, there is no guarantee that this code will always run on
+ * the CPU being updated, so force the register update to run on the
+ * right CPU.
+ */
+ wrmsrq_on_cpu(cpu->cpu, MSR_IA32_PERF_CTL,
+ pstate_funcs.get_val(cpu, pstate));
+}
+
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
{
struct cpudata *cpu;
@@ -2956,6 +2951,11 @@ static int intel_pstate_verify_policy(st
return 0;
}
+static void intel_pstate_set_min_pstate(struct cpudata *cpu)
+{
+ intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
+}
+
static int intel_cpufreq_cpu_offline(struct cpufreq_policy *policy)
{
struct cpudata *cpu = all_cpu_data[policy->cpu];
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
` (5 preceding siblings ...)
2026-06-19 17:45 ` [PATCH v2 6/6] cpufreq: intel_pstate: Move two functions closer to callers Rafael J. Wysocki
@ 2026-06-21 21:50 ` srinivas pandruvada
2026-06-21 23:34 ` Doug Smythies
7 siblings, 0 replies; 9+ messages in thread
From: srinivas pandruvada @ 2026-06-21 21:50 UTC (permalink / raw)
To: Rafael J. Wysocki, Linux PM; +Cc: LKML
On Fri, 2026-06-19 at 19:31 +0200, Rafael J. Wysocki wrote:
> Hi,
>
> This is in v2 because technically it is an update of
>
> https://lore.kernel.org/linux-pm/2381464.iZASKD2KPV@rafael.j.wysocki/
>
> but it contains new patches.
>
> This series updates the intel_pstate driver to set cpuinfo_min_freq
> to a lower
> value when HWP is enabled to support systems in which CPUs can
> actually run
> at performance levels below the current minimum level.
>
Is this intentional?
HWP_CAP: 0x10f163e
MSR 0xce(platform_info: 0x804043df8811b00
cpu0/cpufreq/cpuinfo_min_freq
100000
cpu0/cpufreq/scaling_min_freq
400000
Thanks,
Srinivas
> It also carries out some code cleanups, mostly related to HWP, either
> in
> preparation for the functional changes or top of them.
>
> Thanks!
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread* RE: [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups
2026-06-19 17:31 [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups Rafael J. Wysocki
` (6 preceding siblings ...)
2026-06-21 21:50 ` [PATCH v2 0/6] cpufreq: intel_pstate: Set cpuinfo_min_freq to a lower value with HWP enabled plus cleanups srinivas pandruvada
@ 2026-06-21 23:34 ` Doug Smythies
7 siblings, 0 replies; 9+ messages in thread
From: Doug Smythies @ 2026-06-21 23:34 UTC (permalink / raw)
To: 'Rafael J. Wysocki', 'Linux PM'
Cc: 'LKML', 'Srinivas Pandruvada'
On 2026.06.19 10:32 Rafael wrote:
> This is in v2 because technically it is an update of
>
> https://lore.kernel.org/linux-pm/2381464.iZASKD2KPV@rafael.j.wysocki/
>
> but it contains new patches.
>
> This series updates the intel_pstate driver to set cpuinfo_min_freq to a lower
> value when HWP is enabled to support systems in which CPUs can actually run
> at performance levels below the current minimum level.
>
> It also carries out some code cleanups, mostly related to HWP, either in
> preparation for the functional changes or top of them.
>
> Thanks!
Hi Rafael,
Is there a way to test this? I have tried everything I can think of and have
been unable to get the processor frequency below the old minimum of 800 MHz.
No matter what I do, I always see greater or equal to 8 for each CPU in the
IA32_PERF_STATUS register, or by looking at non stale entries in:
grep . /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
Example:
doug@s19:~$ grep . /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu10/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu11/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq:800013
/sys/devices/system/cpu/cpu2/cpufreq/scaling_cur_freq:800014
/sys/devices/system/cpu/cpu3/cpufreq/scaling_cur_freq:799996
/sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq:800023
/sys/devices/system/cpu/cpu5/cpufreq/scaling_cur_freq:800053
/sys/devices/system/cpu/cpu6/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu7/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu8/cpufreq/scaling_cur_freq:100000
/sys/devices/system/cpu/cpu9/cpufreq/scaling_cur_freq:100000
Readers note:
Stale entries are just "scaling_min_freq".
Non-stale entries tend to be not nice round numbers.
For me this patch set introduces confusion between min and max
frequency settings and what I actually get. I can set " scaling_min_freq"
to 100 MHz and "scaling_max_freq" to 100MHz, but never get them.
Before this patch set, I always got what I asked for.
Other details:
Processor: Intel(R) Core(TM) i5-10600K CPU @ 4.10GHz
MSR_PLATFORM_INFO (0x0ce) 808083af1012900
Other stuff from my msr0decoder program:
doug@s19:~$ sudo c/msr-decoder
How many CPUs?: 12
8.) 0x198: IA32_PERF_STATUS : CPU 11-0 : 8 : 8 : 8 : 8 : 8 : 8 : 8 : 8 : 8 : 8 : 8 : 8 :
B.) 0x770: IA32_PM_ENABLE: 1 : HWP enable
1.) 0x19C: IA32_THERM_STATUS: 88470000
2.) 0x1AA: MSR_MISC_PWR_MGMT: 401CC0 EIST enabled Coordination enabled OOB Bit 8 reset OOB Bit 18 reset
3.) 0x1B1: IA32_PACKAGE_THERM_STATUS: 88450000
4.) 0x64F: MSR_CORE_PERF_LIMIT_REASONS: 200000 RATLL
A.) 0x1FC: MSR_POWER_CTL: 3C005D : C1E disable : EEO disable : RHO disable
5.) 0x771: IA32_HWP_CAPABILITIES (performance): 10B2930 : high 48 : guaranteed 41 : efficient 11 : lowest 1
6.) 0x774: IA32_HWP_REQUEST: CPU 11-0 :
raw: 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 : 80010101 :
min: 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 :
max: 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 :
des: 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 : 1 :
epp: 128 : 128 : 128 : 128 : 128 : 128 : 128 : 128 : 128 : 128 : 128 : 128 :
act: 0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 : 0 :
7.) 0x777: IA32_HWP_STATUS: 0 : high 0 : guaranteed 0 : efficient 0 : lowest 0
The driver was intel_cpufreq, governor conservative (but I tried them all). I also tried epp = 255 so as to slow down the processor response time.
... Doug
^ permalink raw reply [flat|nested] 9+ messages in thread