Skip to content

drm/asahi: g15: keep the T6031 GFX domain on through system sleep - #288

Open
samucarre wants to merge 1 commit into
omacom:integration/aurorafrom
samucarre:t6031-gpu-sleep-hold
Open

samucarre wants to merge 1 commit into
omacom:integration/aurorafrom
samucarre:t6031-gpu-sleep-hold

Conversation

@samucarre

Copy link
Copy Markdown

Problem. On the T6031 the G15 is powered by its PMGR domain, gfx, alone, and once started its firmware session lasts until reboot: nothing starts it again. The G15 holds gfx with a runtime-PM reference, but in the noirq phase of system sleep genpd counts the GPU, the only device in gfx, as suspended whatever its runtime-PM state, and powers gfx off under the running firmware (genpd_finish_suspend(), genpd_sync_power_off()). genpd spares devices in the wakeup path only in GENPD_FLAG_ACTIVE_WAKEUP domains, and PMGR gives that flag only to domains it finds on when it probes them; gfx is off then. This is read from genpd, not observed: before this change no system sleep went past pm_test=devices here with the G15 running.

Change. While the G15 holds gfx, the GPU is a syscore device (dev_pm_syscore_device()), as dwc3-apple, the ISP and the SEP do for the domains of their resident firmware: the PM core skips it in every phase, genpd never counts it as suspended, and gfx stays on, under afr, which is always on. asahi_g15_release_power() clears the flag with the hold. Nothing changes while the system is awake: gfx is powered when it was before, and not at all in a boot without the G15. The admission now reads the ASC control word before it takes the hold, so that no failure there leaves the hold, or the flag, behind. T6031 only, whose configuration admits the J516C alone; g15_sleep_hold=0 restores the old behaviour, and the admission logs which of the two applies. T6030 is not changed.

Marking gfx apple,always-on from the display gate would keep it on in sleep too, but PMGR would then power gfx up when it probes it, before the PMP has started and well before the G15's admission (1.62 s, 2.17 s and 3.44 s in one boot), and keep it up in boots where the G15 never starts.

Nothing else changes for sleep: the GPU mailbox's interrupts are IRQF_NO_SUSPEND and neither the G15's poll work nor RTKit's is freezable, so the firmware is still served during the sleep, each message waking a CPU briefly without ending it; the G15's deadlines run on CLOCK_MONOTONIC, which s2idle does not advance here; and the firmware is not told about the sleep. With #258, its PMP AGX request is not withdrawn for the sleep either.

Checked on a MacBook Pro 16" M3 Max (J516C, 64 GB), integration/aurora 2f72554 plus local patches, among them the sleep work of #274 (now merged) with the J516C RTC alarm of #285, HDMI on dcpext0, #258 and #261, with the G15 running:

Not checked. This branch alone on hardware; an HDMI display attached through the sleep; long sleeps and their battery cost (the mailbox interrupts keep waking a CPU briefly); other T6031 boards.

🤖 Generated with Claude Code

The T6031 GPU is powered by its PMGR domain, gfx, alone, and the G15
holds that domain from its admission on, with a runtime-PM reference it
gives back only after a start that failed before the firmware was
touched: once started, the firmware session lasts until reboot, and
nothing starts it again. In the noirq phase, though, genpd counts the
GPU, the only device in gfx, as suspended, whatever its runtime-PM
state, and powers gfx off under the running firmware
(genpd_finish_suspend(), genpd_sync_power_off()). genpd spares a device
in the wakeup path only in a domain with GENPD_FLAG_ACTIVE_WAKEUP, which
PMGR gives only to a domain it finds on when it probes it, and gfx is
off then.

Leave the GPU out of system sleep instead, as a syscore device, for as
long as the G15 holds gfx, as dwc3-apple keeps its core's domain on and
the ISP and the SEP those of their resident firmware: the PM core skips
the GPU in every phase, genpd never counts it as suspended, and gfx
stays on, under afr, which is always on. asahi_g15_release_power()
clears the flag with the hold. The G15 has no callbacks to skip, and
nothing changes while the system is awake: gfx is powered when it was
before, and not at all in a boot without the G15.

