Repository navigation
Conversation
3926193 to
abc6ee8
Compare
d808c54 to
b189876
Compare
c99d8b7 to
6deb620
Compare
RyanTheTide
left a comment
There was a problem hiding this comment.
Before this can merge, please reword the comments that name macOS driver classes and methods, mark steps as RE or decompile-verified, or say where a value was read. That covers mainly t6040-sleep.c, plus t6040-usb2.c, dcp.c and macsmc.c. Each comment should say what the hardware or firmware does: the register, the bits, the order, and what you measured on the J616s. Values and code can stay as they are.
2ce0d80 to
7aefde0
Compare
|
Done in 7aefde0, thanks for the pointer to #1625.
Rebased onto aea2deb on the way. Tested on the J616s on this head (suspend-to-RAM, hibernation, suspend-to-RAM again; details in the description). That round was on battery without the dock, so the external displays have not run on this head yet; I will add that run. What is left in |
|
Tested on a second J616s (M4 Pro, 24 GB, firmware of a macOS 27.0 install), Linux at EL2 under aura main 27298d21 (includes aura#148), kernel = integration + this series:
Four commits on top of 7aefde0 are on
Checks on that branch: universal config builds (both controllers =y, and each one off), sleep KUnit 6 pass / 1 skip, checkpatch --strict clean, s2idle 3/3 with no kernel errors and the deep rows above on the J616s, s2idle 3/3 on an M1 Pro and an M2 with no new kernel errors. |
…uspend The T6041 (M4 Max) has the AICv3 of T8122 and now a suspend-to-RAM driver of its own. Give "apple,t6041-aic3" its own info, the T8122 one with fw_suspend, so the AIC state the sleep loses is saved and put back as on T8140. Nothing else in the driver looks at fw_suspend. Also in aurora-silicon#1477 (T6040 sleep), which admits apple,t6041-aic3 the same way; drop this one when that lands. Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
apple_nvme_t6040_hw is only matched by "apple,t6041-nvme-ans2". Give it the sleep fields T8140 uses: register ANS with the sleep core (sleep_traced), flush namespace 1 only, the OS's own, and send the full shutdown notification at suspend. The T6041 sleep driver stops ANS through the sleep core's coprocessor stop. On T6041 the sleep core's last check (the shutdown notification has completed) does not run: the T6041 driver calls only the coprocessor stop. Also in aurora-silicon#1477, which sets the same fields with sleep_untraced on the same struct; drop this one when that lands. Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
The PMP's SRAM loses its contents in a real sleep. On the J616C's 26.6.2 firmware its __DATA segment is at 0x500761000, 0x7d000 bytes: back up (0x61000, 0x7d000) of the SRAM, as T8140 does for its own. Also in aurora-silicon#1477, whose HW_CFG_T6041 has the same range; drop this one when that lands. Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
On apple,t6041, write the keys macOS writes last before MBSE slpa in a trace of its sleep: WKTP = 2 (AppleSMCEmbedded, going to sleep), then pmVC. The value written is 0x101, as the bring-up kernel runs it; the comment, taken over from it, says the trace has 0x100. That difference is open. Also in aurora-silicon#1477, which writes WKTP through a sleep_wktp parameter; drop this one when that lands. Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
A conventional host (internal ports with the radio and the SD reader) loses its power in a real sleep: the endpoints sit unpowered or in reset behind a link that is down. On a firmware suspend, save what only the port registers hold; on the noirq resume, note which ports lost their link and keep a copy of their functions saved state before the PCI core spends it on the down link; in the normal resume phase (after the SMC, which owns the PWREN GPIOs) bring each such port up again as probe does, then restore its functions. Only for hosts that are not tunneled, have no managed SIDs, no PIO DMA supplier and more than a root bus; s2r_conventional turns it off. The suspend-to-idle paths (domain hold, adopted links) are unchanged. Also in aurora-silicon#1477 (0ab1a66), which this follows; drop this one when that lands. Signed-off-by: AxxzyWasTaken <axxzytte@gmail.com>
1599341 to
9bee928
Compare
|
Picked up, thanks for the second machine and the four commits. Head is f259e90 on integration/aurora 107b361 (the brcmfmac
If you would rather merge 9bee928 first and take the 35 commits as a second pull request, say so and I will split it there; they sit on top and nothing below them changed. On the J616s here, kernel from this head with Not verified: T8140 on the merged driver (its object differs from before only in the functions that now go through the part; a sleep on a T8140 would be welcome), and external displays, the dock and the kept USB hosts on this head. The USB3 miss on your dock port ("AP idle not acknowledged: -62") is under Open; I could not try for it without a dock. |
… K116s deep-sleep base Base: Jens Axboe's K116s series of 2026-11-12 (40 patches on integration/aurora 2b4523c), the tree his K116s runs at EL2. aurora-silicon#1477 brings the generic Apple SoC sleep driver with per-SoC parts (sleep.c, sleep-t6040.c) to start a T6050 part from. Signed-off-by: Thomas Glanzmann <thomas@glanzmann.de>
|
@fbalazsy thanks for picking up the fixups and folding the T6040 controller into sleep.c. To merge this we need:
|
The probe and the restore after a resume from disk both put the controller into system power state S0, check that application firmware runs and load the patch if the controller waits for one. The restore repeated the probe's sequence step by step. Move the sequence into one helper that both call. The order of the steps, their error returns and what the probe does with the mode it found are unchanged. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The T6040 USB4 router runs only over its port's Type-C PHY and tells the PHY when it starts and stops. The PHY was named in a vendor phandle, which the router resolved to a device node and looked up by hand for each call. Describe it with the standard phys property, as the USB controller of the same port does, so the PHY framework resolves it and orders the router after the PHY. Not run on a USB4/Thunderbolt device. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Name each router's Type-C PHY with phys, as the binding now describes, instead of the vendor phandle. The routers stay disabled here, so no default board changes. The built J616s device tree passes the router schema. Not run on a USB4/Thunderbolt device. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The router called the T6040 Type-C PHY through four exported functions that took the PHY's device node, found the platform device by that node on every call and kept the driver bound with the device lock. Nothing ordered the router's probe or power management after the PHY. Get the PHY at probe with devm_phy_get() from the router's phys property and pass the struct phy to the same four calls, as the USB controller does for its sleep steps. The PHY framework links the router to the PHY as its consumer, and a router whose PHY is not bound yet defers its probe instead of failing its first start. The PHY side checks that the PHY is a T6040 Type-C PHY by its ops, takes its lock and runs the same steps. The check for an enabled router in the PHY driver reads the same property. Not run on a USB4/Thunderbolt device. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
A driver that must treat the kernel loading a hibernation image differently from a kernel that freezes for an image of its own has no way to ask: the freeze callbacks run the same in both. The SMC driver and the RTKit hand-off each registered a PM notifier that sets a flag on PM_RESTORE_PREPARE and clears it on PM_POST_RESTORE, and the hand-off copy is read by two more drivers. Keep the flag in the PM core, next to the restored flag, and have the two notifier helpers set it around the PM_RESTORE_PREPARE and PM_POST_RESTORE notifications, whether the load starts from the resume path or from the snapshot device. pm_hibernate_is_loading() reads it. It is true from before the first notifier runs (the copies became true only when their own notifier was reached) until PM_POST_RESTORE has been delivered, and it is cleared again when a notifier refuses the load, where the copies of the notifiers not reached never became true. It is saved in an image as false, like the notifier copies, so the restored kernel reads false. The SMC driver reads the core flag in its freeze callback and drops its notifier, which also removes the registration at probe. The RTKit hand-off keeps apple_rtkit_hib_restoring() for its callers and answers it from the core flag. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
swsusp cleans every page of a loaded image to the point of coherency before the jump into it, for devices that read memory without snooping the CPU caches, and does so under #ifdef CONFIG_ARM64 in the generic snapshot code, with the justification of one SoC family in its comment. Keep the walk over the image's page frames in snapshot.c and ask the architecture, per frame, through arch_hibernate_clean_image_page(), enabled by ARCH_HIBERNATION_CLEAN_IMAGE. arm64 sets the symbol and provides the function with the body the walk had: a frame that is not in the boot kernel's linear map is left to the restore_pblist copy, any other frame is cleaned and invalidated to the PoC. The frames, their order, the cond_resched() cadence and the clean operations are the same as before; the disassembly of the arm64 function matches the removed loop body. Other architectures compile the walk out, as they did. The comment of the copy loop in hibernate-asm.S no longer names a SoC. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
hibernation_available() asked of_machine_is_compatible("apple,arm-platform")
and aura_hibernate_layout_fixed() in the generic hibernation code, and the
log line carried the reason of one platform.
Add hibernation_set_platform_check(): platform code registers a function
that is true while hibernation must stay refused, with the reason that is
logged at the end of the boot when it is. hibernation_available() asks it
where it asked the two Apple conditions. The aura hibernation code
registers aura_hibernate_blocked(), which is the same expression
(Apple platform and no fixed layout), evaluated at the same moments, and
the same reason text; the explanation of why the machines refuse moves
with it.
The check is registered from the init of that code on every boot of a
kernel that has it, where the Apple condition used to be compiled into the
core unconditionally. To keep that fail-closed, APPLE_AURA_HIBERNATE is no
longer a prompt: it is always on with ARCH_APPLE and HIBERNATION, as the
refusal belongs to it. Nothing registers before that init runs, which
precedes the first possible hibernation (the resume check is a later
initcall level and user space starts after all of them).
Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
arm64's hibernation code read aura's /chosen properties, called aura's nosave functions and kept aura's layout rules in the boot layout check that is stored with an image and compared before it is restored. Add struct arm64_hibernate_platform with two hooks, registered once at boot: pfn_nosave(), asked by pfn_is_nosave(), and layout(), which adds the platform's facts to the layout cookie. The part of the check that belongs to every arm64 machine stays: the CPU release addresses (as offsets from a base the platform may name, together with whether the platform keeps the page out of the image) and the memory map less the ranges the platform names. The aura hibernation code registers the hooks and carries the rest: the /chosen properties, the S2R mailbox and the split of aura's layout around the exec window, moved as they were, with the comment that explains them. arm64_hibernate_layout_mix() is the mixing function, made visible for the hook. The nosave ranges stay a table in aura-hibernate.c and are not handed to register_nosave_region(): that function allocates from memblock and runs at setup_arch() time, and the table is filled from a late initcall. The aura functions that nothing outside the file calls any more become static, and aura_hibernate_layout_fixed() is dropped. The cookie is bit for bit the same: the old function and the new pair were compiled against the same stubbed device tree and memblock in 200000 randomised boots (properties present or absent, mailbox, window, nosave tables, CPUs with and without release addresses, memory maps); every cookie is identical, and a change of one mixed value in the new code is caught. The set of pages kept out of the image is the table's, asked at the same place. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
A driver whose device does not survive a boot cannot tell, in the kernel restored from a hibernation image, whether the machine went through one. pm_hibernate_is_restored() is also true after a test_resume, where the kernel that wrote the image loads it itself and nothing rebooted, and drivers fell back on hardware side channels to tell the two apart. The kernel that loads an image now leaves a record for the restored kernel just before the jump: whether it is the kernel that wrote the image, which is the case only when hibernate() loads the image it has just written for test_resume, or one that was started to resume it. The record lives in the no-save section, which the image neither saves nor overwrites, and carries a magic and its own physical address, so a record from a kernel loaded elsewhere, or none, reads as absent. It is the same requirement that in_suspend and other no-save hand-offs already have: both kernels are the same build at the same physical address. The restored kernel copies it where it sets the restored flag, and pm_hibernate_restored_cold() returns 1 when another boot loaded the image, 0 when this kernel did (or was not restored) and -ENODATA when no record was found. The record is cleared when it is read and when a restore fails, and the value has the lifetime of pm_hibernate_is_restored(). The flag says that the machine booted, not that a given device lost its state: a kexec-style resume would read as another boot with firmware that kept running, and a device that needs more than the boot has to check it itself. Nothing uses it yet. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
iBoot boots sepOS anew on every boot and the SEP has no run bit the AP can read, so its resume from disk asked the PMP: the PMP's restore counted the resumes that found the PMP halted, and the SEP's notifier, one priority below the PMP's, compared the count taken at registration and at each hibernation's prepare and end. That tied the SEP to the PMP driver (a Kconfig dependency, a count, an export and a call from the PMP's restore) and to the order of two notifiers. pm_hibernate_restored_cold() answers the same question in the one place that knows it: whether another boot loaded the image. The notifier asks it where it compared the counts. Not restored (aborted hibernation, wake of a hybrid sleep): warm, as before. Restored and loaded by another boot: the cold path, the session is dropped and the device probed again. Restored by the kernel that wrote the image (test_resume): warm; the PMP found itself running there too. No record: the session is dropped without a probe, which is what a missing PMP count did. On the J616s the boot that loads an image always restarts the PMP, so the two signals agree on a resume, a test resume and an aborted hibernation. They differ where a boot that loaded an image did not restart the firmware (a kexec-style resume), and for a machine without a bound PMP, which can now tell. The PMP's own restore is unchanged: it still reads the ASC run bit and only stops reporting a count. The host test now drives the end of a hibernation through the notifier for an aborted hibernation, a resume after another boot, a test resume and a missing record, with three mutations that each fail it. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
When hibernation is abandoned before the image exists, hibernation_snapshot() and create_image() resume the frozen devices with PMSG_RESTORE, the event of a kernel restored from an image: in_suspend is clear in both cases, and only the creating kernel with an image sets it. The cases are a device that fails to freeze, a wakeup event, the pm_test levels devices, platform and core, and a failure in the noirq phase before in_suspend is set. The hardware did not boot in any of them, but the drivers get their restore callbacks, run them for a state they cannot have, and some have to be told by pm_hibernate_is_restored() that nothing happened. Pick the event in one function: in_suspend set keeps what it was (PMSG_THAW, PMSG_RECOVER after an error); in_suspend clear is PMSG_RESTORE only when pm_hibernate_is_restored() says this kernel was restored, and PMSG_RECOVER otherwise, which is what the PM core sends after every other failed freeze (dpm_prepare() failing here, dpm_suspend_start()/end() through resume_event()). The restored flag is reset at the start of every hibernation_snapshot() and set right where the restored kernel leaves swsusp_arch_suspend(), before either resume call. What changes: only the calls of an abandoned hibernation, from the restore callbacks to the thaw callbacks (pm_op() maps PM_EVENT_RECOVER to the thaw callbacks as PM_EVENT_THAW), and, for a device with DPM_FLAG_MAY_SKIP_RESUME, dev_pm_skip_resume() now follows must_resume as it does for every other failed freeze. pm_hibernate_is_recovering() is now true there as well, as its documentation says. Nothing changes for a created image, a restored kernel or a test_resume, nor after a failed power-off in platform mode (PMSG_RESTORE from hibernation_platform_enter(); only ACPI sets platform hibernation ops). For the Apple drivers the abandoned case was already a thaw: every restore callback that checks the flag returns or forwards to its thaw (macsmc, the RTKit helper, apple-dart, sn201202x, DCP, NVMe, PCIe, cs42l84) or does nothing where there is no thaw (AOP, t6040 USB2 PHY, RTC, GPIO and SPMI early restores); PCIe's restore_noirq and thaw_noirq agree on the ports. So they now get the thaw directly. The checks in those callbacks stay for now. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
…nation An abandoned hibernation resumed its devices with PMSG_RESTORE, so every restore callback that must not act on a state it never lost began with a pm_hibernate_is_restored() check, and most forwarded to their thaw. The PM core now sends PMSG_RECOVER there, which reaches the thaw callbacks, so the check and the forward go from macsmc, the RTKit helper, apple-dart, the sn201202x Type-C controller, the SPMI, GPIO and NVMe restore paths, both PCIe restore callbacks, the DCP and AOP restores, the t6040 USB2 PHY's two and the RTC; cs42l84's restore passes that the codec lost its state. Each callback runs for a restored kernel exactly as before. For an abandoned hibernation the old path was already the thaw or nothing, and the thaw now runs on its own: macsmc, the RTKit helper, apple-dart, sn201202x, NVMe and cs42l84 forwarded to the same function (cs42l84's resume asks pm_resume_via_firmware(), which hibernation_snapshot() has cleared); PCIe's restore_noirq did for a bridge without hibernation tunnelling what its thaw_noirq does, and the same call with it; the AOP, t6040, RTC, GPIO and SPMI restores did nothing and have no thaw. DCP keeps its power-off-failed branch (PMSG_RESTORE after a failed platform power-off, which only a platform with hibernation ops reaches) and loses the abandoned one, whose only other effect was a log line. One path changes: macsmc's thaw, after the SMC was handed over and the image could not be entered, calls apple_smc_restore() to start a new session, and its own check sent that back to the thaw, which did nothing. It now starts the session as the comment says it should. The flag keeps its other users, which are not restore callbacks: the AIC syscore resume, the dockchannel receive interrupt, the SEP's PM notifier. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
DP IN 1 of a Thunderbolt tunnel runs on PCLK2, and on T6030 and T8132 its video stops unless PCLK1 runs as well, at the same rate when DP IN 0 does not use it. The T6040 tunnel clock enabled PCLK2 alone for DP IN 1, so the second stream of a two-stream display (a tiled one) got no video. Enable PCLK1 whenever either adapter runs, and write DP IN 1's rate into the PCLK1 select while DP IN 0 is off. Hold clock switch 1 for it, and release the switch and the enable when DP IN 1 stops, or hand PCLK1 over to DP IN 1's rate when DP IN 0 stops first. A stop of the whole tunnel releases the held switch. Not run on a Thunderbolt display; this follows the two SoCs where the requirement was measured. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
8acba58 to
6e7d5e4
Compare
…lace The render and the compute kick queue return their ring to the state of a freshly installed queue after the GPU firmware was cold-restarted across a hibernation by two functions with the same body: they differ only in a check that the queue has the engine of its type. That check can not fail: the engine of a kick queue is fixed when it is built, and the constructors for the two types refuse the other engine. Replace both functions by one that clears the ring, restarts the timestamp and drops the parent, in the same order as before. Hardware test: resume from disk (S4 round trip) with a render and a compute client holding queues across the hibernation; both must submit their first job after the resume without a timeout. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The wait for the PMP to take the held power state requests after a resume from hibernation is a one-line wrapper around the PMP report call. It sat in the CLPC wrapper file, next to the performance controller calls that it has nothing to do with. Move it to the file that already holds the GPU's PMP request and the sleep-time power state word. The symbol keeps its name and its behaviour. Hardware test: none for behaviour (same call, same arguments); a resume from disk shows the "PMP requests acknowledged" line as before. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The T6040 sleep controller wrote the SMC key pmVC itself, with the key, the value 0x101 (the J616s enable mask | 0x100) and the failure text all living in sleep-t6040.c. The SMC key space belongs to the SMC driver, so move that knowledge here: apple_smc_request_pmvc() performs the same u32 write of 0x101 to pmVC and warns with the same text when it fails. include/linux/mfd/macsmc.h declares it, with a -ENODEV stub when the SMC driver is not reachable. The moment of the write is unchanged. It is deliberately not made a suspend callback of the SMC driver: that would run relative to the USB-C controller's prepare step, which hands the port controller to the S3 state, in a device-list order rather than the order the sleep controller has today. sleep-t6040 still looks the SMC up by its compatible as before and calls the helper from the same point of its .begin, after the AOP island save and before the DCS power setup, with the same warning when no SMC is there (now logged without the value). The write reaches the SMC with the same key, size and value. Hardware test: one suspend to RAM with a USB-C device attached and powered; the log shows no "pmVC:" warning, the ATC port hand-over completes, and the device is still present after the wake. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The statistics sysfs shim also owned the hibernation gate, the G17 drain notifier and the G17 statistics and thaw notifier, registered from the probe of each device. Move them into g17/hibernate.c, next to the other G17 sleep code, and register the gate once at module load instead of when the first device binds. The chain is the same for every event: - gate, priority 30: refuses hibernation with an unrestorable GPU bound and refuses restoring an image with any GPU bound. With no device bound it does nothing, so keeping it registered from module load to unload changes no outcome. Registering it can no longer fail at probe time. - G17 drain, priority 20, registered per device ahead of the display and PMP notifiers. - G17 statistics epoch and thaw, priority -10, below the PMP restore. Per device they are still registered before the gate counts the device and unregistered after it stops counting it, and the notifier bodies are unchanged. The priorities are named in one place. Hardware test: S4 round trip (drain at hibernate, cold republish after the resume, "GPU firmware republished after resume" in the log), a refused hibernation path (a PM_HIBERNATION_PREPARE failure after the GPU drain, for example by a failing later notifier, must reopen submission), S2R (statistics resume), and unloading and reloading the aurora module. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The H16G HWX that Apple's compiler writes carries one LC_NOTE (0x31) command, owner "src model info", which names the source model and the compiler component. The validator refused the container on the unknown command. Accept one note as an annotation with no authority over mappings. The compiler stores the payload inside the command, right after the 40-byte note header, and counts the offset from the start of the command. Require exactly that: a terminated owner name, a payload that starts after the header and ends inside the command, and zero bytes after it. A KUnit case covers the accepted note (the region table is unchanged) and the refusals: payload past the command, overlapping the header, wrapping length, nonzero padding and an unterminated or empty owner. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The validator tied the __TEXT segment flags to the scratch: SG_NORELOC (0x4) with a __DATA scratch, 0 without one. That is one compiler's habit, not a property of the program. Apple's compiler sets SG_NORELOC when the task stream has no relocations: its add [1,1,128,128] program has no scratch and flags 0x4, and its Parakeet encoder has a scratch, 1596 relocations and flags 0. The flag only says that a loader relocates nothing in the segment. The validator checks every relocation of the task stream itself and no mapping depends on the flag, so accept 0 or SG_NORELOC on __TEXT in every form. Other segments keep their exact flags. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Apple's compiler appends STAB entries to the symbol table of an H16G HWX: N_LSYM (0x80) descriptions of the element types (float16, int8, ...) and one N_GSYM (0x20) per tensor with its array type. They have section 0 and value 0 and describe the source, not the image; their names repeat the tensor names. The validator required every entry to be a defined section symbol and refused the container. Skip entries with any N_STAB bit (type & 0xe0) after bounding their name offset by the string table, and leave them out of the duplicate-name check. Section symbols keep every existing check, and a STAB entry never stands in for a surface symbol. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
A whole-model H16G HWX names every kernel blob in its symbol table. The Parakeet encoder that Apple's compiler writes has 24809 entries (24783 section symbols, 26 STAB entries) and 1.77 MB of names, against a limit of 4096 entries and 256 KiB. The duplicate-name check also compared every pair, about 3e8 string compares for that table, and the validator runs several times per LOAD. Raise the bounds to 64K entries and 8 MiB of names, which covers a kernel region at the 1 GiB segment limit at the encoder's density, and find duplicate names by sorting the section symbol names and comparing neighbours. The table and its strings stay bounded by the file and must not overlap any other file range, as before. A KUnit case builds 30000 constant symbols, accepts them, and refuses two equal names far apart, a constant that reuses a surface name and a count above the bound. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
A large H16G model does not fit its kernel data in one __KERN_0 segment. The compiler splits it into __KERN_0, __KERN_1, ... of at most 128 MiB each (the Parakeet encoder: four segments, 390 MiB). The segments are contiguous in VM and in the file, each holds one section __kern_n, the program descriptor lists every section base after the surface bases, and the task stream addresses each section through its own BAR: relocations name the section's ordinal and carry an offset into that section. Accept up to 16 kernel segments in order. Each further segment must start where the previous one ends, in VM and in the file, and follow a wholly file-backed one, so that together they form one kernel region that maps exactly like the file and stays within the segment limit. The validated info keeps every kernel section, and @kernel spans them all with the ordinal of __kern_0. The base records of the descriptor must be the surface bases, then every kernel section base, then zero. Relocations may name any kernel section and are bounded by it. The section, segment and file-range tables grow with the kernel segments; the region table does not. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
A buffer reference (load command 0x40) names its surface in the bytes after +0x18. With names of up to seven bytes the command is 32 bytes long; Apple's compiler writes 0x28-byte commands with a 16-byte field for longer names such as "attention_mask" and "encoder_hidden". The validator took only 32-byte references and compared at most eight bytes of the name. Accept references of 32 bytes up to a 32-byte name field, with the name terminated inside the command and zero after it. A surface pairs with the tensor whose whole short name equals the reference's name, and the surface keeps names of up to 31 bytes. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The engine reads every BAR at the base the operation section gives it, and the firmware programs a BAR only from those (slot, tag) pairs. Tag 1007 names what LOAD slot 1 carries: the __KERN_0 section of a program that has one, otherwise __TEXT,__const, the constants that every program places at BAR slot 1 of its descriptor. One slot gives one base. Apple's whole-model programs need more: the Parakeet encoder reads its 38 MB of constants through BAR 1 and its kernel data through BARs 9 to 12, one per __kern_n section, with offsets into that section. No slot assignment of the kernel and the constants gives five distinct bases. Bind such a program the way a scratch is bound: the generic section lists every kernel section after the surfaces and the scratch, typed as a read-only input of the section size (up to its 16 KiB pages), each with its own ID, and the operation section binds every kernel base to that ID. EXECUTE then carries one buffer per kernel section at its place in the one kernel region mapping. LOAD slot 1 carries the constants at their address in the __TEXT mapping, as for a program without kernel data, and 1007 binds BAR slot 1. A program whose generic section has no kernel entries keeps the existing form: slot 1 carries its one kernel section, which it must bind through 1007. That form refuses more than one kernel section. In every form a 1007 pair must name the resource slot 1 really carries, so the constants base binds to 1007 only when slot 1 holds them. KUnit covers both forms: the slot table and EXECUTE descriptors of a four-section program with a scratch, the refusal of four sections in the slot-1 form, unbound or mismatched kernel IDs, kernel entry sizes, types and duplicate IDs, and which base 1007 may name. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
The load planner capped the sum of all mapped regions of one program at 512M, although each segment may map 1G. Apple's Parakeet encoder maps 488M (390M of kernel data in one region, 37M of __TEXT, a 59M scratch, 1.2M of surfaces): it fits with 24M to spare, and a slightly larger model or a longer input would fail the plan with -E2BIG while every one of its segments is far below its own limit. Raise the sum to 2G, twice the segment limit. The bound stays: every region is rounded to the 16K mapping size and added with an overflow check before any memory is taken, and a program beyond it is refused before any firmware-visible mapping exists. The test plans 1.5G, exactly 2G and one page more, and checks that a segment above its own limit still refuses. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Teach the host section builder the forms the driver now takes: - kernel segments __KERN_0..__KERN_n in order; - BAR slot 1 at __TEXT,__const binds index 1007, which names the constants whenever LOAD slot 1 carries them (no kernel section, or kernel sections bound as buffers). A program without kernel data used to leave that slot unbound; --no-constants-ref keeps that behaviour for comparison; - a program with several kernel sections, or with a kernel section and a constant operand, lists each kernel section in the generic section after the surfaces and the scratch, as an input of the section size with the next input ID, and binds every kernel base to its ID. Buffer references with names longer than seven bytes already parse. The sections of the add-128 fixture, the conv/relu program and Apple's add [1,1,128,128] program are byte-identical to before. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
Describe what the H16 validator now takes from Apple's compiler: the provenance note, STAB entries, SG_NORELOC on __TEXT, longer buffer reference names and kernel data split over __KERN_0..__KERN_15, with the aperture records and relocations that go with them. Describe what index 1007 names, the kernel-buffer form of a program with split kernel data or constants next to kernel data, and the 2 GiB budget, and say that the buffer form has not been run on hardware. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
…ller The H16 firmware checks every EXECUTE buffer descriptor against the buffer size the program's generic section declared at LOAD, like H17 does: a descriptor smaller than the declared buffer makes the firmware refuse the request, and the engine hangs until it is booted again. H16 descriptors carry the HWX section size. That covers programs whose surface section spans the whole buffer, but Apple-compiled HWX keep only the tensor in the section: a [1, 512] add has a 0x400 section in a 0x4000 buffer, and the Parakeet encoder mask has 0x1780 of 0x4000. Both hung on every EXECUTE. Send the larger of the declared size and the section size on H16. A section that already covers the declared buffer sends the same size as before; the declared size never exceeds the mapping, which LOAD checked. With the sections grown to the buffer size in the file, the [1, 512] add and the whole encoder run on the J616s, so the size is the only change they need. The test sends a section holding only the span and expects the declared size. Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
|
Test report from Claude (Opus 5.5) for niteria. The light sensor's sleep handling here also fixes the J700 (MacBook Neo, T8140, CT817 sensor), and we're dropping our own fix in favour of it. What we tested. integration/aurora Without a fix, after the first deep sleep the sensor stops reporting: the mailbox interrupt rate drops from about 51 per 10 s to 0 and the reading stays at its last value for the rest of the boot. With this PR, after a deep sleep woken by the RTC alarm:
(The 10.75 under "covered" is the reading before the finger landed.) An earlier module-swap test on 2026-11-10 gave the same interrupt-rate result over two more deep sleeps. Our fix, for comparison. We had a fix with the same structure: interval 0 before the sleep, the probe's full arming sequence after it. We never opened it because this PR covers the J700 too. Its one extra is leaving the interval at 0 on unbind, so a later probe starts from the state |
J616s (MacBook Pro 16", M4 Pro, T6040) running Linux at EL2 under aura: hibernation and suspend-to-RAM with the desktop session kept. Builds on #1445, which is merged.
Update 2026-11-13, night (head 6e7d5e4)
305 commits on integration/aurora a34d26c; the PR does not conflict. The base moved twice during the day (4277bdd, a34d26c). The rebase onto the second one dropped two commits of the series: the base now carries the T6041 ProRes encoder (
media: apple: proresby RyanTheTide), so the ProRes part ofmedia: apple: ProRes on T6041 and the ISP across sleepandmedia: apple: prores: drop a store that the suspend already madeare gone; what is left of the first ismedia: apple: isp: ask the sleep controller whether the power is lost(a dry run keeps the power, so the ISP must not stop its firmware for it). Since the first update of the day (1ea066e) these were added:pm_hibernate_is_loading()for drivers, an arch hook for cleaning the pages of a loaded image (ARCH_HIBERNATION_CLEAN_IMAGE), an admission hook and two arm64 hooks (layout cookie, nosave pages) that aura-hibernate.c fills, and a record the loading kernel leaves so the restored kernel knows whether another boot loaded it (the SEP uses it instead of the PMP restart counter). A hibernation that ends before an image exists now recovers the devices (PMSG_RECOVER) instead of running their restore callbacks, and 13 drivers lost the check that guarded against that.READ_ONCE/WRITE_ONCE, the once-per-machine power check is documented and atomic; the S2R warm restarts share their firmware return; unused includes dropped;apple_rtkit_idle()reports an idle that kept the firmware's memory apart from an error.physandstruct phyinstead of a node pointer. DP IN 1 of a tunnel gets PCLK1 as well (as on T6030 and T8132). These commits were not run on a USB4/Thunderbolt device (none here); they are separate commits and carry that note, so they can be tested or dropped on their own.Run on the head of the previous rebase (8acba58, without its last commit, the Thunderbolt-only PCLK1 one), one boot, HDMI + DisplayPort in picture-by-picture, USB3 disk, no dock: cold boot (all three displays lit, ANE, ProRes, AES, Wi-Fi, BT, Touch ID, fans taken by the SMC); suspend-to-RAM four times (wake record
MBSE 0x10650, noirq resume 113-120 ms, devices 560-580 ms); suspend-to-idle; dry run 2 ("a real commit would go on here (0 check(s) failed)"); a sleep refused at the enclave's request in the deep path (no SIO message, fans taken after); a hibernation aborted before the image (pm_testdevices: devices recovered, SEP session kept, display and radios up); two hibernations from the desktop in reboot mode in one boot (restored, 14 CPUs, SEP attached again, fingerprint listed, Wi-Fi and BT up, RTC alarm kept) each followed by a suspend-to-RAM.Local checks on the head: the full host test suite (the one failure it showed is fixed), KUnit g1 (1708 passed; the five
apple-display-gate-t6041-maxcases fail as they do on the base), the Apple device-tree check (no new warnings,apple,sleep.yamland the USB4 router binding pass).Run on this head (with an unrelated local series in
drivers/accel/ane, which does not touch sleep): cold boot (three displays lit, ANE without timeouts, SEP, Touch ID, fans), the ProRes encoder through the base's driver (4 frames, no error; the frame header differs from the earlier driver in three bytes of colour metadata, the coded data is equal), suspend-to-RAM three times, suspend-to-idle, dry run 2, a sleep refused at the enclave, a hibernation aborted before the image (devices recovered, SEP session kept) and one hibernation in reboot mode (restored, SEP attached again, ANE restarted cold with no program replayed, fingerprint listed, radios up) followed by a suspend-to-RAM.Not run: the dock, a KVM guest across sleeps, a disk behind a hub, a USB4/Thunderbolt device.
Base
sleep.c) met three of the clean-up commits: the shared header now carries the base's definitions, the PMU write helper takes the USID as the base's does, and what the base reads from its match data (the PMU write command, the boot stage, the response vector's enable for the sleep) stays with the T6040 part as its own values. The 89 on top are new in this push and are listed under "New in this push".phy: apple: t6040: tolerate a busy recovery domain, AxxzyWasTaken'sspmi: apple: drop replies left by firmware at a firmware-driven resume) keep their authors and trailers.What is in it
pm_hibernate_is_restored()lets restore callbacks tell a restored image from an aborted hibernation; a boot chain with a fixed layout (aurahib=1) admits hibernation.sleep.c+sleep-t6040.c,struct apple_sleep_partinsleep-internal.h; one platform driverapple-sleep, the node enabled per board, on the J616s only). The entry takes the hardware down in a fixed order (CPU complexes, power gates, axi2af bridges, APCIe, DCS, the MasterMini S2R timer, then the commit word) and the wake brings the same blocks back, before syscore resume. The coprocessor and enclave registry stays insleep-registry.c; the driver binds it once in probe and each SoC's part gives the two answers (T8140's rules and T6040's are the ones they had).APPLE_T6040_SLEEPstays an option, now the switch of the T6040 part underAPPLE_SOC_SLEEP(withMFD_MACSMC=y). The part keeps its own suspend ops: suspend-to-idle passes through untouched and deep is offered only on a kernel booted witht6040_sleep.allow_entry=1. Four module parameters are left (allow_entry,dry_run,sleep_wd_secs,wd2_secs; 79 before); the progress marks, PMU records, probes, dumps and the experiments that were off by default are gone, the steps that were on by default are unconditional. Dry-run levels are 1 (every step that can be taken back, refused at the commit point) and 2 (also the last steps); the old level 1 never reached the commit point and is removed.hung_stopand session quarantine are used unchanged, the hibernation events go through its notifier, and an engine quarantined at bring-up is powered off for a sleep (and left off at the resume) instead of refusing every sleep of that boot.pm_sleep_ptr()instead of#ifdef CONFIG_HIBERNATIONin PM operations,dev_*messages from the T6040 part, the sleep node's unit address, bindings forapple,t6041-display-powerandaurora,s2r-mailbox. One of them fixes a build configuration: withCONFIG_HIBERNATION=na suspend-to-RAM stopped the display firmware and could not start it again; the restart is built for every system sleep now. For the comment, rename and constant commits the objects are identical before and after;sleep.obuilt without the T6040 part has every symbol unchanged from f259e90.New in this push (89 commits)
MBSE = slpwback: afterslpwand thenwakawith no sleep between, it stopped running the fans (0 rpm with the CPU die at 100 to 113 C) and refused a fan request until the reboot; after the whole commit (WKTP,slpa, the AP idle notice) and no power loss its sensor reports stood still as well, so the thermal zones read a constant. A dry run, a device that refuses, a wake event during the entry and a refusal at the commit point all ended there, on the previous head of this series too. On T6041 the whole sequence is now sent from the sleep controller's last stop, with interrupts off and every refusal behind it (apple_rtkit_ap_idle_polled()is new for that); on the other SoCsslpwmoves from.prepareto the noirq suspend, right before the commit. A suspend that ends short of the power loss sends the SMC nothing.AP idle not acknowledged: -62. The PHY now refuses that power-off while its firmware runs. With it: a powered-down sleep counts as the coprocessor's power cycle, a host whose USB3 is not back at a wake stays at USB2 and tries again at the next wake, and the CIO bring-up recovers the coprocessor and shuts the lanes down when it fails.mode set failed: -5of every suspend-to-idle with an HDMI display); the hotplug that reports the sink back sets the mode. A T6041 sleep keeps to the pipe's own power words; a firmware that was given up stays stopped across an S2R, and a dead internal processor no longer refuses every sleep; the sleep registers are mapped once at probe.sending frame failed (-19)at the first wake of a boot).roles.PM_POST_*, the LSTX level at a router stop keyed on T6040, the T6040 DP IN adapters kept disabled, no watch for a router whose node is disabled. Without a USB4 device here these ran as regressions only.timer_wakeupsinstead ofirq_timeoutsin the ANE's debugfs.macsmc_sleep_order_testexpects the lid read (it failed at the base); new KUnit cases for the SMC's last stop; the host tests of the PM callbacks follow the code they extract.Hardware results
J616s (48 GB), firmware 26.7.1, aura main (9887a6b5) at EL2, kernel built from this tree with
APPLE_SOC_SLEEPandAPPLE_T6040_SLEEPenabled.This head (278b7b9) is the rebase onto aa68b3c of the head the tables below were run on (4b0be95 on fdef45b), plus one commit (
dmaengine: apple-sio: stop the T6041 firmware at the sleep's commit). On the rebase (3d13866) with that commit's module: cold boots, three suspends to RAM, one suspend to idle, a level 2 dry run and two sleeps refused at the enclave's request, with the panel and both external displays, Wi-Fi and Bluetooth back each time. Hibernation and the tables below were not run again.On 4b0be95, one boot. Set-up: a Samsung G95NC in picture-by-picture with one half on the HDMI port and the other in DP alternate mode, a USB3 disk, charger; no dock. All three displays were seen lit after the boot and after every step.
mode set failed; the HDMI half is back with the firmware's hotplug, about 5 s after the wake.On the previous base (6970a51) the same commits ran over five kernels as they were written, most of it with a dock (hub, Ethernet, card reader), the USB3 disk and one USB-C DP display:
-62, 9 SuperSpeed links before and after. Before the fix: 2 of 2 lost USB3.drop_next_power_down_ack)apple_sepsleep_refuse_before_send), and after an RTC alarm that fired during the entry.Not run on either of these two heads: anything with the dock (it was run on the previous base only), the KVM guest across the sleeps, a USB4/Thunderbolt device (none here). T8140 was not run by me on any head, and the SMC and wake-time commits change paths it shares: the noirq
slpwon every SoC,device_enable_async_suspend()on the dwc3 glue, the BCM4388 restart, the skipped 100 ms insn201202x_resume.Review
The comments and commit messages of the 89 new commits follow the same rule as the rest since the last review: they say what the hardware or firmware does and what was measured on the J616s.
Checks
Run on 4b0be95 against its base fdef45b (not repeated after the rebase onto aa68b3c), on an aarch64 host with its own compilers (gcc 16, clang 23, rustc 1.99), not the pinned ones of the workflows.
tools/asahi/run-host-tests.pybrcmf-recovery-testsamong them). Without the shims 28 runs fail on this host's compilers; that run was not repeated at this base.apple-display-gate-t6041-maxcases that fail at the base as well (base: 1686 tests, those five andmacsmc_sleep_order_test, which passes with the series).boot.kunitconfigandtransport.kunitconfigdrivers/soc/apple/sep.kunitconfigapple_sep*) 301 of 301.scripts/dtc/apple-dt-check.sh(CHECK_DTBS on every Apple tree,dt_binding_checkon the changed bindings)sep-sourceworkflow: thetools/aurora-septests, the three DWC3/ATC compile profiles-Oones and the ABI step included); the threeapple-dwc3-atc-compile.shprofiles compile;apple-sep.obuilds.checkpatch.pl --stricton the commits written for this pushOpen
WARNINGattypec_altmode_update_active()came once in the same re-cabling and was not looked at.ignore_loglevel: unchanged from the previous description. Independent of sleep.usbcore.old_scheme_first=Yand the ports' fast-enumeration quirk took 0.64 s of it here with the same devices and device numbers; that is a setting, not part of this series.WKTPis written 0, and whether it loses its fan policy afterslpw+wakaas this one does (then its noirq path has the same hole after the noirq phase that the last stop closes on T6041); whethersn201202x_resumemay skip the 100 ms on every SoC with that controller; whether the AIC mask resync after a resume from disk should be registered for every SoC; whether a host left at USB2 by a wake should try a normal start at once instead of at the next wake. 263989e (DART in an off domain) is not in here.How to try
Deep sleep stays opt-in, on the kernel command line:
With
t6040_sleep.dry_run=1(writable at run time) the same request stops at the commit point and resumes warm.