Skip to content

drm/asahi: m3: restore the M3 MacBook Air GPU on 7.2 - #187

Merged
maralcbr merged 8 commits into
integration/aurorafrom
review/t8122-runtime-7.2
Oct 24, 2026
Merged

maralcbr merged 8 commits into
integration/aurorafrom
review/t8122-runtime-7.2

Conversation

@scottjones

@scottjones scottjones commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

On 7.2, apple,agx-t8122 only reached m3::refuse_probe(). This ports the 7.1.12 release-20 runtime (c46d7dc) onto the current DRM registration, VM job lifetime and UAT APIs, behind CONFIG_DRM_ASAHI_M3_T8122 (default n). It still needs asahi.t8122_start=1, as on 7.1.12.

 probe(apple,agx-t8122)
-  m3::refuse_probe()                        # always ENODEV
+  t8122_admitted()                          # G15G identity gate, asahi.m3_backend
+  probe_t8122()
+    m3_drm::Backend::start()                # 7.1.12 admission, InitData, PMP vote, ASC/RTKit
+      adopt_uat()                           # Uat::new_adopted + g15::uat::Window, as G15 does
+    drm::Registration::new(gpu: Backend)    # stopped again on unbind

The commits:

  1. The 7.1.12 runtime, restored as it was and not wired in. g15_raw.rs and initdata.rs are its #[versions] structures expanded for G15/V14_8_3, so the version matrix is unchanged; they match rustc's own expansion field for field.
  2. The 7.2 port.
  3. A pmp-report fix. The rebase replaced T8122's 14.x GPU-readiness wait with a T6030-only one, so every T8122 GPU power vote returned -ENODEV, even with the PMP running.
  4. to 8. Review fixes: the dummy page back at the address the firmware is given, a failed job's VM quarantined before its fence signals, the adopted UAT kept until ASC stops on a failed start, a bounded compute debug read, and T8122 cases and mutants in the PMP supplier suite.

Pro/Max, M1/M2 and G17 are unchanged. The shared-code edits are additive or cfg-gated:

  • a gpu::Gpu::admit_vm hook for the per-file client gate, and gpu::Gpu::unknown_page for the dummy page (default: the geometry's page, as before);
  • an mmu::m3 helper module;
  • three debug flags;
  • F32::to_bits;
  • Completion/RtKit accessors that 7.2 dropped.

Evidence

Tested on a MacBook Air 13" M3 (J613), stub firmware 14.8.3, encrypted install, with chosen.asahi,t8122-gpu/-gpu-power-standin/-gpu-fuse-leakage/-dcp=1.

  • Before:
    • edge 7.2.10: G15G: T8122 revision 2.0 identity admitted (10 active / 10 slots); image and hardware config incomplete, startup refused. No render node.
    • The reference was 7.1.12 m3gpu: GPU up, mesa-m3 active.
  • After, at this PR's head 4888ad0a0f (kernel 7.2.11-m3air-ARCH #7), with an Aura Stage 2 that doesn't reserve the T8122 dcpext firmware (v0.1.0-6-g5809f60b) and the release mesa-m3 26.1.4.m3.2-5:
    • M3 G15G verdict: firmware-running at 1.927 s, then job-completed for the first compute and the first render job;
    • the internal display on apple-drm (eDP-1, 2560x1664), with Hyprland on the GPU through mesa-m3 (decision=active, so the client gate admits it);
    • gpu-heat: renderer zink … Apple M3 (G15G C0) (MESA_HONEYKRISP), 11,576 frames in 3.0 s, pixel readback correct;
    • compute-check: PASS, 1265 runs, 0 wrong;
    • asahi-m3/progress: completed=4791 healthy=1;
    • no GPU faults, timeouts or firmware crashes.
  • Earlier runs, not this head: the first runs were build #5 from d632ac85a4 on our development branch, before the client gate and the review fixes, with Aura v0.1.0-221-gb9ad403a:
    1.6316 apple-pmp-report: PMP ready … ack 0x218f0
    1.6525 M3 G15G: PMP GPU device 5 power acknowledged
           MMU: initialized … / M3: InitData self-check passed
           M3 G15G verdict: firmware-running
    1.6583 M3: firmware ready; common DRM GEM/VM frontend registered    # card1=asahi, renderD128
    
    gpu-heat 3 64 64 8 gave 11,584 frames in 3.0 s with a correct readback, compute-check 2 PASS with 1242 runs and 0 wrong, and completed=4139 healthy=1. The firmware identity, InitData, leakage and performance-state lines match the 7.1.12 boot on the same Mac.
  • Builds: the option off (as edge ships), G15 only, and G15 + T8122 build locally. No CI job builds the runtime: the CI compile check covers only C (here pmp-report.c, no new W=1 warnings), and the package build uses the shipped config, which leaves G15 and T8122 off. Per-commit receipts for the option-on build are in a comment below; a CI job for that config can follow.
  • Host tests: CI's host tests pass. Locally the full tools/aurora-ci manifest gives 151 pass and 6 known failures; selftests/drivers/gpu/apple-dcp/run.sh also fails locally on the untouched base 42672ed, and this PR doesn't touch drm/apple. The PMP supplier suite now also builds the T8122 wait switched on. DISP resolution by soc-device record isn't covered by a host test yet (follow-up: a T8122 overlay in the graph suite).

Known issues, not from this PR:

  • Aura b9ad403 (via omacom/m1n1 soc: apple: add Apple SEP driver #7) always reserves the T8122 dcpext firmware. With it, the external DCP probe times out (-110) and the internal DCP firmware crashes about 12 s into boot, so the panel goes dark; the GPU still runs. Edge's own 7.2.11 kernel does the same. Raised on m1n1-aurora: build from omacom/m1n1 and migrate aura installs omarchy-pkgs#1513.
  • An encrypted J613 needs apple_pmp in the initramfs once that reservation is in place: the display handover starts the PMP before the root is unlocked, and pmp-report gives up after 20 s.

Merge Danger

Door: two-way

The option is off unless enabled, and the runtime only starts with asahi.t8122_start=1.

Blast Radius: M3 Air

  • Turning it on requires DRM_ASAHI_G15, which also enables the G15 backend for the M3 Pro/Max. Whether to set either in asahi.config is your call; this PR doesn't.
  • Unported from 7.1.12: the devcoredump on the first fault (it's logged instead), and starting the GPU without a render node (asahi.m3_expose=0 now refuses up front).
  • Only the 13" J613 has run this. J615 is allowed by the Kconfig help and the board table, but needs its own run, a cold boot and an unbind/rebind on hardware before anything enables the option.

🤖 Generated with Claude Code

scottjones and others added 3 commits October 23, 2026 02:13
Bring back, unchanged, the M3 runtime that starts the T8122 (M3 MacBook
Air) GPU on the release-20 kernel (c46d7dc, the source of
linux-aurora-m3gpu 7.1.12.aurora2-20261017.20): the runtime, its
firmware admission, InitData, device, RTKit, memory, submission and
client files, the T8122 start experiment, and the 7.1.12 hw tables
(hw.rs, hw/t8122.rs, hw/agx3.rs, identity.rs).

g15_raw.rs and initdata.rs are the G15 (G15, V14_8_3) expansions of
7.1.12's fw/initdata.rs and initdata.rs: every #[versions(AGX)] item
replaced by its G15V14_8_3 instance, which 7.2's version matrix no
longer generates. The expansion keeps the source text; its eleven G15
structures match rustc's own expansion of c46d7dc field for field.

Nothing declares these modules yet, so this changes no build. The
next commits adapt them to the 7.2 driver.

Co-authored-by: Chris Kearney <303316+iconidentify@users.noreply.github.com>
Co-authored-by: Eryk Wieliczko <github@wieliczko.ninja>
Co-authored-by: Satya Benson <satya@benson.earth>
Co-authored-by: Naeem Malik <malik2015naeem@gmail.com>
Co-authored-by: garymeyerca <garymeyerca@users.noreply.github.com>
Co-authored-by: DjDeveloperr <hey@djdev.me>
Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
Wire the restored 7.1.12 M3 runtime to the 7.2 driver behind
CONFIG_DRM_ASAHI_M3_T8122 (default n), so the M3 MacBook Air (J613,
J615) GPU runs again on its 14.8.3 firmware. A T8122 probe still passes
the G15G identity gate and the backend selection first, and the runtime
still starts only with asahi.t8122_start=1; otherwise the probe is
refused as before. Other GPUs are not affected: T6030/T6031 keep the
G15 backend or the refusal, and the T6030/T6031 start paths and the
T6031 start experiment are dropped from the runtime.

On 7.2 the runtime:
- registers through drm::Registration as a gpu::Gpu backend, like G15
  and G17, and is stopped on unbind while its device resources are
  live; the completion worker moves from the DRM device data into the
  runtime's RTKit state;
- keeps user mappings alive across accepted work with the shared VM
  job lifetime (VmJobGuard, retain_job, deferred unmaps), the
  generalized form of 7.1.12's M3 VM job lifetime, on VMs created with
  tracked status;
- adopts the firmware's UAT as the G15 backend does on 7.2
  (Uat::new_adopted and g15::uat: the PPL exchange, TTBAT context 0,
  the host window at root entry 2 through the shared L2) instead of
  7.1.12's M3-only handoff mode in mmu.rs/pgtable.rs. The firmware-
  walked pages are cleaned to the point of coherency, the host window
  is linked before the InitData and each batch reach the firmware, and
  context 0 is invalidated when a job's command aliases go. The option
  therefore depends on DRM_ASAHI_G15;
- refuses VMs to userspace that did not ask GET_PARAMS for the whole
  global parameter structure (7.1.12's per-file client gate), through
  a new gpu::Gpu::admit_vm hook that admits every client elsewhere.

Smaller 7.2 adaptations: the IoMem/Devres, IoSysMap and RTKit buffer
APIs; Queue::submit's registration argument; quiet MMIO mappings in an
mmu::m3 helper module; the M3 debug flags, F32::to_bits,
Completion::complete/try_wait_for_completion/wait_for_completion_timeout
and RtKit::is_running/is_crashed, which 7.2 dropped; the M3 module
parameters move into m3_params, and m3_soc.rs gets back its full 7.1.12
table, cfg-gated with the runtime. asahi.m3_expose=0 is refused before
anything starts. The devcoredump fault snapshot is dropped (7.2's
kernel crate has no devcoredump binding): the first failure is logged.

Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
…e M3 runtime

The 7.2 rebase replaced the T8122 14.x branch of
apple_pmp_report_wait_supplier_ready() with a T6030-only one, so on an M3
MacBook Air every GPU power vote returns -ENODEV even with the PMP
running. With the new hidden APPLE_T8122_GPU_PMP_LINK, which
DRM_ASAHI_M3_T8122 selects (as DRM_ASAHI_G15 selects
APPLE_T6030_GPU_PMP_LINK), wait for the unique T8122 report's display
request (DISP, reg 7) to be ready and acknowledged before AGX, as on the
7.1.12 kernel the runtime was qualified with.

The PMP graph and supplier host tests copy the dispatch, so they copy the
T8122 wait too, built off there; their mutations still target the T6030
path.

Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
@scottjones
scottjones requested a review from maralcbr as a code owner October 23, 2026 11:50
@greptile-apps

greptile-apps Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The changes since the previous review appear safe to merge, and the reported compute-stream failure is fixed.

Summary

Restores the M3 MacBook Air GPU runtime behind the default-off CONFIG_DRM_ASAHI_M3_T8122 option and asahi.t8122_start=1.

  • An opt-in M3 runtime brings the T8122 GPU up through the Asahi DRM driver.
  • M3 clients can submit checked render and compute work through DRM queues.
  • T8122 GPU power requests wait for the linked display request to become ready.
  • Shared DRM and MMU code gains the hooks the M3 runtime needs.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["T8122 probe"] --> B{"Build option and startup gates pass?"}
    B -->|No| C["Refuse probe"]
    B -->|Yes| D["Check bootloader handoff and firmware"]
    D --> E["Acquire PMP power vote"]
    E --> F["Start ASC and adopt UAT"]
    F --> G["Publish InitData and await readiness"]
    G --> H["Register common DRM frontend"]
    H --> I["Run render and compute jobs"]
    H --> J["Unbind: stop runtime"]
Loading

Reviews (2) · Last reviewed commit: "tools/asahi: test the T8122 14.x PMP wai..." · Reviewed by Greptile

Comment thread drivers/gpu/drm/asahi/m3/m3_compute.rs Resolved

@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.

Thanks @scottjones, this is a careful port. I checked the first commit blob by blob against c46d7dcdb871: 32 of its 34 files are byte-identical to the 7.1.12 sources. With the option off, the pmp-report change keeps edge exactly as it is, because T8122 already got -ENODEV from the T6030 path. On your UAT question, I agree with reusing the G15 adoption (Uat::new_adopted plus g15::uat::Window) rather than putting 7.1.12's M3-only handoff mode back into mmu.rs/pgtable.rs.

Two things before merge:

  1. The dummy page moved. 7.1.12 mapped each VM's dummy page at the backend's unknown_page(), which the M3 runtime returned as 0x2ff_ffff_8000. On 7.2, file.rs:550-555 maps it at uat_geometry().unk_page(). With the 42-bit geometry from m3/m3_drm.rs:234 that is (1 << 42) - 0x8000 = 0x3ff_ffff_8000 (mmu.rs:187-198). m3/initdata.rs:125,832 still gives the firmware 0x2ff_ffff_8000 as unk_30, so the firmware's unknown page is now unmapped in every T8122 VM. Could you add a gpu::Gpu hook for the dummy-page address, defaulting to uat_geometry().unk_page(), and have the M3 backend return RUNTIME_UNKNOWN_PAGE? That way the two can't drift again.
  2. Nothing in CI compiles the runtime. compile-check.py skips every .rs file (tools/aurora-ci/compile-check.py:639-640, and the "Rust objects … are left to the package build" note in tools/aurora-ci/README.rst). The package build uses the shipped config, which has CONFIG_DRM_ASAHI=m and neither G15 nor T8122 (arch/arm64/configs/asahi.config:47). So "the CI compile check (W=1, per commit, with the options on) finds no new warnings" only covers the C side, and the 15k lines under CONFIG_DRM_ASAHI_M3_T8122 are only ever built on your machine. Please correct that line in the PR body, and post the per-commit receipts for the option-on build: the config fragment, the rustc and bindgen versions, the command, and the result for each of the three commits. A CI job for the option-on config can be a follow-up.

Should fix, here or in a follow-up:

  • Failed jobs don't quarantine their VM. Packet::finish records the error and signals the fence (m3/m3_submit.rs:87-96), and the comment at :91-92 says the runtime quarantines the guard. Nothing on the M3 path calls VmJobGuard::quarantine(), though. After a timeout, userspace can unmap and close what a retained job may still be running against. Unmap invalidates the TLB, so this ends in a GPU fault, not freed memory, and 7.1.12 behaved the same. But 7.2's shared job lifetime supports it now: please quarantine a still-retained guard before signalling its error fence, as g15/job.rs:116-120 does, and fix the comment.
  • Startup unwind order. Once adopt_uat has pointed TTBAT context 0 at the kernel-owned lower root (g15/uat.rs:358), a failure in Config::new or window.sync_all drops uat and window inside the closure (m3/m3_runtime.rs:1013-1017). That happens before stop_asc() at :1026, and the retain-on-stop-failure branch can't retain tables that are already freed. It's an error path after an armed start, so this isn't a blocker, but please keep the UAT owners alive until ASC has stopped.
  • The T8122 PMP wait isn't tested. Both host suites build it with CONFIG_APPLE_T8122_GPU_PMP_LINK=0 (tools/asahi/t6030-pmp-graph-tests.c:22, tools/asahi/t6030-pmp-supplier-tests.py:57), so apple_pmp_report_wait_t8122_14 returns at its first check in every case. Please add a config=1 T8122 control: DISP resolved by soc-device record, plus mutants for machine scope, supplier compatible, duplicate or disabled report, the apple,pmp shape and identity, and a no-ack or disabled DISP entry. That would match the T6030 coverage.

Nits, fine as follow-ups:

  • Please name the commit behind the J613 evidence. "This branch at 7.2.11" could be any of the three heads.
  • Backend::stop doesn't drain a queued completion work item. It's harmless today, because the worker sees None and returns (m3/m3_completion.rs:33), and 7.1.12 was the same. It matters if the module is ever unloaded right after an unbind.

Checked and fine:

  • The T8122 DISP request bit is resolved by soc-device record. The display gate adds apple,soc-device-record on T8122 (drivers/soc/apple/t6030-display-gate.c:870-872), and apple_pmp_report_bit maps it (pmp-report.c:452-474). The new wait is stricter than 7.1.12's and fails closed.
  • adopt_uat takes the regions in m3_board.rs:122-127 order, and every window mapping is one 16K page inside a validated, aligned region.
  • Backend::stop is idempotent, runs on unbind while devres is live, and doesn't deadlock with the completion worker.
  • The admit_vm gate records the GET_PARAMS size only after a successful copy, and every other GPU admits by default.
  • t6030-pmp-supplier-tests.py --mutations passes locally (controls pass, 21 mutants killed), and so does g15-retention-tests.py --mutations (23 cases).

CI: only ci / plan and ci / CI self-test were listed, both pending, so commits, compile and host tests hadn't run yet.

For release, not this merge: J615 is in the Kconfig help, but only J613 has been run. Before anything enables the option, I'd want a J615 run, a cold boot and an unbind/rebind on hardware.

I'll approve once the dummy page and the build receipts are in.

unsafe { core::arch::asm!("mrs {x}, CNTFRQ_EL0", x=out(reg) value) };
value as u32
}
fn uat_geometry(&self) -> mmu::UatGeometry { mmu::UatGeometry { ias: 42, oas: 42 } }

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.

With this geometry, file.rs:550-555 maps the dummy page at 0x3ff_ffff_8000, but m3/initdata.rs:125,832 gives the firmware 0x2ff_ffff_8000. 7.1.12 got that address from the backend's unknown_page(), so please bring back a backend hook for it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 8e864a57c4. gpu::Gpu::unknown_page() defaults to uat_geometry().unk_page(), so other GPUs map their dummy page where they did before, and file.rs now maps it there. The M3 backend returns RUNTIME_UNKNOWN_PAGE, which also ends its user_range(), so the firmware's unk_30, the mapping and the user range share one constant.

Comment thread drivers/gpu/drm/asahi/m3/m3_submit.rs Outdated
// A scheduler job/fence and the runtime's last packet can outlive
// hardware retirement. They must not keep the VM's active-job count
// nonzero: GEM closes otherwise accumulate across completed frames.
// On failure the runtime quarantines this guard with the packet until

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.

Nothing on the M3 path calls VmJobGuard::quarantine(). Please quarantine a still-retained guard before signalling the error fence (as g15/job.rs:116-120 does), or correct this comment.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 75c5823f60. Packet::finish now quarantines a guard that is still held before it records the error and signals the fence, as g15/job.rs does, so after a failed job, unmaps and closes on that VM wait until the runtime drops the packet; the comment is corrected. Unlike G15 it also quarantines on ECANCELED: withdraw has already released the guard of a packet that was never published, so a guard still held at cancel belongs to live work. Separately, and predating this, M3 records ECANCELED as sticky VM status where G15 only reports it; we'd leave that for a follow-up.

Comment thread drivers/gpu/drm/asahi/m3/m3_runtime.rs Outdated
// every context's upper half, and the host window (root entry 2) through the
// shared L2. The RTKit is awake and no initdata or GPU job has been published.
let (uat,mut window)=adopt_uat(&drm,device.soc(),&device.firmware().resources)?;
let config=Config::new(&drm,&uat,device.firmware(),&contents)?;

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.

If Config::new or sync_all fails here, uat and window drop before stop_asc() at :1026, while TTBAT context 0 still names the lower root. Please keep them alive until ASC has stopped.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in d2666d8ca7. The adopted uat and window now live outside the closure: they're dropped only after stop_asc() succeeds, and leaked with the transport, state and device when it doesn't. A failure inside Window::bootstrap after the TTBAT write still unwinds within adopt_uat, but the only steps left there are register accesses at fixed offsets.

Comment thread tools/asahi/t6030-pmp-supplier-tests.py Outdated
command = compiler + ["-std=gnu11", "-g", "-O1", "-Wall", "-Wextra", "-Werror",
"-fsanitize=address,undefined", "-fno-omit-frame-pointer",
f"-DCONFIG_APPLE_T6030_GPU_PMP_LINK={config}",
"-DCONFIG_APPLE_T8122_GPU_PMP_LINK=0",

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.

With T8122 fixed at 0, apple_pmp_report_wait_t8122_14 never gets past its first check. Please add a config=1 T8122 control and mutants.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Done in 4888ad0a0f. The suite now builds three configurations (both links off, T6030 only, and T6030 + T8122 as the M3 runtime uses). With T8122 on it runs a T8122 graph control and its failure cases (machine, supplier and report compatibles, a duplicate or disabled report, the apple,pmp shape and identity, a missing, duplicate, disabled, incompatible or no-ack DISP entry, and the managed start and readiness), and with it off a well-formed T8122 graph is refused. There are 11 new mutants, including machine scope at the dispatch in both directions; all controls pass and every mutant is killed. One gap: the suite stubs apple_pmp_report_bit, so DISP by soc-device record isn't exercised here; that needs a T8122 overlay in the graph suite, which we'd do as a follow-up unless you want it in this PR.

@joshuaswarren

Copy link
Copy Markdown

Test of head d8ecb2e7706378e853c4a749fb8bb84a1d862d123 on three lab laptops. No regression found.

Kernel CI ran only the checks: plan, self-test, commits, compile, device trees and host tests pass. Package, KUnit and boot were skipped. I built the head by hand (release 7.2.11-pr187-ARCH+, aarch64, asahi.ko included, unsigned) and booted it one-shot on each laptop.

Laptop Result
13-inch M1 MacBook Pro PASS on 2 of 2 boots. Boot 1 logged spi-hid-apple-of spi1.0: waiting for get report failed: -110 and a Magic Mouse -110 once; boot 2 was clean. Error classes otherwise match the 7.2.11 run.
14-inch M2 Max MacBook Pro PASS. 12 CPUs, tunnel ranges as expected. One new line class against the baseline: dp-xbar probe deferral (-517) five times.
16-inch M1 Max MacBook Pro Not run yet. It is queued behind another test window.

Each laptop returned to its normal boot afterwards with the protected boot files unchanged. This does not test the M3 GPU itself, because none of these laptops has an M3.

@chriskearney

chriskearney commented Oct 23, 2026 •

Copy link
Copy Markdown

One option-on build data point for d8ecb2e7: I combined this head with merged #177 (42672ed7) and the current #182 (a089fd06). The merge was clean, and a full ARM64 Image/modules/DTBs build passed with LLVM 22.1.8, Rust 1.93.1 and bindgen 0.73.2.

Both CONFIG_DRM_ASAHI_G15=y and CONFIG_DRM_ASAHI_M3_T8122=y were enabled, along with the T8122 PMP link. I also checked the resulting asahi module for the M3 runtime/start symbols, so this did compile the new runtime rather than just the default-disabled configuration.

This is build evidence only; I don't have a J613 to boot it. It doesn't clear the dummy-page address or failure-lifetime points Marcelo raised, and option-on coverage in the production CI toolchain is still useful. Thanks for restoring this path and documenting the hardware runs.

Follow-up: this combination has now completed a one-shot test and a normal default boot on our M3 Pro/J516S. All 12 CPUs came up; hardware GL and Vulkan readback passed; no host warnings, coprocessor crashes, GPU recoveries or hang kills were recorded. Wi-Fi and dock Ethernet are up. The compositor reports the internal panel at 120 Hz, Samsung at 4K59.997 and portrait Dell at 4K60.

I repaired a local module-retention issue before the completed normal boot. These are bounded T6030 regression checks, not T8122 GPU qualification or reclaim-edge stress tests.

@joshuaswarren

Copy link
Copy Markdown

Update for head d8ecb2e7706378e853c4a749fb8bb84a1d862d123: the 16-inch M1 Max MacBook Pro ran too. PASS, no regression.

  • Candidate 7.2.11-pr187-ARCH+ booted with 10 CPUs. Smoke checks passed, including a 5 s glmark2 run on the M1 Max GPU (no GPU timeout, halt, fence or oops lines) and no HID errors.
  • Error classes in the kernel log are the same as on the stock boot, or fewer (dp-xbar deferrals 3 against 6).
  • The SPI-HID timeout I saw once on the 13-inch M1 also appears on this laptop's stock baseline boot (spi-hid-apple-of ... waiting for get report failed: -110). So it is a boot-time flake, not caused by this PR.
  • The laptop returned to its normal boot; the protected boot files are unchanged.

All three laptops are done for this head.

scottjones and others added 5 commits October 23, 2026 11:28
7.1.12 mapped each VM's dummy page at the backend's unknown_page(),
which the M3 runtime returned as 0x2ff_ffff_8000, the address its
InitData gives the firmware (unk_30). On 7.2 file.rs maps it at
uat_geometry().unk_page() instead, which is 0x3ff_ffff_8000 with the
runtime's 42-bit geometry, so the firmware's unknown page was unmapped
in every T8122 VM.

Add a gpu::Gpu::unknown_page() hook, defaulting to the geometry's page
so no other GPU changes, and have the M3 backend return
RUNTIME_UNKNOWN_PAGE, which also ends its user range, so the two can't
drift again.

Reported-by: Marcelo Alcantara <maralc@gmail.com>
Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
Packet::finish signalled an error fence while the packet could still
hold its VM job guard, and nothing on the M3 path quarantined it, so
after a timeout userspace could unmap and close memory that work the
firmware had not provably stopped was using. Unmap invalidates the
TLB, so this ended in a GPU fault rather than freed memory, as on
7.1.12, but 7.2's shared job lifetime can block it.

As G15 does, quarantine a guard that is still held before the error
fence becomes visible: mapping changes wait until the runtime drops
the packet. Guards already released (work never published, or retired)
are unaffected. Fix the comment that said this already happened.

Reported-by: Marcelo Alcantara <maralc@gmail.com>
Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
Once adopt_uat() points TTBAT context 0 at the kernel-owned lower root,
a failure in Config::new() or the window sync dropped the UAT and its
window inside the start closure, before stop_asc(), and the branch that
retains everything when ASC fails to stop could not retain tables that
were already freed.

Keep both outside the closure: drop them only after ASC has stopped,
and leak them with the rest when it does not.

Reported-by: Marcelo Alcantara <maralc@gmail.com>
Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
Compute::new() read 48 bytes of the client's CDM stream for a debug
message, whatever the stream's length, and failed the job if the read
did. A short stream ending at a mapped page boundary with the next page
unmapped passed the stream checks but then failed its first submission,
even with debug logging off (as on 7.1.12).

Read no further than the stream, and only log when the read succeeds.

Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
The supplier suite built apple_pmp_report_wait_t8122_14() only with
APPLE_T8122_GPU_PMP_LINK off, so every case returned at its first
check. Build it also as the M3 runtime does (T6030 and T8122 links on)
and run the T8122 graph: the unique, available report linked to this
PMP, with DISP (reg 7) acked, and its failures (machine, supplier and
report compatibles, a duplicate or disabled report, the apple,pmp shape
and identity, a missing, duplicate, disabled, incompatible or no-ack
DISP entry, the managed start and its readiness). With the link off, a
well-formed T8122 graph is refused.

Mutants cover the wait's config scope, compatibles, report checks,
readiness result and entry reference, and the dispatch's machine
scope in both directions.

Reported-by: Marcelo Alcantara <maralc@gmail.com>
Generated-by: LLM
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Scott Jones <scottajones@gmail.com>
@scottjones

Copy link
Copy Markdown
Collaborator Author

Thanks for going through it this carefully, blob by blob. Both before-merge points and all three should-fix points are in, as separate commits on top, so the first three commits stay as you reviewed them:

  • the dummy page is back at 0x2ff_ffff_8000 through a gpu::Gpu::unknown_page() hook (8e864a57c4);
  • a still-held job guard is quarantined before the error fence signals (75c5823f60);
  • the adopted UAT and window live until ASC has stopped on a failed start (d2666d8ca7);
  • the supplier suite builds the T8122 wait switched on, with a control and mutants (4888ad0a0f);
  • the per-commit build receipts for the option-on config are in the comment below.

We also fixed Greptile's compute debug read (e8023bba60).

You were right about CI, and the body was wrong. The CI compile check only compiles the C side, so the runtime had only ever been built locally. Our earlier "each commit builds" wasn't solid either: that run dropped the T8122 option after the first commit. The receipts below are a fresh run, and the body now says plainly what CI covers.

You were also right to ask about the evidence commit. The J613 runs in the body were kernel #5, built from d632ac85a4 on our development branch, before the client gate, the pmp-report fixes and these commits. None of them was a PR head. The head 4888ad0a0f has now run on the same Air (with the Aura that doesn't reserve the dcpext firmware):

  • firmware-running, then the first compute and the first render job completed;
  • the desktop on apple-drm, with Hyprland on the GPU through mesa-m3, so the client gate admits it;
  • gpu-heat 11,576 frames in 3 s with a correct readback;
  • compute-check PASS, 1265 runs, 0 wrong;
  • completed=4791 healthy=1;
  • no GPU faults, timeouts or firmware crashes.

So with the dummy page back at its 7.1.12 address, nothing regressed on that run. The PR body has the details and names both builds.

The Backend::stop completion drain we'd leave for a follow-up, as you suggested. And agreed on J615: the body now says only J613 has run this, and that J615, a cold boot and an unbind/rebind need to run on hardware before anything enables the option.

@scottjones

Copy link
Copy Markdown
Collaborator Author

Build receipts for the option-on configuration, one build per commit of this PR.

Config: edge's config with arch/arm64/configs/asahi.config merged (the package config), plus:

CONFIG_DRM_ASAHI_G15=y
CONFIG_DRM_ASAHI_M3_T8122=y
# selected: CONFIG_APPLE_T6030_GPU_PMP_LINK=y, CONFIG_APPLE_T8122_GPU_PMP_LINK=y

CONFIG_DRM_ASAHI=m, CONFIG_RUST=y. At each commit we set both options again and ran olddefconfig. The first commit predates the T8122 symbol, so it builds with G15 only.

Toolchain: rustc 1.85.0 (4d91de4e4 2025-02-17), bindgen 0.72.1, clang/LLD 22.1.8, on aarch64.

Command: make O=<out> LLVM=/usr/lib/llvm22/bin/ BINDGEN=<bindgen wrapper> -j10 drivers/gpu/drm/asahi/ drivers/pmdomain/apple/

commit subject T8122 errors Rust warnings
e51f1082fa drm/asahi: m3: restore the 7.1.12 T8122 runtime sources, unwired not yet defined 0 28
ad52c9b317 drm/asahi: m3: start the T8122 runtime on 7.2 y 0 28
d8ecb2e706 pmdomain: apple: pmp-report: keep the T8122 14.x GPU readiness for the M3 runtime y 0 0 (asahi not rebuilt: no Rust change)
8e864a57c4 drm/asahi: m3: map each VM's dummy page where the firmware expects it y 0 28
75c5823f60 drm/asahi: m3: quarantine a failed job's VM before signalling its fence y 0 28
d2666d8ca7 drm/asahi: m3: keep the adopted UAT until ASC stops on a failed start y 0 28
e8023bba60 drm/asahi: m3: don't let the compute stream debug read fail a job y 0 28
4888ad0a0f tools/asahi: test the T8122 14.x PMP wait in the supplier suite y 0 0 (nothing rebuilt: tools only)

All 28 Rust warnings are G15's existing dead-code warnings under DRM_ASAHI_G15=y (g15/hw.rs, g15/wire.rs, g15/power/idle.rs and others); none are in m3/. No C warnings.

At the head, these three configurations build the same targets with 0 errors:

  • off, as edge ships;
  • G15 only;
  • G15 + T8122.

The full Image modules dtbs build passes too.

Thanks to Chris for an independent build of d8ecb2e7 merged with #177 and #182, on a different toolchain (LLVM 22.1.8, Rust 1.93.1, bindgen 0.73.2), with the M3 runtime symbols in asahi.ko. He also booted that build on an M3 Pro (J516S) as a T6030 regression check.

@scottjones

Copy link
Copy Markdown
Collaborator Author

Thanks for running d8ecb2e7 on all three Macs, and for doing the stock baselines alongside. That makes the comparison easy to trust.

  • dp-xbar -517: that's DCP's devm_mux_control_get(dev, "dp-xbar") (drivers/gpu/drm/apple/dcp.c:4459) deferring until the mux controller has probed, so it's probe order; the 16" showed 3 against 6 at baseline. This PR doesn't touch drm/apple, the mux or the device trees.
  • SPI-HID -110: agreed it's a boot-time flake, since it shows on the 16" stock baseline too.

The new head adds the review fixes. Your M1/M2 results should carry over, because the only change outside T8122-gated code is the gpu::Gpu::unknown_page() hook:

  • its default returns uat_geometry().unk_page(), exactly what file.rs mapped before, so every other GPU maps its dummy page at the same address;
  • the rest is in m3/, built only with CONFIG_DRM_ASAHI_M3_T8122, or is host tests.

@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 4888ad0. The dummy-page address, short compute debug read, failed-job quarantine and adopted-UAT cleanup fixes look correct. The UAT owners now survive the Config::new/sync failure paths until ASC has stopped, and stay retained if it cannot stop. I found no remaining merge blocker in this pass.

Independent checks on this exact source tree:

  • ARM64 W=1 component build of rust/, drivers/gpu/drm/asahi/ and pmp-report.o passed with G15 + T8122 enabled, LLVM 22.1.8, Rust 1.93.1 and bindgen 0.73.2. The compiled object contains the T8122 runtime, compute, fence and dummy-page implementations. This was not a new full-kernel build or boot.
  • The PMP supplier suite passed in all three configurations; all 32 mutants were caught with passing controls.
  • G15 host tests: 61 passed, two off-tree J516C fixtures ignored. Retention fault-injection tests passed all 23 cases.
  • Six additional extracted-source Rust cases passed for the dummy-page producer/consumer, bounded nonfatal debug reads and quarantine-before-fence ordering; six deliberately broken variants failed at runtime. These use mocked boundaries, not hardware or real DMA.

The per-commit build receipts and the J613 run at this head address the earlier evidence gaps. My earlier M3 Pro boot remains a regression check of d8ecb2e, not a T8122 hardware test of this revision.

Approved for the default-off, opt-in scope described here. Completion-work draining and the documented J615/cold-boot/unbind-rebind qualification remain follow-ups before wider enablement. Thanks for addressing the review points separately and correcting the build claims.

@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.

Thanks @scottjones. Re-reviewed 4888ad0a0f. Both before-merge points are in: the dummy page is back at 0x2ff_ffff_8000 and the receipts cover every commit. Approving for the default-off, asahi.t8122_start=1 scope. It still merges cleanly onto the current integration/aurora (with #182), and #182 doesn't touch any file that commits 4-8 change.

Checked and fine:

  • Dummy page (8e864a57c4). The M3 user range now ends at RUNTIME_UNKNOWN_PAGE and the 16K dummy sits right there, matching unk_30 (m3/initdata.rs:125,832). vm_create's kernel-range check stays inside the user range (file.rs:475-480). Every other GPU keeps uat_geometry().unk_page() through the default hook.
  • Quarantine (75c5823f60). quarantine() sleeps (untimed) until in-flight mapping commits drain, and M3 calls finish with Shared held. I looked for a cycle. Commit holders take residency and the GPUVM reservation before they count, and their page-table and TLB work never needs Shared or the completion worker, so I found no deadlock.
  • Failed-start unwind (d2666d8ca7). Every match arm is right: owners are kept until ASC stops, or leaked with a module reference if it doesn't. Dropping Config on a sync_all failure is safe because its root isn't published until boot.
  • Compute debug read (e8023bba60). end <= base is already rejected in agx_uapi.rs:689-700, so the zero-length case can't happen.
  • Shared code. mmu::m3, all the runtime modules and m3_soc are cfg-gated. admit_vm and unknown_page default to the old behaviour. The debug bits, F32::to_bits and the completion/RTKit accessors are additive. With APPLE_T8122_GPU_PMP_LINK=n, T8122 still gets -ENODEV.

We want this on by default, so I'd keep the switch-on in its own small PR. These two need to land in or before that PR:

  1. A second start in one boot hands the firmware freed tables. Runtime::drop (m3/m3_runtime.rs:1240-1247) and the failed-start arm free the adopted lower root after ASC stops. TTBAT context 0 still names it (g15/uat.rs:358). The next start (unbind/rebind, module reload, or a retry after a failed start) only checks ASC RUN (m3/m3_device.rs:233). It then sets RUN (m3_runtime.rs:1004) before adopt_uat rewrites context 0 (:1016), so the firmware runs with a stale root for that window. stop_asc only clears RUN. It doesn't reset the firmware or bring back a reusable RTKit or InitData state. So I'd refuse a second start per boot rather than try to make restart work. A latch claimed just before the first ASC start would do it, as long as it survives a module reload (or unloading is blocked once the latch is claimed). Clearing context 0 and then checking for zero wouldn't be safe: our own cleanup would look like a fresh handoff. This also changes what the unbind/rebind qualification should expect: a clean refusal, not a second boot of the firmware.
  2. Quarantine also catches packets the firmware never saw. Inner::fail_pending (m3_runtime.rs:173) finishes pending packets without release_guard, so a never-published packet now quarantines its VM too. The commit message says those guards are already released. A pending packet can be partly published (:51-54), and fail_active drains active before it calls fail_pending (:185-186), so a check against active won't work there. A per-packet "may have been published" flag would: set it before the first firmware-visible change (partial ring appends count, :437-453, :594-604), and release in fail_pending only when it's unset. Please don't skip quarantine for ECANCELED the way G15 does. M3's cancel only withdraws the unpublished remainder (m3_submit.rs:152-154), so active commands can still be running.

The default-on PR also needs:

  • asahi.t8122_start on by default, or dropped. Please confirm that the experiment's knobs left unset give the values J613 was tested with, and aren't refused.
  • A decision on DRM_ASAHI_G15=y. The T8122 option depends on it, and turning it on also moves M3 Pro/Max to the G15 backend.
  • The boot loader setting the chosen.asahi,t8122-* properties by default, plus the Aura fix for the dcpext reservation (omacom/omarchy-pkgs#1513). Otherwise the panel goes dark about 12 s into boot.
  • apple_pmp in the initramfs for encrypted installs.

Still open from before: the Backend::stop completion drain, and J615, a cold boot and unbind/rebind. Those can be qualified on edge.

Policy: nothing here changes existing behaviour outside T8122. Everything new is disclosed and off by default: the per-file GET_PARAMS client gate, the module params and debugfs controls. GET_PARAMS now records a size and VM_CREATE calls the hook for every GPU, but both are no-ops away from M3. One thing to keep in mind for asahi.config: the option selects the T8122 PMP link at build time, whether or not t8122_start is set.

@maralcbr
maralcbr added this pull request to the merge queue Oct 24, 2026
Merged via the queue into integration/aurora with commit be6381f Oct 24, 2026
24 of 25 checks passed
@joshuaswarren

Copy link
Copy Markdown

Hand build of the integration/aurora tip 7b96998 (contains the merges of this PR and #199, #202, #203, #204). Package release 7.2.11-tip-ARCH+, package sha256 52830bb4538e8e8f5344eacff87fbdb9ab26cc553540c36e993ba4e097561c23.

Tested so far (one-shot boot only, stock untouched):

machine boots result
14-inch M2 Max yes (candidate boot 3c4b9246, return 1beecd62) smoke equal to stock; omarchy-m-test 0.1.13: https://omarchy-m-testing.org/reports/6qHb7QcJkwg2Ref7zubzgZuA (stock reference: https://omarchy-m-testing.org/reports/RVXdswZ8LJoUJKF7vRh2KAHf)
13-inch M1 pending — machine reserved for an all-night test run; will add a line when it ran
16-inch M1 Max pending — same

CI on this PR: 9 pass, 4 skipped (attest, KUnit, boot, package).

Regressions: none found. dmesg error classes on the candidate boot match the stock baseline (known flakes only: dp-xbar -517 deferrals, brcmfmac join_pref/assoc noise, Bluetooth codec-capabilities -110). m-test check list identical to stock except two tool-level deltas, neither a functional failure: (1) hardware.drivers counts apple,mesa-fingerprint unclaimed on the tip (the node exists, no functional impact seen); (2) sep.attach reads SKIP because the SEP diagnostics ABI moved 1 -> 2 and the tool's reader expects 1 — the driver itself is up on the tip (apple_sep loaded, SEP platform profile T6020/J414s, xART scanned, trusted-keys registered, endpoints discovered), and the audio.microphone checks still pass.

Not tested: M3 paths (this PR's T8122-without-G15 build path is M3-family; the M3 Pro GPU startup in #202 and the J615 camera path in #203 compiled and booted in this build on M1/M2 but their M3-only code paths were not exercised — no M3 machine in this lab).

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.

4 participants