As before, the hold covers a bound GPU only: when the probe fails after
the firmware was touched, its cleanup detaches the GPU from gfx, and
genpd may then power gfx off. The admission now reads the ASC control
word before it takes the hold, so that no failure there leaves the
hold, and the flag, behind.

Only on T6031, whose configuration admits the J516C alone, and unless
g15_sleep_hold=0, which restores the old behaviour; the admission logs
which of the two applies. T6030 is not changed.

Marking gfx apple,always-on from the display gate, as it marks the
PMP's own power states, would keep it on in sleep too, but PMGR would
then power gfx up when it probes it, before the PMP has started, instead
of at the G15's admission (in a boot of 29-oct: PMGR turned its
always-on domains on at 1.62 s, the PMP was started at 2.17 s, the G15
admitted at 3.44 s), and keep it up in boots where the G15 never starts.

Nothing else is changed for sleep: the GPU mailbox's interrupts are
IRQF_NO_SUSPEND and neither the G15's poll work nor RTKit's is
freezable, so the firmware is still served through the sleep, each
message waking a CPU briefly without ending it; the G15's deadlines run
on CLOCK_MONOTONIC, which s2idle does not advance here (cpuidle-apple's
states have enter_s2idle, so the tick and timekeeping are frozen); and
the firmware is not told about the sleep.

Tested on a J516C with the G15 running, on top of local patches that
let it sleep and wake (among them the sleep work of omacom#274 ported to the
J516C, with its RTC alarm): pm_test=platform, then three s2idle sleeps
of 30 s, each ended by the RTC alarm. gfx was never powered off (genpd
counted no new entry into its off state), the GPU mailbox raised 0 to 8
interrupts in each sleep without ending it, and the GPU ran compute work
after each one. That gfx goes off in the noirq phase without this is
read from genpd, not observed: before this change no system sleep went
past pm_test=devices with the G15 running.

Generated-by: LLM
Signed-off-by: Samuel Carreño <soyminero11yt@gmail.com>

@chriskearney chriskearney left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed all four changed files at exact head ff2c986fd2db9ccd4af5ae616a5b3cd58594dd11 and the independent PM-core/genpd and lifetime analysis. The syscore flag is restricted to the existing T6031/J516C DeviceTree G15 admission, is cleared on the pre-firmware unwind, and the ASC read now precedes the power hold. T6030 remains outside this gate. No source blocker found; normal current CI and a full native package build/merge-group result are still required.

The author's three s2idle/compute observations are on integration plus local patches, not an exact-head hardware qualification. Long-sleep battery cost remains unmeasured. This review does not qualify a new board, firmware image or HDMI/sleep cohort, and no additional physical test is required for this protective scoped change. Small documentation nit: SEP is not a syscore precedent in this tree; dwc3-apple and ISP are.

@chriskearney chriskearney reopened this Oct 30, 2026
@chriskearney chriskearney reopened this Oct 30, 2026
chriskearney added a commit that referenced this pull request Oct 30, 2026
The suite builds admit() from g15/boot.rs against host models. With
the T6031 system-sleep hold (#288), admit() reads the ASC control word
before it takes the hold, passes whether to hold through system sleep
to glue::hold_power(dev, sleep_hold), reads params::sleep_hold() and
warns with dev_warn! when g15_sleep_hold=0 on T6031. The model has no
dev_warn!, no params module and a one-argument hold_power(), so the
admit() control no longer builds.

Add dev_warn! (counted), params::sleep_hold() and a failing ASC read to
the model, and pick the hold_power() mock from the admit() it is given:
with the sleep-hold argument it records the value passed; without it,
the model is the old one. Every existing scenario and mutant runs
unchanged on both.

For an admit() with the sleep-hold argument, also check that the hold
is taken through system sleep only on T6031 with g15_sleep_hold on,
that g15_sleep_hold=0 on T6031 warns once, that T6030 never holds
through sleep, and that a failing ASC read returns before any hold is
taken on either SoC. Four mutants (the hold on any platform, ignoring
the parameter, no warning, the ASC read after the hold) each fail one
of those checks.

Signed-off-by: Chris Kearney <303316+chriskearney@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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