Skip to content

cpufreq: apple: keep T8140 policy->cur in step with the cluster - #239

Merged
DjDeveloperr merged 1 commit into
integration/aurorafrom
neo/t8140-cpufreq-policy-cur-20261026
Oct 26, 2026
Merged

DjDeveloperr merged 1 commit into
integration/aurorafrom
neo/t8140-cpufreq-policy-cur-20261026

Conversation

@DjDeveloperr

Copy link
Copy Markdown
Collaborator

Summary

This is a follow-up to #227, merged as 98ef5ae, for the hole maralcbr found in its last review.

The fast die-temperature limit moves a lazy_verify cluster without a scheduler request. It lowers a request above a new limit, and it restores the scheduler's request when the limit rises again before the QoS request was updated. policy->cur kept the value the last fast-switch request returned. If that was a capped frequency equal to the suspend frequency, cpufreq_generic_suspend() skipped the driver after the limit rose, and the cluster suspended at the restored, higher state.

  • Suspend: the suspend step records the state it settled the cluster in as policy->cur before the generic suspend, so the suspend frequency is written whenever the cluster is elsewhere.
  • Limit moves: when the fast die limit moves the cluster, policy->cur follows, for scaling_cur_freq and the statistics, until the next fast-switch request sets it.

Only lazy_verify SoCs (T8140) run either path.

Testing

On Neo (7.3), with a diagnostic build that sets the cap without touching the QoS request and prints the cluster's state at suspend. Each case set the cap to suspend_freq (744000 kHz) while a spinner ran, restored it, then ran a pm_test=devices suspend.

before after
after the cap is restored cluster back at P-state 17/15, policy->cur still 744000 cluster at P-state 15/17/12, policy->cur 3924000 / 4044000 / 3648000
suspend with policy->cur == suspend_freq generic suspend skipped the driver; cluster suspended at P-state 10 (3336 MHz) in both runs settled state recorded, then the suspend P-state 1 was written and verified

The E-cluster wrote its suspend frequency in every run. There were no DVFS errors and no driver suspend errors.

Under real load the stale policy->cur rarely survives to suspend, because the real fast die limit changes the QoS request within about 0.3 s and schedutil asks again. The diagnostic therefore restores that state at suspend entry, to exercise the case.

Builds with W=1. checkpatch --strict is clean.

The fast die-temperature limit moves a lazy_verify cluster without a
scheduler request. It lowers a request above a new limit, and it
restores the scheduler's request when the limit rises again before the
QoS request was updated. policy->cur kept the value the last fast-switch
request returned. If that was a capped frequency equal to the suspend
frequency, cpufreq_generic_suspend() skipped the driver after the limit
rose, and the cluster suspended at the restored, higher state.

The suspend step now records the state it settles the cluster in as
policy->cur before the generic suspend, so the suspend frequency is
written whenever the cluster is elsewhere. When the limit moves the
cluster, policy->cur is updated too, for scaling_cur_freq and the
statistics, until the next fast-switch request sets it.

Checked on T8140 with a diagnostic build. The limit was set to the
suspend frequency under load, then restored before the QoS request
changed, and policy->cur was left at the suspend frequency. A
pm_test=devices suspend then left the cluster at 3336 MHz, because the
generic suspend skipped the driver. With this change, policy->cur
followed the restored state, and the suspend frequency was written and
verified.

Signed-off-by: DjDeveloperr <hey@djdev.me>

@maralcbr maralcbr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving at f360510, with CI green.

This closes the hole from #227: after the suspend step settles the cluster, it records that state as policy->cur before cpufreq_generic_suspend(), so the suspend frequency is written whenever the cluster is elsewhere and skipped only when it really is there. The diag-build run of the exact sequence (cap at suspend_freq with a spinner, cap restored, pm_test=devices) going from "suspended at 3336 MHz" to "P-state 1 written and verified" is the evidence I was after. Pending requests are drained and verified before they're recorded, resume clears schedutil's cached target, and the E-cluster takes the same path.

Two nits, not blocking:

  • policy->cur publication race. apple_fast_die_cap() writes policy->cur after lazy_cap() drops priv->lock, and the core publishes a fast-switch result after ->fast_switch() returns, outside that lock too. Either update can overwrite the other with a stale value. It only affects scaling_cur_freq, since suspend now re-records it, but note that moving the write under priv->lock alone wouldn't fully fix it.
  • Comment wording. A direct policy->cur write doesn't go through cpufreq_stats_record_transition() or arch_set_freq_scale(), so "the statistics" overstates what follows the cap. Frequency invariance also stays at the last fast-switch value after a cap move (that part predates this PR).

@DjDeveloperr
DjDeveloperr added this pull request to the merge queue Oct 26, 2026
Merged via the queue into integration/aurora with commit dd39c56 Oct 26, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants