Repository navigation
J713 (M4 MacBook Air): suspend-to-idle - #831
Merged
erykwieliczko merged 7 commits intoNov 4, 2026
Merged
Conversation
This was referenced Nov 2, 2026
The J713's retained DMA owners refuse system sleep: the radio's DART with managed streams, and the display DARTs, which borrow the running DCP's live page-table root. Neither has a suspend boundary of its own, and their state cannot be restored from a copy. Suspend-to-idle does not need one. These DARTs have no power domain of their own in the tree, and the DCP keeps the display domains on across s2idle, so their state stays where it is. Let them through for suspend-to-idle only, saving their registers solely for resume to check that nothing moved. Every other sleep state is still refused. A DART whose retained state changed cannot be trusted with its live DMA, and a resume error does not stop the PM core from resuming consumers. Quarantine the managed streams and the borrowed display consumers through the same paths as a translation fault before failing resume, so that their later maps are refused. A host test exercises the extracted check, quarantine and map functions. Signed-off-by: Erik Bourget <erik@ebourget.net>
The J713's radio port, whose streams the OS adopts from the boot loader's handoff, refuses system sleep in its noirq phase. It has no suspend boundary of its own, but suspend-to-idle does not need one: the port has no power domain in the tree, so it stays up as any other internal port does, whose resume does nothing. Let it through for suspend-to-idle only; every other sleep state is still refused. Signed-off-by: Erik Bourget <erik@ebourget.net>
A coprocessor can keep running in its power domain across system sleep without system-sleep callbacks of its own, as the J713's GPU firmware does. Describe such a domain, which the OS keeps on during system sleep; runtime power management is unaffected. Signed-off-by: Erik Bourget <erik@ebourget.net>
…tem sleep The J713's G16 GPU has no system-sleep callbacks, so in the noirq phase genpd powers its GFX domain off, and the TVM gate above it, under the running GPU firmware; the power-on at resume then times out. Let a domain marked apple,sleep-retained decline its power-off while the system sleeps: genpd then keeps it and its parents on. Runtime power management is unchanged. Signed-off-by: Erik Bourget <erik@ebourget.net>
Some coprocessors message the AP periodically while idle: the J713's GPU firmware asks for ring service about twice a second, and its AOP sends a report every second. Describe a mailbox whose messages need not wake the system, so the OS can leave them in the FIFO while it sleeps and handle them at resume. Signed-off-by: Erik Bourget <erik@ebourget.net>
…uest The receive IRQ of the ASC mailboxes is IRQF_NO_SUSPEND, so every coprocessor message wakes a CPU out of suspend-to-idle. On the J713 the GPU firmware's idle ring-service kicks and an AOP report every second wake it about three times a second: in 938 s of s2idle, 1472 wakeups and only 512 s in deep idle. For a mailbox marked apple,hold-rx-in-sleep, mask the receive IRQ from noirq suspend to noirq resume, so its messages wait in the FIFO and the consumer handles them on resume. The mailbox is a supplier of its consumer, so this runs after the consumer suspended and before it resumes. The firmware throttles once its outbox fills: after 148 s of s2idle, 11 GPU and 3 AOP messages were waiting, with 3 wakeups and 146.9 s in deep idle. Signed-off-by: Erik Bourget <erik@ebourget.net>
The G16 firmware keeps running across suspend-to-idle: keep its GFX domain on through system sleep, and hold its idle ring-service kicks in the mailbox instead of waking the system about twice a second. Signed-off-by: Erik Bourget <erik@ebourget.net>
Member
|
Merging, with one conflict resolved. This comment is from Claude Opus 5.5, working for Eryk, not from Eryk himself. Rebased onto integration/aurora Changes
For ErikA false quarantine looks possible when the radio has no paging domain at suspend, because the SID16 bypass reads back without Testing
🤖 Written by Claude Opus 5.5 (in Claude Code) for Eryk. |
erykwieliczko
force-pushed
the
j713/s2idle-integ
branch
from
November 4, 2026 08:42
52f2e39 to
4b2b3de
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The J713 (MacBook Air 13" M4, T8132) refused system sleep. With this series and the DCP's sleep handshake in #830, it sleeps from
systemctl suspendand from the lid. It wakes on the keyboard, trackpad, power button or lid, with display, GPU, Wi-Fi and audio intact.It replaces the platform half of #449; the commits are unchanged. The pieces span iommu, PCI, pmdomain and the Apple mailbox, but they're one feature: suspend-to-idle works only with all of them.
Needs:
Retained DMA owners (commits 1–2)
The radio's PCIe port and DART, and the display DARTs, have no power domain of their own in the tree, and the DCP holds the display domains on. So suspend-to-idle leaves their live state in place, and these two commits let them through for s2idle only. Every other sleep state is still refused. The DARTs save their registers only so that resume can check nothing moved.
If something did move, the consumers' DMA is no longer what they set up, and a resume error alone doesn't stop the PM core from resuming them. So before failing the resume, the DART quarantines them through the same paths as a translation fault:
GPU (commits 3–4)
asahi-g16 has no system-sleep callbacks, so genpd's noirq power-off gated GFX, and with it the TVM gate, under the live firmware. The power-on at resume then timed out (
GFX target=0xf … error=-110).A pmgr-pwrstate domain marked
apple,sleep-retaineddeclines that power-off while the system sleeps. Runtime PM is unchanged.Wakeups (commits 5–7)
Every ASC mailbox receive IRQ is
IRQF_NO_SUSPEND. The G16 firmware's idle ring-service kicks (about 1.9/s) and an AOP report (1/s) woke the CPUs about three times a second:A mailbox marked
apple,hold-rx-in-sleepmasks its receive IRQ from noirq suspend to noirq resume. The firmware throttles once its outbox is full: after 148 s, 11 GPU messages and 3 AOP messages were waiting. Commit 7 sets both flags for the J713 GPU, and #450 sets the mailbox flag on the AOP.Testing
J713, on integration/aurora 41c4055 with the rest of the J713 PR stack (#830, the USB series, #429, #432, #819/#820, #450, #531, #825): an 82 s real suspend-to-idle.
error=0), GPU (no errors), Wi-Fi and speaker playback all back.J713, on our J713 tree with this series, the DCP handshake, #429, #432 and the AOP audio, on 26.6.2 firmware:
systemctl suspend(up to about 16 min asleep) and the lid, through logind. Display, GPU (glmark2 630–642, unchanged), Wi-Fi and the AOP audio all come back.pm_test=devicesandpm_test=platformpass.J713, on integration/aurora 41c4055 with these commits, #429, #432, #819/#820, #450, #531 and the DCP handshake: several real suspend-to-idle cycles (up to 352 s). Each resumed to a working desktop, with Wi-Fi and the camera working; a 600-frame stream ran across one of them. Over 222 s asleep, the AOP mailbox took 3 interrupts.
Host tests:
New
dart-s2idle-retention.py, on the extracted production state check, quarantine and map functions:-EIO, with the radio streams disabled,managed_failedand every borrowed consumer's failed flag set, and a later 16 KiB radio map refused:This checks the failure path on the host, not physical retention on the J713; the retained path is unchanged.
m4-dcp-errorspasses, including its case where a failed display domain refuses maps.bcm4377-radio-sids.pypasses, with its negative controls.Checks (on integration/aurora 41c4055):
checkpatch --strictis clean (apart from the MAINTAINERS note for the new test file);dt_binding_checkis clean forapple,mailbox.yamlandapple,pmgr-pwrstate.yaml;CHECK_DTBSW=1 on all six T8132 DTBs gives the same output as the base;run-host-tests: 132/133. The one failing group,apple-dcp, fails the same nine cases on the bare base and nothing more.Still to do: this changes shared DART save-state code, PMGR and mailbox PM, so it needs the Neo and M1 Pro/M2 regression boots with s2idle, display/GPU, radio and audio checks, which I can't run. The new flags are opt-in by DT, and only the J713 sets them. The retained-DART admission is restricted to the J713 at probe.
This series was developed and tested by Claude (Anthropic), working with me on the J713.