Skip to content

Carry aurora-silicon's G17 and M5 GPU driver work - #439

Open
edimoldovan wants to merge 171 commits into
omacom:integration/aurorafrom
edimoldovan:carry/aurora-silicon-m5-gpu
Open

edimoldovan wants to merge 171 commits into
omacom:integration/aurorafrom
edimoldovan:carry/aurora-silicon-m5-gpu

Conversation

@edimoldovan

Copy link
Copy Markdown

Carries aurora-silicon/linux's G17 GPU driver work since #139, and Erik Bourget's M5 port of it (aurora-silicon/linux j716c/t6050-gpu-max, b9dc01a37038), into integration/aurora. This is the driver half of #426; the J714c board support follows in its own PR, stacked on this one and #404.

The work is theirs. Each commit keeps its author and Signed-off-by and gets a "(cherry picked from commit in aurora-silicon/linux)" line and a Signed-off-by for carrying it. Authors:

  • Jeff Queisser (82)
  • Ryan Murray (30)
  • Jonathan Goyvaerts (24)
  • DjDeveloperr (16)
  • Erik Bourget (11)
  • Artyom Astafurov (3)
  • Michal S. (2)
  • František Balázsy (1)
  • Jahnavi MN (1, Task::tgid() from upstream 2847d9a)

What it carries

  • The aurora-silicon G17 commits after the G17 sync in 4b7aa80 (aurora-silicon d3cf19b) that this tree does not have: 58 of 74. They include T6040/T6041 (M4 Pro/Max) firmware identification and calibration, the 25G83 partial-render work, the recovery and blame series, client usage accounting in fdinfo, the statistics export, the device binding lease and the VM-reservation-only VA updates.
  • Erik Bourget's branch: the 104 GPU commits (M5 Pro, Max and Ultra, firmware 27.3 beta 1). Its 13 display, display-DART and macsmc hwmon commits are not in this PR.
  • Jonathan Goyvaerts' MMU fault bank logging (8ce1613), and the mailbox part of Ryan Murray's G17 mailbox stall bounds (9827b6b; its drm/asahi part is already here), with DjDeveloperr's receive-thread minimum utilization on top.
  • A commit of mine adapting the carried 7.3 code to 7.2.11: module parameter references, the M3 T8122 probe's binding owner and new_queue argument, the G15 identity module, cpufreq-less builds of the M5 thermal governor, and the M5 fan request returning -EOPNOTSUPP (this tree's macsmc hwmon has no kernel fan request).

Commits a carry changed to fit this tree say so in a [Eduard Moldovan: ...] line.

Not carried

  • a97f7b8, the rename to "aurora": this PR keeps the "asahi" DRM name, which this tree's Mesa accepts (honeykrisp: accept the aurora kernel driver name at every version->name check mesa#37 adds "aurora").
  • G16 (T8132) only, and the G15/G16 shared-interface fixes for building G16 next to G15: this tree does not build G16.
  • c0cd9aa and a91ef82, G15/M3 module-parameter policy changes in this tree's own G15 code.
  • The 7.3 forms of the statistics export and two-phase data setup this tree already has in its 7.2.11 form (1c771d7, 3f09610, 8a9127f), and the 7.3 merge cleanup a9e24ae.
  • e15f70bc981c (macsmc fan control): it needs aurora-silicon's macsmc fan series.
  • 34b438d (recycled firmware identities): Erik's branch fixes the same QoS-ID recycling another way; the two need merging.

This range changes include/uapi/drm/asahi_drm.h (the M5 render and compute program UAPI, DjDeveloperr); Mesa needs the matching update for the M5.

Testing

  • Build: omarchy-pkgs linux-aurora config + asahi.config, Rust on: Image and 1769 modules, modpost clean.
  • KUnit (aurora.kunitconfig through kunit.py, QEMU): 1829 cases, 1825 pass, 0 fail, 4 skip, no splats; matches kunit-expected.json (one new expected skip, a G16-only fwid case).
  • MacBook Pro 14-inch, M5 Max (J714c), macOS 27.3 beta 1 firmware: this PR + Add the T6050 (M5 Max) and the 14-inch MacBook Pro (J714c) #404 + the J714c GPU PR + a test-only stack (N1 Wi-Fi, USB host for the Ethernet cable, watchdog) boots to the Omarchy lock screen; the GPU starts (M5 primary and secondary initdata acknowledged, [drm] Initialized asahi 0.0.0).
  • tools/aurora-ci/check-commits.py: pass (no failures). checkpatch reports, on carried commits: Signed-off-by lines missing on three DjDeveloperr commits whose originals carry none, a missing SPDX tag in Ryan Murray's recovery-safety notes, and style warnings.
  • Per-commit builds: not done. The carried commits are written for 7.3; the tree builds at the adaptation commit and after.
  • Other Macs (J700 T8140, M1, M2, M3): not tested on hardware.

🤖 Generated with Claude Code

jgoyvaerts and others added 30 commits November 10, 2026 11:10
…rved regions

With reserved table regions (no-map systems such as the T6040), a
page-table page outside them went through Page::borrow_phys_unchecked(),
which is undefined behaviour when the page is other no-map memory
without a struct page. Use the checked borrow there and refuse such a
page with -EIO; systems without reserved regions keep the unchecked
borrow of an allocated page-table page.

Document the single cache invalidate of the reserved regions at boot.
It runs after the host has already written table entries, which is safe
because the T6040 cleans every host table store to the PoC
(UatQuirks::clean_tables), so the invalidate drops only clean lines. Not
invalidating again assumes the firmware stops writing the tables the
host walks once it has booted; say that this is an assumption. The
wrapper's comment claimed the invalidate came before the first host
edit, which it doesn't.

