[PATCH] cpufreq: intel_pstate: Sync policy->cur to the pinned pstate

Jing Wu <[email protected]>
Newsgroups org.kernel.vger.linux-pm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
When cpu->policy is CPUFREQ_POLICY_PERFORMANCE, intel_pstate_set_policy()
pins the CPU to a fixed pstate (max(min_pstate, max_perf_ratio)) and
programs it directly, precisely because, per the existing comment,
"NOHZ_FULL CPUs need this as the governor callback may not be invoked
on them". Two lines later it still unconditionally clobbers policy->cur
down to policy->min, discarding the pinned value it just computed and
applied.

arch_freq_get_on_cpu() falls back to cpufreq_quick_get(), i.e.
policy->cur, whenever its APERF/MPERF sample goes stale. A CPU whose
tick keeps running refreshes that sample constantly and rarely hits
the fallback, but an isolated CPU covered by nohz_full with a single
runnable task never gets another tick, so it permanently reports the
floor through this fallback - even though it is genuinely pinned to,
and running at, the frequency computed just above.

Set policy->cur to the exact pinned frequency (pstate * scaling) in
the CPUFREQ_POLICY_PERFORMANCE branch instead, and only fall back to
policy->min for the general case, where the frequency genuinely isn't
known without a fresh sample.

Fixes: d51847acb018 ("cpufreq: intel_pstate: set stale CPU frequency to minimum")
Co-developed-by: Qiliang Yuan <[email protected]>
Signed-off-by: Qiliang Yuan <[email protected]>
Signed-off-by: Jing Wu <[email protected]>
---
 drivers/cpufreq/intel_pstate.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 5a0eeb84d3821..b2c60c4931dcd 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -2908,8 +2908,23 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
 		 */
 		intel_pstate_clear_update_util_hook(policy->cpu);
 		intel_pstate_set_pstate(cpu, pstate);
+
+		/*
+		 * Report the exact pinned frequency instead of the floor:
+		 * the CPU is pinned to pstate here and nothing else changes
+		 * it, unlike the general case below.
+		 */
+		policy->cur = pstate * cpu->pstate.scaling;
 	} else {
 		intel_pstate_set_update_util_hook(policy->cpu);
+
+		/*
+		 * Keep policy->cur within limits here: outside of the pinned
+		 * CPUFREQ_POLICY_PERFORMANCE case above, it is never updated
+		 * by the intel_pstate driver, but it is used as a stale
+		 * frequency value.
+		 */
+		policy->cur = policy->min;
 	}
 
 	if (hwp_active) {
@@ -2922,11 +2937,6 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
 			intel_pstate_clear_update_util_hook(policy->cpu);
 		intel_pstate_hwp_set(policy->cpu);
 	}
-	/*
-	 * policy->cur is never updated with the intel_pstate driver, but it
-	 * is used as a stale frequency value. So, keep it within limits.
-	 */
-	policy->cur = policy->min;
 
 	mutex_unlock(&intel_pstate_limits_lock);
 

---
base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
change-id: 20260729-bug-intel-pstate-policy-cur-1e1498a56641

Best regards,
-- 
Jing Wu <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.