ANDROID: Revert "cpufreq: Avoid using inconsistent policy->min and policy->max"

The combination of the cpufreq changes that came in with v6.12.28,
commit 573b04722907 ("cpufreq: Avoid using inconsistent
policy->min and policy->max") and commit 962d88304c3c ("cpufreq:
Fix setting policy limits when frequency tables are used")
unfortunately broke the KABI.

The second of which was reverted in ad2b007ef43c ("Revert
"cpufreq: Fix setting policy limits when frequency tables are
used"").

However, that change is actually a necessary fix to the first.
As the refactoring to passing the max and min through the
arguments couldn't be done without KABI impact, the
changes to be more consistent with policy->min/max ends up
introducing a subtle problem where the new max value being
set ends up being clamped to the current max value - thus
cpufreq max can be reduced but not increased (with the
min increased but not decreased).

A minimal fix of this effectively undoes the key point of
commit 573b04722907, so it seems best to revert the whole thing
for now.

I think the small pre-existing risk of the policy->max/min values
being read when shortly to an intermediate value before getting
assigned the final value seems to be less problematic in practice.

Fixes: ad2b007ef43c ("Revert "cpufreq: Fix setting policy limits when frequency tables are used"")
Bug: 428984800
Signed-off-by: John Stultz <jstultz@google.com>
Change-Id: I5a76cc2b0056071ffa26a682458df5fe0a4b83a3
This commit is contained in:
John Stultz
2025-07-06 18:08:53 +00:00
parent 5f592a6260
commit be36ded303

View File

@@ -543,6 +543,7 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy,
unsigned int idx;
unsigned int old_target_freq = target_freq;
target_freq = clamp_val(target_freq, policy->min, policy->max);
trace_android_vh_cpufreq_resolve_freq(policy, &target_freq, old_target_freq);
if (!policy->freq_table)
@@ -568,22 +569,7 @@ static unsigned int __resolve_freq(struct cpufreq_policy *policy,
unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,
unsigned int target_freq)
{
unsigned int min = READ_ONCE(policy->min);
unsigned int max = READ_ONCE(policy->max);
/*
* If this function runs in parallel with cpufreq_set_policy(), it may
* read policy->min before the update and policy->max after the update
* or the other way around, so there is no ordering guarantee.
*
* Resolve this by always honoring the max (in case it comes from
* thermal throttling or similar).
*/
if (unlikely(min > max))
min = max;
return __resolve_freq(policy, clamp_val(target_freq, min, max),
CPUFREQ_RELATION_LE);
return __resolve_freq(policy, target_freq, CPUFREQ_RELATION_LE);
}
EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq);
@@ -2369,7 +2355,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
if (cpufreq_disabled())
return -ENODEV;
target_freq = clamp_val(target_freq, policy->min, policy->max);
target_freq = __resolve_freq(policy, target_freq, relation);
trace_android_vh_cpufreq_target(policy, &target_freq, old_target_freq);
@@ -2662,15 +2647,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
* Resolve policy min/max to available frequencies. It ensures
* no frequency resolution will neither overshoot the requested maximum
* nor undershoot the requested minimum.
*
* Avoid storing intermediate values in policy->max or policy->min and
* compiler optimizations around them because they may be accessed
* concurrently by cpufreq_driver_resolve_freq() during the update.
*/
WRITE_ONCE(policy->max, __resolve_freq(policy, new_data.max, CPUFREQ_RELATION_H));
new_data.min = __resolve_freq(policy, new_data.min, CPUFREQ_RELATION_L);
WRITE_ONCE(policy->min, new_data.min > policy->max ? policy->max : new_data.min);
policy->min = new_data.min;
policy->max = new_data.max;
policy->min = __resolve_freq(policy, policy->min, CPUFREQ_RELATION_L);
policy->max = __resolve_freq(policy, policy->max, CPUFREQ_RELATION_H);
trace_cpu_frequency_limits(policy);
policy->cached_target_freq = UINT_MAX;