Link: aurora-silicon/linux#408
Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
(cherry picked from commit bec833e in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
The T6040 selected its firmware build only by apple,firmware-version,
the macOS release the boot loader reports. That says which build to
expect, not that it is the build loaded: a loader can write the version
for a boot firmware it merely recognises, and the init-data hash covers
only the driver's own constants.

The G16 backend already proves its build from the loaded TEXT: the
SHA-256 of the image with the entropy bytes of its GKTS and ECAP records
zeroed, plus the segment sizes. Move that check out of g16 into a shared
fwid module with its SHA-256 helper, built for every asahi build. A
build entry names the offsets of its two entropy records, which are
checked and zeroed there, as G16 did; an unknown image is reported with
the records found by their tags, so its digest is stable across boots
and a new variant is one more entry. G16 uses it as before.

A G17 firmware build now carries its image identity, and the T6040
refuses the GPU unless the fw-text region holds the 25G83 image it was
written for (measured on a J616s, macOS 26.6.2), with the DATA size of
the fw-data region. A tree without fw-text no longer gets the GPU; the
J616s tree ships it disabled until a boot loader fills it in.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
[Eduard Moldovan: integration/aurora does not carry the G16 backend: the g16/ changes are left out, and CRYPTO_LIB_SHA256 and fwid.o go to DRM_ASAHI and integration/aurora's asahi-y]
(cherry picked from commit a335c77 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Cover the shared identity code moved out of G16 with synthetic TEXT.
Entropy changes must preserve the normalized digest, non-entropy changes
must change it, malformed records must be refused, and measurement must
leave its input unchanged. No firmware image is included in the tests.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit da42c7c in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Keep a list of admitted images on each versioned firmware Build and pass
that list to fwid::identify(). Version selection uses the first matching
Build, so another Build for macOS 26.6.2 would leave its image unreachable.

Add the second normalized T6040 identity measured over two J616s boots.
The boots differ only in their entropy payloads. Compared with the
qualified 25G83 image, the remaining differences are the field at 0x23d
and the iBoot-filled patchbay/tunables area. The executable code outside
those areas and DATA are unchanged. This follows the J713 precedent in
omacom#442, while keeping whole-TEXT hashing and exact identity checks.

Factor the existing lookup so KUnit can exercise the real T6040 and J713
lists with digest measurements, without embedding firmware. Cover both
T6040 identities, both J713 identities, unknown digests and size/offset
mismatches. Keep the entropy-normalization tests.

Link: aurora-silicon/linux#442
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 26f5eb6 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Treat the OS version as a candidate-order hint. Continue to require an
exact admitted loaded TEXT image and preserve omacom#453's images list. This
extends Jonathan Goyvaerts' shared identity work.

Originally-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Link: aurora-silicon/linux#428

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 804bba8 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Wire the reader into probe and firmware construction, validating OPPs and
enabled cores before firmware starts. Use the maps, leakage and power
ceiling in the 25G83 objects, replacing bin-specific output hashes with
layout and host encoder checks. Keep the Neo path unchanged.

The old ceiling declaration remains only for the hardware-default
reference removed by the next patch. Firmware uses the calibration.

Retain GPL-2.0-only and the Gravity Linux encoder attribution to Cody Ho
and Niklas Sheth. The original T6040 work is by Jonathan Goyvaerts.

Originally-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Link: aurora-silicon/linux#428
Link: https://github.com/GravityLinux/linux

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 53877ea in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Keep the structural hardware description while requiring the loader maps
and power ceiling. Remove the last single-unit ceiling reference and its
declaration together, keeping this commit buildable independently.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 415fd2e in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Run both dynamic compute growth and the full logical queue budget checks
with the 25G83 floor of 32, alongside the existing floors. This checks
render headroom and firmware-owned QID exclusion on the M4 Pro layout.

Bring the host resource runner forward to the shared reserve_for helper
and current render reserve, retaining its capacity and stale-ID controls.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
[Eduard Moldovan: conflict resolved by taking aurora-silicon's version of tools/asahi/g17-resource-tests.py]
(cherry picked from commit 61aca8f in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
An exact completion record that has aged for 50 ms permits compute
retirement without a stamp in the ordinary generation. The recovery
path can consume queue items without completing command writes; those
cursors and an old record alone must not release command mappings.

Restrict the record-only fallback to the publication's generation.
After a restart, retain the command until a covering stamp and consumed
items provide the release witness, or the existing quarantine/stop path
takes ownership. Keep interrupted fence classification independent.

Exercise aged records with missing, stale, exact and later stamps across
a restart, consumed and busy rings, and the ordinary fallback control.
This closes a retention hazard; it does not establish the cause of the
T6040 CTS page faults or qualify recovery on that firmware.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit fcd39d5 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
The 25G83 path has no validated slot-key address. It consequently lost
progress observations too, even though they come from a separately
validated firmware-owned view. Read those observations with an unknown
key represented by zero; preserve firmware blame when ownership is
unknown or a read fails.

Report the bounded halted-firmware snapshot with its generation, reason,
slot mask, known-key count and per-slot progress. Identify stampless
retirement counters explicitly as lifetime totals so they cannot be
mistaken for commands retired by a single recovery. Read no new MMIO
addresses and change no firmware timeout, feature or voltage policy.

Test unknown ownership, incomplete progress and page-fault fallback.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 90150b0 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Readable progress is not complete ownership evidence. If even one
selected slot lacks a valid key, do not use another slot's unstarted
render to clear firmware blame. Require every sampled selected key to
name a queue before attempting host attribution.

Cover a known blamed queue with an unknown peer key, in addition to
wholly unknown keys and failed progress reads. This also keeps a failed
key read conservative on firmware builds with a known key address.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 34665a1 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
The G17 backend exported an idle-delay attribute but always started at
the native two-millisecond policy, ignoring apple,idle-off-delay-ms.
Use the existing DT property at probe and validate it against the same
2..1000 ms bounds as the existing attribute. Document that property in
the binding. Missing policy preserves the current default; other GPUs
need no platform flag or new module parameter.

Exercise absent, valid and invalid policy values and depth-one gaps
within a bounded sixteen-millisecond hold, followed by real idle release.
This supplies a board policy through the existing power-control path;
it changes neither firmware register layouts nor voltage/clock tables.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
[Eduard Moldovan: the binding change keeps integration/aurora's reg-names and adds only apple,idle-off-delay-ms]
(cherry picked from commit 6ca4244 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…ification

G17 discarded statistics payloads and unknown event words before returning
ring slots. Keep the latest full statistics sample per role/type with host
monotonic time and count in read-only debugfs, and add a static-key raw
report tracepoint for complete trace/statistics/event timelines. Copy before
publishing the consumer; retain the existing tag and transport quarantine
rules. Debugfs owns the session and samples under the device mutex without
waking firmware or reading gated core registers.

No decoded achieved-clock/power ABI is available for these firmware builds.
Do not relabel legacy pstate fields, requested OPPs or advertised maxima as
achieved frequency. Preserve raw observations so their semantics can be
qualified independently. KUnit covers full payload preservation, role/type
separation and invalid-tag bounds.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
[Eduard Moldovan: conflict resolved by taking aurora-silicon's version of g17/channel.rs]
(cherry picked from commit e4ee193 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Retain bounded first-fault evidence from the already mapped render graph:
queue identities, completion stamps, free-list balance and the oldest four
commands' ring cursors, pass timestamps and scheduler identity. Sample while
firmware is halted at state 1 before publishing recovery targets and before
acknowledging the restart. Explicitly report a borrowed/unavailable pair.

The existing recovery reason and blame alone do not distinguish a stalled
tiler from fragment execution, lost completion visibility or work that never
started. This observation makes that distinction possible without new MMIO
addresses, invented reason codes, timeout changes or weaker release rules.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 22c3c57 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…uous idle

T6040 keeps the GFX supplier powered for the firmware's lifetime, as its
PMGR DT documents. Using that supplier as CLPC demand therefore pins DCS 5 /
fabric 2 even after the GPU cores gate. Neo's activity-following supplier is
not a valid T6040 idle witness.

Add a DT-selected CLPC demand consumer. Every actual GPU publication asserts
it, including off-lock direct publication. The existing race-checked 16 ms
continuous-idle effort clear releases it; quarantined work does not count as
execution. CLPC retains its existing 32 ms hold and CPU arbitration. Firmware
shutdown and consumer destruction clear the request. An independent refcounted
request allocation is safe across provider removal, and a device link orders
the supplier. The hot path uses only a leaf spinlock, with no sleeping call,
allocation or GPU callback. Missing requested providers defer probe.

Expose last requested floor, reason bits and host timestamps alongside actual
PMC readback, and expose safe core-power plus last publication time in the
read-only G17 firmware_reports view. Generic runtime PM remains distinct from
firmware core gating: do not relabel unsupported generic PM as active/suspended.
Keep Neo's existing PMGR input and all voltages, floors and delays unchanged.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
[Eduard Moldovan: integration/aurora has no T6040 device tree or CLPC table: the t6040.dtsi and T6040 table changes are left out, and the host GPU demand interface, its probe allocation and its demand input are ported into integration/aurora's clpc.c without the vote-reason diagnostics]
(cherry picked from commit 32f7efe in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Keep the C wrapper responsible for the device layout, as the existing
sysfs wrappers do. Rust bindings include private configuration-dependent
scheduler members and cannot be named in a WERROR-safe extern signature.
The live platform device and owned request lifetime remain unchanged.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 61a2fec in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Provide a concise debugfs power view with the existing always-accessible
core power witness, host hold state, idle policy, effort, direct-publication
count and last publication time. Read under the live firmware owner without
waking the GPU. The same values accompany raw firmware reports.

Generic Linux runtime PM does not manage this firmware's autonomous core
gating and may correctly report unsupported. Report the actual firmware
power witness without enabling a fictitious runtime-suspend implementation.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 460e460 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Clear the owned CLPC request after the processor stop sequence, so a
slow shutdown does not begin the memory-floor idle hold while firmware
can still consume work. Late request destruction remains independently
safe and clears the request again without accessing provider storage.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit fa12ae8 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Resolve slot attribution while firmware is halted in state 1, alongside
its key and monitor snapshot. Previously classify() read pass timestamps
after the 3->0 acknowledgement, when resumed work could change them and
make a later-started peer appear responsible for the original fault.

Keep the captured attribution through the handshake. Unknown 25G83 slot
keys still preserve firmware blame; no new retirement or release witness
is introduced. This fixes the shared sampling race, not the unqualified
T6040 reason-2 first faults. KUnit drives the real service() handshake
and rejects a pass read after the first acknowledgement.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 8bce44c in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Record the declared TVB state, block inventory and high-water values,
plus the blamed pair's bounded render geometry/GTP layout and pending
parameter-buffer growth. All reads run in the existing state-1 snapshot;
there is no allocation, MMIO access or high-water reset.

These observations distinguish a full tiler, a delayed grow request and
an unstamped unstarted pass in the large point/barrier CTS cases. They
are diagnostics, not a timeout extension or a claim that reason 2 means
TVB exhaustion. Keep raw captures in private qualification evidence.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 0d75383 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Add static-key input-resolution and scheduler lifecycle traces. Join
these to existing publish/complete and dma_fence/sched events using the
engine/context/sequence and fence identity to separate conversion,
inline setup, dependency/capacity waits, scheduler dispatch and firmware
execution in multi-queue signal hops.

Counters are read only when each tracepoint is enabled. The trace path
does not poll a fence, allocate, request GPU power or alter scheduling.
These are measurement boundaries; no unmeasured latency saving is claimed.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 84f47ef in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…torage

25G83 packs its existing GTP sub-buffers after the tail-pointer cache.
One of them is 64 times the tile map. The inherited 32 MiB TPC limit
was applied to the combined object, so the valid 10240-square target
used by CTS point_size_10000 is rejected with ERANGE even though the
cache and tile record individually fit their original limits.

Apply TPC_MAX to the aligned cache, and retain TARGET_RECORD_MAX before
allocating or growing the object. Both bounds cap the derived auxiliary
extent. Keep the encoder's buffer sizing, address checks, allocation
accounting, retained generations and memory-pressure handling unchanged.
No firmware field or numeric resource limit increases. The same preflight
serves fresh and grown targets; Neo has no GTP tail and retains its policy.

KUnit covers the CTS geometry for both utile shapes, oversized core and
layered tile-record rejection, and unchanged Neo cache capacity. Hardware
must confirm the point case; this does not diagnose the separate 256-square
1 MiB vertex/barrier fault or decode firmware reason 2.

Link: https://github.com/KhronosGroup/VK-GL-CTS/blob/vulkan-cts-1.4.6.2/external/vulkancts/modules/vulkan/rasterization/vktRasterizationTests.cpp#L9384
Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit aecb91d in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
A J616s with 26.6.2 boot firmware (25G83, iBoot mBoot-18000.161.10) can load
a third normalized T6040 TEXT identity: TEXT 0x60000, DATA 0x138000, the same
entropy offsets, sha256 d725264d4831b95a5b8a375abf2fb5cdfbd6d7cbc7f1baa2cc8b37ee5d6e5e98.
Without it the GPU probe stops with "GPU firmware image not admitted" and the
device has no render node.

Add the digest to the 26.6.2 T6040 image list next to the two existing
identities and to the KUnit test that exercises every listed image through
the lookup used by identify().

Signed-off-by: František Balázsy <frantisekbalazsy@gmail.com>
(cherry picked from commit d42eada in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
The 25G83 firmware reads the tiling descriptor's fragment_busy word
(TA+0x7a4) only in its out-of-memory lane, at the first out-of-memory
stop of a pass. When it is non-zero the firmware compares the pass-seq
byte of the last completed fragment kick on that queue with the lane's
copy of TA+0x7b0. On a mismatch it resumes the stopped TA with the
resume-after-grow register write but without adding memory, and retires
the lane: the tiler then stops silently with no further out-of-memory
stop and no completion, and the forward-progress watchdog fires
(reason 0).

We set fragment_busy whenever the previous fragment kick had not
completed at publish, which is common in a pipelined stream. macOS
always writes 0 there on this firmware. Add Variant::fragment_busy and
clear it for V25G83, so the out-of-memory lane takes the path macOS
takes. Renders that fit their tiler heap never reach that lane, so they
are unaffected. V26A428 keeps its current behaviour.

The firmware behaviour above is from a static disassembly of the 25G83
firmware and the macOS AGXG16X kext.

In our testing on a J616s (T6040, 25G83), with the tiler heap at its
tile-count size so ordinary heavy passes must grow, this alone took
dEQP-VK.memory.pipeline_barrier.graphics.all_device.1048576_vertex_buffer_stride_2
from 7 firmware recoveries over three runs to 4; the next change
removes the rest.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
(cherry picked from commit 763b4dd in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Commit 0d9efa5 ("drm/asahi: g17: render lead commands for the 25G83
firmware") led every 25G83 fragment descriptor with a FragmentBarrier
(tag 4) that waits for the paired tiling stamp. macOS does not send
that item: its fragment submission stores item tags 1, 0xc, 0xe, 0xf
and 0x10 only, and keeps fragment-after-tiling ordering in the kick
entry's dependency 0, which we already set.

The barrier deadlocks a pass that runs out of tiler memory. The
firmware's item-ring loop stops at an item whose handler returns 0, and
the tag-4 handler returns 0 until the tiling stamp is reached, so the
fragment kick's AddKicks is only processed after its tiling pass
completes. A partial render needs that fragment kick announced while
the tiling pass is stopped (the firmware releases it in out-of-memory
state 7 by clearing the kick entry's dependency 0), so the tiling pass
waits for the partial render and the partial render waits for the
tiling pass.

Remove FragmentBarrier and write only InitBufferManager as a lead
command. V26A428 has no lead commands and is unaffected.

The firmware behaviour above is from a static disassembly of the 25G83
firmware and the macOS AGXG16X kext.

On a J616s (T6040, 25G83), with the tiler heap left at its tile-count
size so ordinary heavy passes must grow, this and the previous change
take dEQP-VK.memory.pipeline_barrier.graphics.all_device.1048576_vertex_buffer_stride_2
from 7 firmware recoveries over three runs to none. A 1/2000
vk-default slice is 769 pass / 0 fail / 0 crash, and the desktop and
GL clients render as before.

Fixes: 0d9efa5 ("drm/asahi: g17: render lead commands for the 25G83 firmware")
Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
(cherry picked from commit ad14f2d in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…ps stall

A render pair is observed only once both queues' completion stamps cover
its front group. On the J700, about every other boot under a CTS load,
the stamps of one pair stop one kick short of a group the firmware has
executed: the pass record holds its tiler start and fragment end, both
rings are consumed, and later groups on the pair execute too, but no
stamp store, completion notification or later event moves the stamps.
The pair is never observed again, and after the scheduler watchdog and
its renewals (about 30 s) the client's render fails with ETIMEDOUT and
it sees a lost device.

Give render the bound compute already has for its records:

- When an observation scan finds a front group executed and consumed
  while the stamps lag it, it latches the time. The scan before a render
  watchdog attribution also latches, so a pair whose notification never
  came is found within one watchdog period.
- A latched pair stays in the 1 ms rescan without a notification. After
  STAMP_FALLBACK_NS (50 ms) it is observed and the group retires on its
  pass record.
- When the watchdog of such a front group itself expires, the group
  retires on its record instead of failing; failing would have given up
  on the stamps as well.

The first and every 64th such retirement are logged with a lifetime
count.
(cherry picked from commit fa91d94 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…e GPU is the bottleneck

Every G17 completion arrives through the primary coprocessor's mailbox,
whose receive thread is an RT thread. With the RT default minimum
utilization, schedutil raises its CPU cluster to the top frequency for
each completion. While the GPU itself is the bottleneck that burst gains
nothing. On J700, during GPU-bound work the P-cluster sits at its top
frequency in about half of 1 s samples although the CPUs are about 3%
busy, and once the SoC reaches its thermal limit (within about 40 s of
heavy work) that power comes out of the GPU's clock.

Have the feed detector also recognize when the GPU is the bottleneck: at
least eight passes in a row whose refill gaps stay under a quarter of
their busy time, the complement of its host-refill-bound test, lingering
8 ms like that state. While it holds, the port asks for a minimum
utilization of 256 for the receive thread, and for the scheduler's
default otherwise. The port re-evaluates at every publication and
completion through a lock-free RTKit handle, so after a pause the
publication that ends the state restores the default before its
completion arrives. There is no new work item or timer.

Lowering the boost whenever the feed is not streaming is not enough. The
completion that ends a short pause then runs slower too: idle.wake with
2 ms gaps took 5% longer even at a floor of 512. A floor of 0 instead of
256 costs single-submit heavy compute about one completion per 250 ms.

Measured on J700 with the panel off, in one boot after a 45 s heat-up,
the old and new behaviour strictly alternated five times (gpubench,
microseconds per submit, mean of the per-round medians; lower is better):

  render.heavy fill 2160p d1     2817 -> 2723   -3.3%
  render.heavy fill 2160p d16    2655 -> 2577   -2.9%
  render.heavy fill 1080p d1      802 ->  780   -2.7%
  compute.heavy alu d16          1199 -> 1179   -1.7%
  compute.heavy alu d1           1374 -> 1375   (one window in five)
  idle.wake 2 ms / 20 ms         191 / 588 -> 191 / 590 (medians)
  render.light d1/d32, compute.light d1/d8, compute.light queues d2,
  sync.signal binary queues      within run-to-run noise

On the heavy rows the P-cluster's mean frequency drops from 2.5 to
1.0 GHz and system power by 0.4-0.5 W.

A KUnit suite covers the detector's three outcomes.
(cherry picked from commit d266c70 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
A render group whose completion stamps stall retires on its pass record
after STAMP_FALLBACK_NS. The comment said the stamps follow the cache
maintenance after a pass, but not that this path has no such evidence:
whether the firmware completes the maintenance before it advances the
done cursors is not known. Say that a group retired this way relies on
the 50 ms bound for its counts, stores and exported timestamps to be
visible. Comment only.

Signed-off-by: DjDeveloperr <hey@djdev.me>
(cherry picked from commit 4176f53 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…d's node

The firmware stores the completion stamps of an ioctl's commands only once
every kick counted on the ioctl's work-state node has completed: a node's
completion word reaches the host's submitted count, and only then do the
compute and render stamps move. A command whose record or pass record is
present therefore waits for its stamp for as long as the rest of its ioctl
runs. A command buffer of a dozen render passes and their copies, or a
compute command beside a render that waits on another queue, keeps the
stamps of its early members back for tens to hundreds of milliseconds.

The 50 ms stampless fallback measured from the record, so it retired those
members on their records while the firmware was still running their node:
their fences, their VM pins and their render leases were released before
the post-maintenance stamp the retirement path otherwise requires. On the
Neo, one CTS synchronization2 pass retired about 9.8k compute commands this
way. Each of them had kicks of its own node still running (the node's
completion word below the host count), and the stamp covered it 4 to 300 ms
later (median 28 ms).

Count the bound from the drain instead. Once it has passed, a compute
command or a render group whose stamps lag asks its node whether every
counted kick completed; if not, the stamps are not late and the wait starts
again. A drained node whose stamps still lag keeps the existing fallback,
so a group whose stamps stop one kick short still retires on its pass
record, and the watchdog's expiry still retires an executed group without
waiting for the node. A node that cannot be read keeps the old bound.

Signed-off-by: DjDeveloperr <hey@djdev.me>
(cherry picked from commit effb9e0 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Apply rustfmt to existing files that the per-client engine accounting
change touches. Keep the mechanical formatting separate from the
accounting and firmware timestamp changes for review.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
[Eduard Moldovan: took aurora-silicon's version of g17/mod.rs to resolve a conflict; the module order in asahi_core.rs keeps integration/aurora's G15 adoption module and has no G16]
(cherry picked from commit 137cfcf in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
funkzy and others added 26 commits November 10, 2026 11:27
…on either die

On the M5 Ultra (J775D), a round of 32 back-to-back GPU jobs now takes
1.085-1.102 ms from every CPU of both dies, where an app on the other
die from the GPU's completion path took about 1.306 ms: up to 20%
faster, and no longer dependent on where the app or the boot landed.

The GPU's mailbox receive IRQ is threaded, and the AIC cannot re-affine
it, so its thread stays wherever it first ran. The event work was queued
on the per-CPU high-priority queue from that thread and ran on its CPU,
and each scheduler's run and free work ran wherever an unbound worker
was.

On M5, queue the event work on an unbound high-priority queue of the
driver's, aimed at the CPU that last published work: it runs in that
CPU's affinity pod, its L2 cluster, wherever the IRQ thread is. Each
scheduler gets an ordered submission queue restricted to the cluster of
the CPU that created it. No die or CPU is named, so a one-die part
behaves the same. The queues are freed at unbind, after the event work
has been disabled. Other G17 GPUs are unchanged.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 5bf870bd80d09618bcc1ca2dcccb5597d7eb37fb in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…U for every client

On M5, a client could bind its own memory over the kernel's mappings in
the compact window at 64 GiB of its VM, where the kernel places the
parameter buffers' page lists, render targets, scratch and the metrics
records the firmware reads. The bind replaced the kernel's page-table
entries, so the GPU then used client memory in place of that
state, and the later unmap of either mapping cleared the other's.
An M5 client VM now reserves the compact window against VM_BIND from
creation, as it already reserves the queue arenas.

The bind check refuses only ranges registered as driver mappings, and
the compact window was never registered in a client VM: its mappings
were placed there at render or compute setup, after the VM existed. The
kernel range a client names at VM_CREATE need not cover the window, so
the client's own range check did not catch it either.

Mesa's M5 layout keeps that window inside its own driver reservation,
so no Mesa bind is refused.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 3acf8c75683d01fd70c802a1f8f906eef0d4e1ef in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
On M5, GPU work that never finished could hold its queue, queue ID,
render pairs, pool backing and memory for as long as other clients kept
the GPU busy, or for as long as its owner kept the queue open. Every
such path is now bounded:

- A job queued behind an older node of its own context was renewed by
  the watchdog at every poll, with no count, while any client kept the
  firmware's device-wide progress word moving. When the older node was
  failed work held until the firmware drains it, the renewal had no
  end. It now stops once the VM has failed work, mirroring the rule
  that a failed blocker of another VM excuses nothing, and it is
  bounded by the existing thirty-second shared budget counted on the
  job's deferrals. The older node's own job runs under the same
  allowances and was published earlier, so a healthy older node drains
  or fails within that window.
- A compute command the watchdog timed out was never killed while its
  owner kept the queue open: a context kill was published only for a
  released queue or a closed context. A timed-out queue's context is
  now killed once the quarantine delay has passed; its VM has already
  failed, so the owner loses nothing it could still use. Spared work,
  which a recovery returns to service, is not killed, and a running ray
  traversal is still never killed, as before.
- The kill of a closed context with a timed-out command was postponed
  while any other client had work in flight and the GPU retired
  something every five seconds, on the assumption that its commands
  retire like any others. A timed-out command now counts as failed
  compute for the kill, as a firmware-reported fault already does, and
  any closed context's kill waits at most the recovery bound after it
  closed.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit c4f8ad4927dbf5a448dda97ba556220aeca447a5 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…ther process takes it

Physical compute queues and render pairs move between processes, but
the client-visible state behind them did not move cleanly with them. A
previous owner could keep reading and writing the state the next
owner's GPU work used, and the next owner could read what the previous
owner's commands left. Each handover now gives the next owner state
the previous owner can no longer write, and clears what it left:

- Compute: when a queue moved to another VM, the previous VM kept
  read-write mappings of the queue's kick ring, preemption buffer,
  usage page and operand state until the new owner's first command
  retired, and the kick ring kept the previous owner's entries. The
  previous owner's mappings are now removed before the new owner's are
  created, and the kick ring is cleared with the other state pages. A
  move needs an idle queue whose pool release the firmware consumed,
  so the firmware no longer uses those views; the previous context's
  scheduler state, which the queue may still run until the new owner's
  first command, stays retained as before. If the new owner releases
  the queue before publishing anything, the queue is left detached, as
  for an exited owner, instead of restoring the removed views.
- Render: a parked pair goes to whichever queue takes its render slot
  next, and storage of a ring that never wrote an entry returns to a
  stock any VM's next ring could take. The rings kept their contents,
  and stock storage handed to another VM stayed mapped read-write in
  the VM that created it. A parked pair's rings are now cleared when it
  goes to another VM's context, and stock storage is reused only by the
  VM that created it.

A parked pair moved to another VM still leaves the previous VM's
mapping of its rings in place, since that mapping lasts as long as the
VM. The read-only client kick rings later in this series keep that VM
from writing the new owner's entries.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit b98a430aa530210c4d010dc0a1b079fa055a984a in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
… another process reuses

After a GPU context was released, the firmware's QoS table kept naming
its scheduler page for that QoS ID until the ID's next owner published
work. On M5 scheduler pages are pooled, so the page could meanwhile be
zeroed and given to another process's context, and a firmware read of
that row would see the other process's scheduler state. A released
ID's scheduler and share rows are now cleared before a new context is
created, and at each event turn.

A released ID is recorded when its lease drops and forgotten again if
a new context takes it, since that owner writes its own row at its
first publication. Rows of IDs with work still in flight are left
alone.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 33a290369dca55a2c661f53f06f9dd6dbf1e8257 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
When a user bind and a kernel mapping claimed the same GPU addresses in
one VM, the page-table code logged the collision and overwrote the
existing entries, so the GPU silently used the newer mapping's pages in
place of the older one's, such as client memory in place of state the
firmware reads, and the later unmap of either cleared the survivor's
pages. On the A18 Pro a client could reach this by binding where the
kernel later places that client's queue aliases. A map operation now
fails with EBUSY and leaves the existing mapping untouched, and the A18
Pro arenas are reserved against binds from VM creation.

- The structural fix: no mapping path maps over a live entry on
  purpose (user binds run after the VM manager removed every
  overlapping mapping, kernel mappings take fresh ranges, a residency
  restore clears its own range first), so a live entry is always
  another mapping's. Each map operation checks its whole range before
  its first store, because its failure path clears the whole range it
  asked for; the store loop refuses a live entry too, as a backstop.
- The A18 Pro instance: the kick and descriptor rings, render
  generation state and client-private compute and render backing are
  placed in two arenas when a queue is installed, after the VM exists,
  and were registered as driver mappings only then. A bind made earlier
  was not refused, nor one checked at parse time and committed after an
  alias was installed. With both arenas reserved at creation, the
  reserved set no longer changes. Mesa already keeps this range out of
  its allocator on the A18 Pro, so no Mesa bind is refused.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 44bf21e070ff5cc983a25c9db85d7b27f8cf8665 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
On M5, a compute dispatch with shader-context scratch passes the
hardware an auxiliary allocation word, the per-core page count of its
scratch storage, unchanged from userspace. The pool behind it was sized
for a fixed eight pages per core whatever the word said, so a dispatch
asking for more (Mesa's ray-query dispatches ask for 14) let the
hardware use storage past what its pool holds. Any value was accepted,
also without scratch. The pool now covers the requested count, and a
nonzero word without scratch is refused with EINVAL.

Render already sizes its pool from the same word: its spill budget adds
the published auxiliary page count, which includes the eight-page tail,
for every core. Compute now does the same, with the eight-page tail as
the floor, so no dispatch gets a smaller pool than before. Mesa's
ray-query compute pools grow by six pages per core.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 2b1ebc6f6f8f6b5ea161e9db1ee9b8e88a71359d in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…PU pool sizes

On M5, the render and compute pools behind a client's queues are sized
from that client's own program records, up to the board's whole pool
inventory (16 GiB on the M5 Ultra), and allocated and zeroed at once
as kernel memory. Kernel memory counts toward the device total but is
never refused and is attributed to no process, so one unprivileged
client could pin many gigabytes per queue: other clients' allocations
then failed with ENOMEM, and the OOM killer could not see the culprit.
An M5 pool backing is now admitted against its client's and the
device's memory limits before it is allocated, as a user buffer of the
same size would be, and a refusal fails the submission with ENOMEM.

A client VM now carries the memory accounting of the file that created
it, so every place that builds an M5 pool for a context's VM charges
that client: compute pools at install, re-arm and growth, and render
pools when their backing is built. The charge is released with the
backing. Kernel VMs and the other GPUs' pools are unchanged.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 16c04001c3236da56199c6e7e110dca068b20ac1 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
On GPUs with independent queues, QUEUE_CREATE had no per-client limit,
so one unprivileged client could open queues until the device's
execution contexts were gone. Every other process, the compositor
included, then failed to create a queue with EBUSY: a GPU denial of
service for the whole seat. A client now holds at most half of the
device's independent queues, and its next QUEUE_CREATE fails with
EBUSY.

The limit comes from the same queue limit GET_PARAMS reports, so it
follows each GPU's budget (29 of 58 where all execution contexts are
available), and leaves the other half to the rest of the seat. The
file's queue table hands out the lowest free ID, so bounding the IDs
bounds the queues the file holds. GPUs without independent queues are
unchanged.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit b1994bb3dbc8865836d0581957fd63f0fee35b2d in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…er GPU VM

Each sparse tile was a 64-page physically contiguous allocation, 1 MiB
with 16 KiB pages, of which the page tables read only the first UAT
page. Every VM that did a sparse-tile bind allocated two, so any client
could pin 2 MiB of high-order memory per VM it created, exhausting or
fragmenting contiguous memory for the rest of the system. A tile is
now one UAT page.

The allocation's order is derived from the UAT page size, so the tile
stays naturally aligned to a UAT page whatever the kernel page size.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 3f1090a0a72032fa101ee066d475b5369d0dce62 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…r overwrite kernel memory

On GPUs whose page tables the firmware builds in reserved memory (the
T6040, T6041 and T6050), a page-table walk followed any table
descriptor the firmware or bootloader had written, and accepted a
child table anywhere in System RAM. A corrupted or unexpected
descriptor below the shared kernel root would then have the walk store
PTEs into an arbitrary kernel page. A table page must now be in the
reserved regions or be one the driver allocated; anything else fails
the walk with EIO.

Freeing already refuses tables the driver does not own, so only the
write path was exposed. The firmware's own tables on these boards are
reserved no-map regions, and every table the driver adds is recorded
when it is allocated, so no legitimate walk is refused.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 5c869c10b83c52065bb8dd272430a15d58c8dea3 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…pletion and scheduler pages

On M5, the render completion stamps, each context's scheduler and
work-state pages, and each compute queue's support page were mapped for
both the firmware and the GPU. The kernel trusts what they hold. They
sit in the kernel's upper half, which every execution context includes.
Whether user shaders could reach that half was never established. This
removes the GPU permission either way: on M5 these pages are now
firmware-only. On the Studio, every GPU path ran clean with them
firmware-only, so the GPU itself doesn't need them.

Scope, by page set:
- Render completion stamps (initdata/m5.rs): allocated only on M5.
- Scheduler pages (context.rs): M5 takes them from the retained pool, Neo
  allocates its own. Firmware-only on M5 only; Neo is unchanged.
- Work-state pages (context.rs): shared code, allocated on Neo too.
  Firmware-only on M5 only; Neo is unchanged.
- Compute support page (queue/compute.rs): Neo allocates a larger one
  for its own use. Firmware-only on M5 only; Neo is unchanged.

set_fw_cached_prefix now derives the cached prefix from the mapping's own
protection, changing only the cache attribute, instead of rewriting it to
the firmware-and-GPU protection. Its readback already refused any change
other than the cache attribute. So a firmware-only pooled object used to
fail queue creation with EFAULT, and every source that succeeded is one
for which the derived protection is the same as before. That covers every
pooled family on Neo and M5 today, all firmware-and-GPU shared, so the
change is identity there.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit ff0d367316b29f631940187420c3962dd66939ed in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…e kernel validated them

Every client VM had a read-write view of its queues' kick rings, the
entries the kernel builds from validated state for each command: queue
and descriptor addresses, dependencies, QoS slot, event masks and the
register programs' addresses. A client's GPU work could therefore
rewrite an entry after the kernel had built and checked it, before the
firmware consumed it. A render pair's rings also stay mapped in every
VM that ran on them. Client views of kick rings are now read-only.

The host writes kick entries through the kernel's own mapping and the
firmware reads them through its own; neither uses the client's view,
and nothing in the driver reads an entry back. The client's view is
there for the GPU's reads, as the descriptor rings' client views,
already read-only, are. The kernel's lower and firmware mappings keep
their permissions.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit 9a9e352f065736115349b21ca909737594a8c25c in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
… under memory pressure

Two kinds of G17 work signal job fences: the event work, which
completes jobs, and each scheduler's timeout work, which fails timed-out
ones. Memory reclaim may wait on those fences, but neither ran on a
reclaim-safe workqueue. The event work ran on an M5 driver queue
allocated without WQ_MEM_RECLAIM, or on system_highpri_wq; the timeout
work ran on system_percpu_wq, drm_sched's default. When a pool has no
idle worker and creating one needs memory, that work cannot run, and
neither the fences nor reclaim make progress.

Send all of it to one reclaim-safe queue, aurora_g17_events. On M5 it
is unbound and high priority as before, so the event work still follows
the submitting CPU; elsewhere it is per-CPU and high priority, the
counterpart of system_highpri_wq, so the event work runs where it did.
Every scheduler takes the queue as its timeout queue and keeps a
reference until it has been finalized. Their run and free work already
used reclaim-safe queues.

For that, the Rust OwnedQueue gains reclaim-safe unbound and per-CPU
constructors (restrict() refuses a per-CPU queue), and the Rust DRM
scheduler binding's new_with_queues() takes an optional submission
queue and an optional shared timeout queue, in place of
new_with_submit_wq().

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
[Eduard Moldovan: the KUnit cases in aurora-silicon's rust_drm_sched test module are left out; integration/aurora has no such module]
(cherry picked from commit 37770014197fbd1078b85390c3008686a09966d6 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…he report and fault-ownership changes

With KUnit enabled, asahi no longer built: two of its tests still
called interfaces that later commits had changed.

- f04338837f3f ("drm/asahi: g17: M5: install M5 queues and submit
  through the host command port") gave Reports::record() the family's
  statistics tag mask and 64 tags per role. The report tests now pass
  the G17 mask and index the second role at TAGS, and a new case checks
  that tag 32 counts under M5's mask only and that tags past 63 are
  refused under any mask.
- e7ddf2b8e869 ("drm/asahi: g17: Fix a process keeping access to a GPU
  queue after another process takes it") added Previous::moved. The
  same-VM replacement test sets it false.

Signed-off-by: Jeff Queisser <funkzy@users.noreply.github.com>
(cherry picked from commit d078ca18fa45ac38a53e3230c0e593ad8d03ebdd in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
- HW+0x10a8: the active MCC mask for all eight AMCCs (0xff), matching the
  slot 3 windows, instead of the inherited 0xf.
- HW+0x100c (16) and HW+0x1048 (40, all cores).

J714 keeps the inherited values, and J775D its own.

Developed with Claude Code.

Signed-off-by: Erik Bourget <erik@ebourget.net>
(cherry picked from commit d91195fcb8ffd6e89dac1f33cc77e2d3b47c3278 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
The M5 Max's controller defaults were J714's, applied only to a part
with J714's calibration words, which no M5 Max has. Give it its own: the
J714 defaults, including the relative power curves, with the leakage of
its four clusters, its base and AFR values, a maximum power of 196098 mW,
and the found masks of its AON PTD records, applied for the J716c
calibration words.

As on J714, a unit whose calibration words differ keeps the default
budget.

Developed with Claude Code.

Signed-off-by: Erik Bourget <erik@ebourget.net>
(cherry picked from commit f36da76cf6cafb222ec05619fda23b3b64753c20 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
The M5 Max (J716c) already has its board data, but its configuration
still names no firmware and probe refuses it as having no bare-metal GPU
tables.

Give it the M5 Ultra's bare-metal profile: both roles publish their
kernel roots, the secondary's at 0x40000 in `pagetables`, each asks for
its crash log inside `fw-data`, and the UAT policy is the Ultra's. Admit
the G17C firmware build of both roles: primary TEXT 0x50000, then the
secondary's 0x54000, with the boot-filled ranges zeroed as on the Ultra.

Only the M5 Pro is refused at probe now. The firmware identity test
covers the Max's image too.

Tested on a J716c: the GPU boots both roles and runs the desktop through
zink and Vulkan.

Developed with Claude Code.

Signed-off-by: Erik Bourget <erik@ebourget.net>
(cherry picked from commit 84d4f9057e9f145a4e648ebec0c558c1eecbedaf in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Bind the T6050 GPU through "apple,agx-g17s", the compatible its M5 Max
("apple,agx-g17c") and M5 Ultra ("apple,agx-g17d") nodes fall back to,
in place of "apple,agx-t6050", which no binding documents. The GPU's ID
registers still choose the board's configuration.

Developed with Claude Code.

Signed-off-by: Erik Bourget <erik@ebourget.net>
[Eduard Moldovan: applied to integration/aurora's 7.2.11 OF table]
(cherry picked from commit b9dc01a3703813ab6ab25cb25253051b224b03ef in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
A G17 recovery reports the firmware's reason (3 is a page fault) and the
blamed queue, but not which address faulted or which unit faulted on it:
the G17 runtime never reads the MMU fault registers. On T6040 a Transport
Fever 3 shadow pass page-faults its fragment queue repeatably, and without
the address there is no telling whether a depth surface, a tiler heap page
or freed client memory is behind it.

T6040's GPU is G16S hardware, and G15/G16 expose the fault through two
banks: status at SGX +0xd8c0 and address (64-byte units) at +0xd8c8 under
the bank selector at +0xd800 (g16::regs::Regs::engine_state). Read both
banks while the firmware is halted in the recovery handshake, restoring the
selector, and log them decoded by the existing G14X decoder, now shared as
regs::decode_fault(). This is diagnostics only: nothing in attribution,
cancellation or release depends on it.

Signed-off-by: Jonathan Goyvaerts <jonathan.goyvaerts@gmail.com>
Assisted-by: LLM
(cherry picked from commit 8ce1613 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Validate version 2 of the per-chip handoff, sixteen raw OPPs and selector
slots, eleven populated selectors, zero tails and base state 1. There is
no single-unit fallback. The initdata patch wires the reader into probe
and firmware construction so this patch adds no unused compiled items.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit a8fb138 in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Use valid sixteen-slot handoffs in the calibration KUnit fixture, with
both eleven-state maps ending at raw OPP 15. Check the highest state's
second voltage lane as well as the intermediate-state ordering and
relative-frequency consistency.

The former 0..10 fixture could not pass the production map reader and
never exercised the final five raw operating points.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
(cherry picked from commit 989406b in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
The aurora-silicon G17 and M5 commits carried before this one are
written for Linux 7.3 and aurora-silicon's driver core. On
integration/aurora (Linux 7.2.11):
- Module parameters return references: read the M5 mesh storage,
  MSAA depth compression and thermal target parameters, and
  stats_export, through them.
- float.rs already has F32::to_bits(): drop the second definition.
- The M3 T8122 probe takes a device binding owner, as the other probes
  now do, and its Gpu::new_queue() takes the client usage argument the
  trait now has.
- The G15 backend keeps its identity module, which aurora-silicon moved
  into the shared fwid code.
- The SMC hwmon cell has no kernel fan request: the opt-in M5 thermal
  governor's fan request returns -EOPNOTSUPP and the SMC keeps the fans.
- Without CONFIG_CPU_FREQ, cpufreq_cpu_get() and cpufreq_cpu_put() are
  inline stubs the Rust bindings lack: the M5 thermal governor takes no
  CPU frequency requests then.
- The recovery KUnit mock drops announce_withheld(), which
  8ce1613 adds for a Queues method integration/aurora does not have.
- kunit-expected.json lists asahi_fwid.j713_accepts_both_loaded_images
  as skipped: it is a G16 case and the G16 backend is not built.

Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Returns the TGID (Thread Group ID / Process ID) of the given task.

This is the rust/kernel/task.rs part of upstream commit 2847d9a
("rust_binder: Add dynamic debug logging mask"), backported to 7.2.11
on its own for the asahi driver.

Signed-off-by: Jahnavi MN <jahnavimn@google.com>
Link: https://patch.msgid.link/20260716-rust_binder_debug_mask-v4-1-3d7436c2d2f2@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 2847d9a)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prevent compute replay from waiting indefinitely for event-serviced input
fences while holding the device mutex. Bound initial dependency waits and
recovery preparation joins. Queue workload-triggered stop from scheduler
callbacks; halt firmware producers before a bounded stop join and retain
all graph/lease ownership when a borrower has not returned.

Stop on a per-device burst of eight watchdog expirations or eight restart
handshakes within thirty seconds. New VMs, generations and replay cannot
renew that budget or undo terminal loss. Charge render borrowed-graph and
queued-retirement deferrals against the same finite eight-poll bound as
compute attribution; a deferred timeout cannot evade eventual device loss.

G17 RX now uses an oneshot threaded interrupt with a 64-message pass and
an off-lock sleep on exhaustion. G17 non-atomic TX without an IRQ sleeps
instead of polling for 500 ms with interrupts disabled; atomic sends have
a 1 ms cap. Share one absolute TX deadline across contention/retries and
preserve provider/removal/PM/cookie gates.

Add lockdep KUnit for 64 consecutive timeouts during pending recovery,
late borrower return and latched failure; inject permanently full/empty
register models through production mailbox poll/send functions. Document
the audited bounds and the unverified hardware attribution.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
[Eduard Moldovan: the drm/asahi part is already in integration/aurora through DjDeveloperr's G17 sync (4b7aa80) and Erik Bourget's tree; this carries the mailbox part, its KUnit header and the safety notes]
(cherry picked from commit 9827b6b in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
…utilization

The G17 mailboxes receive in a threaded IRQ handler, which runs as an RT
thread. RT threads run with the RT default minimum utilization, 1024
unless the system lowers sched_util_clamp_min_rt_default, so schedutil
raises the thread's CPU cluster to its top frequency for every message.
For the GPU completion mailbox that means one top-frequency burst per GPU
completion, also while the GPU itself is the bottleneck and the CPU has
nothing to do quickly.

Add apple_mbox_set_rx_util_min(), which records the minimum utilization a
consumer wants for the receive thread, or -1 for the scheduler's default,
and have the threaded handler apply it to itself (sched_setattr_nocheck()
on current, keeping its policy and priority) the next time it runs. The
request is a single store, so it may be made from any context. Only
mailboxes with a threaded receive handler support it; until a consumer
asks, the thread keeps the default.

Wrap it for RTKit consumers as apple_rtkit_set_rx_util_min() and
RtKit::set_rx_util_min(). RtKit::rx_util_min_handle() returns a handle
that makes the same request without borrowing the RtKit, for consumers
that update it from their submission and completion paths.

A KUnit case covers the request checks, and applying a request to a FIFO
thread without changing its policy or priority.
(cherry picked from commit 564d91c in aurora-silicon/linux)
Signed-off-by: Eduard Moldovan <edimoldovan@gmail.com>
@edimoldovan edimoldovan changed the title drm/asahi: Carry aurora-silicon's G17 and M5 GPU driver work Carry aurora-silicon's G17 and M5 GPU driver work Nov 10, 2026
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.

10 participants