Skip to content

drm/asahi: G17 (Neo, T8140) driver update for 7.2.11 - #229

Merged
maralcbr merged 69 commits into
integration/aurorafrom
neo/g17-neo-perf-20261025
Oct 29, 2026
Merged

maralcbr merged 69 commits into
integration/aurorafrom
neo/g17-neo-perf-20261025

Conversation

@DjDeveloperr

@DjDeveloperr DjDeveloperr commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Brings the G17 driver up to aurora-silicon/linux (AsahiLinux#423 head 8e257af) on integration/aurora:

  1. One sync commit: drivers/gpu/drm/asahi at aurora-silicon d3cf19b, three-way merged onto
    integration/aurora (base 7.2.10 merge point 44d5afc). Kept: G15, the M3 T8122 runtime, UAT
    adoption, M3 Pro GPU crash fix: preserve new mappings during deferred GEM close #214 deferred-close binding sequences and the 7.2.11 shared-code adaptations. Not carried:
    the G16 (T8132) backend. 7.2.11 adaptations: module parameter refs, THIS_MODULE, a local
    raw_try_init, MODULE_OF_TABLE, Devres for the sgx window, G17's soft-fault opt-out in the
    shared feature flags, G15/M3 on the shared timestamp::Buffer and reserved-table root walk.
    Crate/helper pieces the driver needs: shmem SG leases and pages_no_reclaim, DRM file memory
    stats/fdinfo/is_current_master, mm RSS counter. The message credits the carried authors.
  2. 61 G17 commits from aurora-silicon/linux After upgrade to 6.18.400 cursor diapered then reapers FIXED AsahiLinux/linux#423 (submit/render CPU cost, timestamps, sync inputs and
    outputs, doorbell batching, liveness watchdog, kill gating, recovery fixes, cumulative signals at bit
    29), cherry-picked with -x and signed off.

M4 Pro (T6040): the sync also matches apple,agx-t6040 and probes it through the G17 driver with the 25G83 firmware configuration in hw/t6040.rs. This is initial, untested support: nothing in this PR was run on a T6040, and the installer doesn't offer M4 and later yet.

GPU memory limits (mem_limit_pct, client_mem_limit_pct, oom_attribution) apply only to G17 (1032928). Other GPUs keep the totals in fdinfo and sysfs, with no limit and no RSS attribution.

UAPI: include/uapi/drm/asahi_drm.h gains the G17 features (VM status, queue limits, cumulative signals
at bit 29, ...); Mesa: aurora-silicon/mesa #62 (stage rb6) matches.

Testing (Neo J700, 7.2.11-ARCH-neo72 with #226/#227/#228, Mesa rb6):

  • CONFIG_DRM_ASAHI_G15=y + M3_T8122=y compile check clean; Neo config clean.
  • Regression gate PASS (cross-queue data, vkstress mixed 893 devices bad=0, pressure, capacity).
  • deqp-vk targeted list incl. query_pool: 23638 cases, 22847 pass, 791 not supported, 0 fail/crash.
  • 600 s six-lane stress (CTS global_priority, gpubench churn/render, long ALU, oracle clients):
    no GPU errors, recoveries or crashes; oracle 34/34 PASS; desktop alive.

The performance work in the picked commits was measured on 7.3, and the numbers are in aurora-silicon#423. Highlights against macOS on the same Neo: light compute submission matching or beating macOS from depth 1 to 64, the cross-queue hop down from about 31 µs to 23 µs, and multi-client stress that previously collapsed the firmware in under 3 minutes now running clean.

Known differences on 7.2.11

  • Slower light rows on the base, fixed by iommu/apple-dart: fix the J700 internal display and SLC with handed-off display DARTs #235. On every 7.2.11 boot, the display DART (apple-dart 412300000.iommu) fails to probe with -16 ("IOMMU driver was not able to establish FW requested direct mapping"). The display subsystem then never binds, and apple-mcc, which waits for it, never enables the system level cache. That is why light rows were slower here than on 7.3, for example a cross-queue gate pair of 333.6 µs against 227 µs. With iommu/apple-dart: fix the J700 internal display and SLC with handed-off display DARTs #235, the GPU rows match 7.3: hop 22.4 vs 22.7 µs, compute.light d1 106.7 vs 102.2, d64 13.7 vs 13.9, render.light d32 29.0 vs 29.4. Two smaller differences remain. The gate's cross-queue pair is 259 vs 225 µs under schedutil, but 205 vs 204 µs with the performance governor. The cpufreq driver isn't the cause: on 7.3, the same driver as here and the previous one give 229 and 230 µs. So the difference comes from how the 7.2.11 scheduler ramps the CPU under this bursty pattern. mem.image is 7% slower and is still under investigation. On one of three unfixed boots, IRQ 55 also fired with no handler and was disabled; with iommu/apple-dart: fix the J700 internal display and SLC with handed-off display DARTs #235 that no longer happens.
  • The 600 s stress had 7 of 222 gpubench rows miss their 300 ms measurement windows while sharing the GPU with 1.5 s kernels (3 of 222 on 7.3). No client lost its device.

Depends on / pairs with

Bring drivers/gpu/drm/asahi up to the aurora-silicon/linux state at
d3cf19b, the base of the G17 performance series that follows, merged
three-way on top of integration/aurora with the 7.2.10 merge point
44d5afc as base. integration/aurora's own work is kept: the G15 backend,
the M3 T8122 runtime, UAT adoption, deferred-close binding sequences (#214)
and the 7.2.11 shared-code adaptations. The G16 (T8132) backend is not
carried.

This carries the G17 work merged on the aurora side since 7.2.10,
including the T6040 (M4 Pro) and 25G83 firmware support and the render
replay/recovery series by Jonathan Goyvaerts, the watchdog, replay and
backing-population changes by Ryan Murray, the tracked VM lifetime work by
Eryk Wieliczko, and the G17 queue, capacity and timestamp changes by
DjDeveloperr (aurora-silicon/linux AsahiLinux#382, #391, AsahiLinux#397, AsahiLinux#400).

Adaptations to 7.2.11:
- module parameters return references; THIS_MODULE replaces
  kernel::module::this_module; a local raw_try_init replaces the newer
  pin-init helper; of_device_table! takes the MODULE_OF_TABLE name.
- regs.rs keeps G17's sgx window as Devres<IoMem>, as 7.2 has no
  DevresIoMem.
- The shared feature flags keep G17's opt-out of soft faults.
- G15 and the M3 runtime use the shared timestamp::Buffer and the
  reserved-table aware root walk; omacom's G15 vm_closed hook becomes
  vm_destroyed, next to the G17 vm_closed.
- Crate and helper pieces the driver needs: the shmem SG lease and
  pages_no_reclaim (drm_gem_shmem_helper), DRM file memory stats, fdinfo
  and is_current_master, and the mm RSS counter.

Signed-off-by: DjDeveloperr <hey@djdev.me>
A compute command on a bound queue went through every admission step on
each submission. ensure_compute took the device mutex for a replay and
witness pass, shared_compute took a preparation lease and the mutex
again, and build_compute did both once more to find its queue already
bound. compute_packet then took a third lease and the mutex a fourth
time, replaying compute again before publishing. Compute also never
published from its submit ioctl, so even a command with nothing to wait
for went through the scheduler worker first. Its completions never fed
the CPU-capacity detector, so the host loop feeding a compute-bound GPU
ran at the lowest CPU performance level.

Check what ensure_compute establishes under the one device-mutex section
that publishes, and run the admission passes only when that check
fails. Publish a dependency-free compute command from its submit ioctl
when its queue is bound and nothing has to wait, as renders do. Keep a
separate backlog per engine so that a command waiting in one engine's
scheduler does not stop the other engine's inline publication. Report
compute dispatch envelopes to the detector as render passes are.

(cherry picked from commit ad691cd)
Signed-off-by: DjDeveloperr <hey@djdev.me>
A render whose pair was out on loan slept 200 us before trying again.
The event worker lends each pair with completions out for an off-lock
observation after every completion event. At queue depths of two and
more, completions and submissions interleave, so a submission often
found its pair on loan for a few microseconds and then slept the full
200 us.

Count the device's change notifications. Every pair return already
notifies under the device mutex. Wait for the notification under that
mutex, unless one arrived since the attempt started, with the same
deadline as before.

(cherry picked from commit 1121ae3)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Object::initialize already clears the complete descriptor before calling
its encoder. Fill that zeroed representation directly instead of clearing
the same 16 KiB again. Name the encoder write_zeroed to make its precondition
explicit.

The firmware bytes and validation remain unchanged. The matched module
passed the targeted compute/synchronization gate and checked GPU readbacks.

(cherry picked from commit abd8593)
Signed-off-by: DjDeveloperr <hey@djdev.me>
A publisher waiting for a physical compute channel reclaimed idle USC
backing even though freeing backing cannot create another QID. The normal
warm-pool limit could also evict a retired channel while another runnable
publisher was waiting to reuse it. Subsequent handoffs repeatedly allocated
and cleared fresh pool backing.

Distinguish channel pressure from backing allocation pressure. Track unbound
compute admission through publication, cancellation and error, and retain
backing for the existing compute channels while that demand remains. The
last publisher schedules normal idle reclamation. Allocation-pressure
reclamation, the idle warm-pool limit and expiry remain in force. Expose the
admission count in the capacity diagnostics.

On Neo, the matched 16-client probe drops pool allocations from 4888 to 53
and median submission time from 257 to 109 us. The Asahi KUnit suites pass
67/67; the targeted compute/synchronization gate passes 116 with 18 skips.
Full mustpass qualification remains pending.

(cherry picked from commit 3ef3720)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Fence arrays require every member to signal. During syncobj timeline walks,
a pending predecessor already proves that the array is incomplete, yet the
lazy signaled callback polls every successor too. Return false immediately
at that predecessor, keeping callback accounting and the enabled-signaling
path unchanged.

Add checks for out-of-order completion, avoiding successor polls, and
callback installation after a partial lazy poll. Remove the obsolete
signal-on-any description from the constructor documentation.

(cherry picked from commit f35d7ea)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Compute-only contexts that yield their physical channel still take the
device mutex in the inline submit path before falling back to admission.
Track an advisory binding hint to skip that attempt. Actual publication
retains the locked VM, epoch and binding checks, and scheduler admission
ordering is unchanged.

Mark contexts with validated rendering before any batch member is queued,
so mixed-engine queues retain the original inline path.

Validated with 69 Asahi KUnit cases, targeted compute/sync CTS (116 pass,
18 skip), mixed device churn and 16-client concurrent GPU readbacks.
Matched 16-process quick submission time improves from 117.27 to 89.55 us;
paired render follow-ups remain at control performance.

(cherry picked from commit 319805f)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Only bypass an unbound compute-only inline attempt when multiple
publishers are waiting for admission. A lone admission retains the
original probe and its latency behavior. Actual publication still uses
the existing locked state checks.

Matched quick controls retain queue signaling latency (174.1 to 174.5 us)
while 16-process submission time improves from 117.3 to 90.7 us. All 20
performance rows complete successfully. Checked mixed/concurrent GPU
readbacks, 69 Asahi KUnit cases and targeted compute/sync CTS also pass.

(cherry picked from commit 5a4822c)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Recognize eligible singleton compute producers through their exported aggregate
fences. Order queued consumers after actual producer publication using the
existing DRM scheduled fence, then validate the current physical ticket and
emit firmware waits. Preserve CPU waits for unsupported dependencies and host
outputs, and revalidate recovery epochs before acquiring consumer capacity.

Retain source binding loans through consumer retirement, propagate source errors
before dependent completion, and release failed submission pins when the last
runtime owner retires even if exported fence references survive. Keep bounded
member counters in byte atomics so submission state retains its original
allocation class.

Validated with 78 KUnit tests, the compute/synchronization CTS gate, chained
readback, process exits and mixed compute/render pressure. Fixed-core ordinary
compute matches the control while the queue-hop path improves. Existing
intermittent unrelated-client loss during forced recovery remains unresolved.

(cherry picked from commit 026065c)
Signed-off-by: DjDeveloperr <hey@djdev.me>
… queued

Compute retirement removes the producer from its queue's active list under
the device mutex, but signals the producer's fence only after the lock is
dropped. A consumer published in between found neither an active producer
nor a completed one, fell back to the scheduler, and every later command in
the chain then waited for its producer's publication through the scheduler.

Mark the singleton firmware source retired as its successful retirement is
queued (errors are already recorded there), after rechecking its own inputs.

sync.signal queue-to-queue (timeline, 2 queues): scheduler fallbacks for
chain consumers 57% -> 0.1%.

(cherry picked from commit a3be7f63500c76d117000ee1474713e27889aabe)
(cherry picked from commit 89c8873)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Early publication was limited to queues with fewer than two outstanding
commands, so every deeper queue paid a scheduler worker hop per command and
cross-queue chains advanced one scheduler round trip per link. The backend
already falls back to the scheduler behind any backlog and on every capacity
miss, which preserves submission order, so the depth limit only added
latency.

sync.signal queue-to-queue (timeline, 2 queues) 94.1 -> 56.2 us/hop together
with the preceding change; compute and render depth rows unchanged.

(cherry picked from commit 8508510641edcedb5ae1417f560cdff4da646bda)
(cherry picked from commit 3ff4f4b)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Render descriptors already come from the retained object pool with a
firmware-cached mapping; compute descriptors were mapped uncached, so the
firmware read every compute descriptor from memory on each command.

Allocate the compute descriptor ring from the same pool (fully cached
prefix, retained until processor stop) and give the hardware an uncached
canonical low alias for the descriptor address it fetches.

compute.light d64 27.4 -> 24.3 us/submit, queue-to-queue hop 58.1 -> 54.8 us;
compute/sync CTS gate, cross-queue order/data 10k, dependent reads under
pressure and mixed churn pass.

(cherry picked from commit c85c050ae2ef77cbeebddb70c6602db477675090)
(cherry picked from commit a0dfc3c)
Signed-off-by: DjDeveloperr <hey@djdev.me>
The compute channel budget was static: compute could only take a QID while
every one of the 58 possible execution contexts could still install a
render pair, which always left exactly ten compute channels. A client
without a channel then made every idle channel of every live client
shareable before binding one, so sixteen compute processes evicted each
other on nearly every submission (map/unmap and TLB invalidation churn,
ComputeReserve refused 52k times in one benchmark pass).

Installed QIDs never change engine before processor stop, so a compute
channel still permanently narrows render. Size the render reserve by the
logical queues that are actually open plus 24 queues of headroom, and
refuse a new logical queue only when its dedicated render pair would no
longer fit. With every context open this is the previous rule.

Rebinding now prefers a channel of a closed owner, then a vacant one to
re-arm, then a fresh QID, and only then shares the least recently used
idle channel of a single live client.

gpubench on Neo (us/submit, matched baseline): compute.light procs d16
92.0 -> 33.4; compute.light queue rows unchanged (d64 27.4 -> 26.5).
Stress gate passes.

(cherry picked from commit bf7ae5bf04b7d3f14b5ec94ef1f8c1434b4fe494)
(cherry picked from commit a36e352)
Signed-off-by: DjDeveloperr <hey@djdev.me>
A render whose attachment spans overlapped a live render of another logical
queue in the same VM waited in admission, on the host, until that render
retired. gpubench render.light queues renders every queue into one image, so
all queues ran one render at a time: run_job blocked for (N-1) renders and
the 2/4/8-queue rows stayed at one serialized step (174/201/217 us/submit).

Order such overlaps at publication instead. The device mutex already orders
publications; the later render's fragment kick now waits in firmware for the
newest published overlapping fragment kick of every other pair, so its tiling
kick stays concurrent and no host wait or scheduler stall is involved.
Published QIDs keep their kick rings, so these stamps only advance. An
admission bound on other pairs of the VM keeps the barrier count within its
fixed room. Cross-VM overlaps through shared objects keep the host wait, so
one VM's fault can never hold another VM's kick in firmware.

render.light queues d2/d4/d8: 173.8/201.3/216.9 -> 81.4/66.9/62.1 us/submit. Other
rows unchanged; the mild stress gate (CTS compute/sync, cross-queue order/data,
slow-read pressure, mixed churn) passes.

(cherry picked from commit 809d95cfdd685b6f94570cd313b1723c7f01f466)
(cherry picked from commit b141ca9)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Each compute command writes a queue configuration record, an optional
predecessor and completion-wait records, and an announcement; the firmware
read all of them through an uncached mapping. Render keeps its equivalent
configuration records cached and only its announcements uncached.

Move the configuration, predecessor and completion-wait records into a
retained pool object with a firmware-cached mapping at the same per-slot
offsets; announcements stay uncached.

compute.light d1 161.0 -> 152.2 us, d64 24.3 -> 23.1 us/submit, queue-to-queue
hop 54.8 -> 51.2 us; compute/sync CTS gate, cross-queue order/data 10k,
dependent reads under pressure and mixed churn pass.

(cherry picked from commit b3d5b9d6294bb46d63778264205da9d3b750651e)
(cherry picked from commit a475f4f)
Signed-off-by: DjDeveloperr <hey@djdev.me>
…found

Every event pass with an unobserved compute command walked all 2048 records
of the compute completion ring under the device mutex to find the few it
needed; that walk was half of the event worker's CPU time.

Resume each scan after the last record the previous scan needed and stop as
soon as every requested identity has an observation. A scan that finds
nothing still wraps the whole ring once, as before.

scan_compute leaves the top of the 16-process profile; benchmark rows are
unchanged within noise (they are not bound by the scan). Compute/sync CTS
gate, cross-queue order/data 10k, dependent reads under pressure and mixed
churn pass.

(cherry picked from commit 67a49c9c40b31b96a7834c8c185dc20e0bac1fa2)
(cherry picked from commit ca71e44)
Signed-off-by: DjDeveloperr <hey@djdev.me>
…mutex

Every compute publication took the device mutex, which the event worker
also holds for each service pass, and repeated device-wide work on every
submit (replay scan, render-prefix scan, binding checks).

Give each physical compute queue its own lock (a cell the registry owns;
device-mutex holders lock cells one at a time) and move the device-wide
state a publication needs into a per-session port that is reached under a
preparation lease: compute work-ring slot reservations, QoS accounting
under its own spinlock, the recovery generation, the full-effort flag and
the doorbell, whose RTKit borrows are serialized by a mailbox lock. The
steady-state path (bound, installed, no input sources, no render prefix)
publishes from the submit ioctl or run_job with only the queue's lock and
the port's small locks; everything else falls back to the device-mutex
path, which now reserves work-ring slots through the same port.

A command published while the event worker is scanning is not part of
that scan's completion snapshot and is left unobserved until the next one.

gpubench on Neo (us/submit, vs matched baseline): compute.light d1
166.3 -> 156.2, d64 27.4 -> 25.8, procs d16 33.4 -> 33.0 (firmware per
command time now bounds these rows). Stress gate passes.

(cherry picked from commit 8fc91b2117de925e362342a842b0d0befbba5312)
(cherry picked from commit 1cdac9b)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Render emits its queue configuration record only for an install, a context
or QoS update, or when the configuration differs from the last one the
firmware consumed in the current recovery epoch. Compute appended the record
to every command, so the firmware reapplied unchanged queue state each time.

Use the same rule for compute, caching the last consumed configuration with
its epoch and forgetting it when the item ring is reset.

compute.light d2 61.9 -> 51.5, d8 25.9 -> 24.3, d64 23.9 -> 22.8 us/submit;
queue-to-queue hop 51.1 -> 49.6 us. Compute/sync CTS gate, cross-queue
order/data 10k, dependent reads under pressure and mixed churn pass.

(cherry picked from commit 0e59b1f92effb58c87f705907959de45abe77623)
(cherry picked from commit 7242bf8)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Waits for shared capacity sampled a condition and slept 1 ms before
checking again. Add availability domains: a waiter samples the domain's
generation before its failed check and registers a fence against that
sample (or retries when a release intervened); the release that provides
the resource bumps the generation and signals only that domain's
waiters. The fences can serve as scheduler prepare_job dependencies or be
waited on directly. The preparation gate can carry a domain that its
reopening, failure and removal signal.

Logical-queue creation is the first user: a creator refused for want of
a queue slot or an execution context held by a closing queue now waits
for the returned slot or the reclaimed context instead of sleeping in
1 ms steps, under the same overall deadline.

Tested on Neo as part of compute-wait2 (stress gate passes).

(cherry picked from commit 79cf4be7732d549b0f5d1f903bed7effdb80a4fb)
(cherry picked from commit 014605a)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Compute admission and publication retried with sleeps: 1 ms for an
unpublished input source, a 20 us..1 ms backoff for a work state, up to
200 x 1 ms for recovery, 1 ms per ring backpressure retry, 200 x 1 ms for
a spared drain witness, and 1 ms per growth and channel capacity retry.

Use two availability domains for compute admission; the release that
provides the resource signals only the waiters of its own domain:

- channels: a queue becomes reusable, shareable or re-armable (checked
  on each transition in the retirement scan and pool service), a
  scheduler release is consumed, an owner closes, or an unpublished slot
  and QID are returned;
- progress: any compute retirement, finished replays, pool release
  observation, and the preparation gate reopening after recovery.

prepare_job now returns the channel, work-state or recovery fence a
compute packet still lacks, so run_job finds its capacity ready, and a
prepared packet claims its bound channel so the channel is not shared
away before run_job. Retries that remain inside publication block on the
same fences; the admission slice only bounds cancellation checks. Each
event pass also rechecks the level while waiters exist, which covers
capacity that appears through render (QIDs, work states, closed queues).

gpubench on Neo (us/submit, matched baseline): unchanged steady state
(procs d16 33.1, d64 25.9, d1 162); procs d2 93.2 -> 69.2. With the
channel budget forced back to ten channels (diagnostic build), sixteen
processes now share them at 51.9 us/submit instead of the old 92.0, with
no stall. Stress gate passes, also under the forced shortage.

(cherry picked from commit 25fb5800d97db7457f093ff41206047fbd9bddcc)
(cherry picked from commit 64f717d)
Signed-off-by: DjDeveloperr <hey@djdev.me>
…record

A consumer of a firmware-visible compute source carried a completion-wait
record before its descriptor and also named the source in its kick entry.
The second dependency flagged the command as entry-signalled, so it also
appended a predecessor record, and the firmware resolved the same wait
twice.

Keep only the completion-wait record, which orders the consumer behind its
source by itself.

Queue-to-queue hop 49.6 -> 46.0 us. Cross-queue order and data checks (10k
iterations each), dependent reads under pressure, the compute/sync CTS gate
and mixed churn pass.

(cherry picked from commit 58ef65a530b707fb77878e9fdc68d577a27759fc)
(cherry picked from commit 327e50f)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Add tracepoints for each command's publication (doorbell rung, with its out
fence and the CPU counter), its retirement (with the firmware's GPU start and
end timestamps), physical queue binds and event worker pass boundaries. With
the counter and the GPU's system counter timestamps on the same events, a
trace places firmware dispatch, GPU execution, firmware completion and every
host stage of a command on one timeline.

The events are disabled by default and cost a static-key test each.

(cherry picked from commit 565dae906223948df97a252cc3274e8db6183363)
(cherry picked from commit 6f4d3bb)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Compute rang its pipe and priority doorbell (pipe 2 in bits 1:0, class in
bits 3:2) only for the first publication of a priority class, then the
generic work doorbell for every command. Render rings its own pipe
doorbell for every publication, and so does the M5 compute path.

Ring the compute pipe doorbell for every publication instead of the
generic one.

gpubench on Neo (us/submit, on the integration branch): compute.light d2
60.3 -> 53.2, d64 22.8 -> 21.5, d1 163 -> 154..160, procs d16 unchanged
(27.2), hop unchanged (48.7). Stress gate passes.

(cherry picked from commit 398141cf95c44ac4d0073f3620a99d1235f31309)
(cherry picked from commit e24e3ba)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Render keeps its queue records in a firmware-cached prefix; the compute
queue record, job-list head and item ring were mapped uncached. Allocate the
compute graph from the retained object pool with its 32 KiB queue record,
job-list head and item ring in a firmware-cached prefix, and move the
producer/consumer words to their own uncached page after it, as native
does.

compute.light d64 22.2 -> 19.7 us/submit, 16-process compute 27.2 -> 25.7,
queue-to-queue hop 47.5 -> 42.4 us. Compute/sync CTS gate, cross-queue
order/data 10k, dependent reads under pressure and mixed churn pass.

(cherry picked from commit 488708add18c39f709d6a9b53736d339428cf5d0)
(cherry picked from commit 94c66ec)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Render admission and publication still slept or polled: a 20 us..1 ms
backoff when every work state of the context was taken, up to 200 x 1 ms
while recovery was observed, an unconditional 1 ms sleep for render
capacity (through the compute capacity wait), and a 1 ms condvar timeout
as the wakeup for a pair on loan, firmware room or a pending teardown.

Block on the event that ends each wait instead:
- a render availability domain, signalled by every admission-pool return
  (lease drop, owner close, quarantine change, exit-kill hold release,
  processor stop), every pair return from a loan, and on each event pass
  while a render publisher waits, since firmware ring room, consumed
  releases and teardown steps have no event of their own;
- a per-context work-state domain, signalled whenever a work state
  returns;
- the preparation gate: a publisher that observed recovery waits for its
  closure (close() now wakes the gate's waiters) and then blocks in
  enter() until recovery reopens it.
Render capacity first returns idle backing, then waits on the domain.
Waiters sample a domain only after a failed check and retry once before
blocking, so steady-state publication takes no extra lock. Deadlines only
bound the waits; 10 ms slices only bound cancellation checks.

Steady state is unchanged (render d1 135.7, d32 41.4, queues d8 62.6
us/submit); the mild stress gate passes.

(cherry picked from commit a3fc054bc52c2bc82350e6073366045a1c3c9489)
(cherry picked from commit db365ec)
Signed-off-by: DjDeveloperr <hey@djdev.me>
A logical render queue owns exactly one physical pair, whose active ring
holds RENDER_DEPTH (16) commands, but its scheduler had 32 credits. Jobs 17
to 32 entered run_job and parked there in the admission pool (or in the
1 ms busy wait) until a retirement freed a ring entry, holding the
scheduler worker. With the credit limit equal to the pair depth the
scheduler itself waits for the credit that the retirement returns, and
run_job never blocks on a full pair.

render.light d32 41.15 -> 41.26 us/submit (unchanged; the row is firmware
bound), all other rows unchanged, mild stress gate passes.

(cherry picked from commit 15de925f91cdb2a875e09fc1c6b64af79fa37ae2)
(cherry picked from commit 06bc290)
Signed-off-by: DjDeveloperr <hey@djdev.me>
…is busy

A render pool whose last render retired sent its final FreeListRelease
right away: a control-ring record and a control doorbell for every render
of a one-deep queue. The firmware processes each such message serially
before it returns to the work rings, so with several queues active the
releases stretched every completion burst (one release per render in
render.light queues: about 44.6k per run).

When another pair still has published work, leave a registration whose
references drop to zero lingering instead; the owner's next render reuses
it like an overlapping render, with no release and no new generation. A
lingering registration ends, and its release is published, when its owner
closes or moves to another pool (each event pass checks) or after the
16 ms firmware idle hold, for which the event worker schedules a timed
pass. On an otherwise idle device the release is still sent at once:
reusing a registration that went idle costs the firmware more than the
release does (render d1 147 -> 184 us when every idle registration
lingered).

render.light queues d2/d4/d8: 80.8/67.3/62.6 -> 76.9/62.4/58.2 us/submit;
render d1 148, d32 41.3 (unchanged). Releases per queues-d8 run: 44574 -> 18
(measured with every idle registration lingering).
Mild stress gate passes.

(cherry picked from commit 3d1f204)
Signed-off-by: DjDeveloperr <hey@djdev.me>
A render publication into an owner's installed pair took the device mutex
six times from the scheduler (seven from the ioctl): to fetch the
admission pool (and, from the ioctl, again to try it), to check the pair's
identities, to find the pair already built (constructing a throwaway set
of build resources), to look for a sibling pair to warm, to lend the pair
out and to publish it.

The admission pool lives as long as the firmware session, so the logical
queue keeps a reference to it. The identity check also reports whether the
owner's pair is installed, idle and backed, in which case the first pass
skips graph construction; every retry still goes through it. An owner
has exactly one pair (kick.rs asserts it), so there is no sibling to warm.
Steady state now takes the device mutex three times from either path.

gpubench unchanged within noise (render d1 151.6, d32 42.8, queues d8
58.8 us/submit); the mild stress gate passes.

(cherry picked from commit b7fa0d4)
Signed-off-by: DjDeveloperr <hey@djdev.me>
Every render publication held the device mutex, which the event worker
also needs for each pass, across the whole publication: dependency and
hazard collection, kick and descriptor commits, QoS accounting, both
work-ring records and producers, and the doorbell.

In the steady state (the owner's graph is installed and registered at its
priority, last ran this owner's scheduler, needs no growth, has nothing to
replay or settle, and the command has no compute prefix) the device mutex
now only lends the pair out, together with its free-list preparation and
a parameter-buffer reference, and takes it back. Preparation and
publication in between take the port: a render publication lock that every
render publication holds, with or without the device mutex (the tiling
and fragment work rings keep one host producer at a time, and attachment
overlaps keep their publication order), QoS accounting, the completion
stamps, the doorbell and the full-effort witness. The port gains views of
the render work rings and of the stamp page. The free-list lease leaves
preparation, or is rolled back with the parameter-buffer reference, when
the pair returns; while it is lent the event worker skips the pair, so no
retirement can touch its commands or references. A recovery that starts
during the publication fails it with EIO, as on the compute path.
Anything else, including a first publication, growth and owner changes,
still publishes under the device mutex.

During gpubench render rows 306k of 320k publications took the new path.
render.light d2/d8/d32 68.9/45.2/42.8 -> 65.9/43.5/41.1 us/submit, d1
150.2 (151.6), queues d8 58.7 (58.8); the rows stay firmware bound. Mild
stress gate passes.

(cherry picked from commit d272a70)
Signed-off-by: DjDeveloperr <hey@djdev.me>
After the direct render path, a steady-state publication still took the
device mutex three times: once to check the pair's identities and
readiness, then to lend the pair and to take it back. The lend itself
validates everything the identity check does.

The logical queue remembers the pair it last published to directly. A
lease on that pair (the ioctl's, or a non-blocking admission from the
scheduler) goes straight to the lend; anything else, and any lend that
declines, takes the full path with the identity check.

gpubench unchanged within noise (render d1 150.8, d32 42.9, queues d8
58.4 us/submit); the mild stress gate passes.

(cherry picked from commit 6428f7f)
Signed-off-by: DjDeveloperr <hey@djdev.me>
…L generation

The M3 runtime admits a VM only for a file that asked GET_PARAMS for at
least AGX3_PARAMS_SIZE bytes, and that was the size of
drm_asahi_params_global. The G17 update grows the structure from 600 to
616 bytes with two optional tail fields, memory_limit and
client_memory_limit, so Mesa built against the 600-byte structure would
be refused VM creation with EOPNOTSUPP until it is rebuilt.

The check only needs to know that the client knows the AGX3 fields. Pin
the minimum at the end of gpu_hal_generation, 600 bytes, and assert that
value at build time. GET_PARAMS still copies only the size the client
asked for.

Signed-off-by: DjDeveloperr <hey@djdev.me>
The main probe configured the GPU memory ledger for every GPU, so the
new defaults (mem_limit_pct=67, client_mem_limit_pct=50,
oom_attribution=1) also applied to M1, M2 and the M3 runtime. Those
GPUs would refuse BO creation with ENOMEM once committed sizes passed
the fractions, even with nothing resident, and would count GPU memory
in the creator's RSS for the OOM killer. The separate G15 probe never
configured the limits, but still got the RSS attribution, because it
was read from the module parameter on every object.

That is a policy change for every Mac, and it should be proposed on its
own. Until then, configure the ledger in the G17 probe only, and make
configure() also decide the RSS attribution. Every other GPU keeps the
totals, in fdinfo and sysfs, with no limit and no attribution, and
reports zero (no driver limit) in the GET_PARAMS tail. The module
parameter descriptions now say they apply to G17.

Signed-off-by: DjDeveloperr <hey@djdev.me>
@maralcbr

Copy link
Copy Markdown
Member

@DjDeveloperr fair enough on both:

  • Split: dropped. One PR is fine.
  • T6040: fine to keep. Matching apple,agx-t6040 only changes behaviour on an M4 Pro, which our installer doesn't offer yet. Please just add a line to the description saying it's initial, untested support.

Two things still block, because they change machines we ship today:

  1. M3 GPU on the current Mesa. drm_asahi_params_global grows to 616 bytes, and m3/m3_client.rs:33 uses size_of as the minimum GET_PARAMS size. The mesa-aurora on edge asks for 600, so the M3 runtime refuses its VMs with EOPNOTSUPP. Pinning AGX3_PARAMS_SIZE to 600 (the end of gpu_hal_generation) fixes it. The bounded copy in file.rs already handles the longer struct.
  2. Memory limits on M1/M2/M3. mem_limit_pct=67, client_mem_limit_pct=50 and oom_attribution=1 default on for every GPU through LEDGER.configure() and the shared gem_create (asahi_core.rs:177-188, file.rs:716). That's new ENOMEM behaviour outside G17. Defaulting them off, or applying them only on g17::Gpu for now, keeps this PR Neo-scoped. We can take the policy separately.

With those two fixed, plus a quick boot with a desktop and GL/VK smoke on one M1 or M2 and one M3, I'm happy to approve.

@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Thanks for the review, and for keeping it one PR. Both blockers are fixed:

  • M3 on the current Mesa: 18c6404 pins AGX3_PARAMS_SIZE at the end of gpu_hal_generation, 600 bytes. It's computed with offset_of! and asserted at build time, so the mesa-aurora on edge keeps its VMs. GET_PARAMS still copies only the size the client asked for.
  • Memory limits: 1032928 configures the ledger only in the G17 probe, and configure() now also decides the RSS attribution, which was read from the module parameter on every object before. M1, M2, the M3 runtime and the separate G15 probe get no limit and no attribution. They keep the totals in fdinfo and sysfs and report 0 (no driver limit) in the GET_PARAMS tail. The three parameter descriptions now say G17.
  • T6040: kept. The description now says it's initial, untested support.

#244 stays stacked on this branch. It can be folded in at merge time if you prefer.

Testing at 1032928:

On hardware, only the Neo is available to me right now. I'll post a Neo run of this exact head. I can't do the M1/M2 and M3 boots, so those would need you or another tester.

DjDeveloperr added a commit that referenced this pull request Oct 28, 2026
…0261027

Pick up #229's review fixes (the M3 GET_PARAMS minimum and the G17-only
memory limits). No conflicts.

Signed-off-by: DjDeveloperr <hey@djdev.me>
@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Neo (J700) hardware run of this exact head (1032928), as promised above.

Build and boot: the kernel was built with omarchy-pkgs' linux-aurora PKGBUILD (7.2.11.aurora8-4, release 7.2.11-8-4-ARCH, asahi build ID c6dc69dc) and booted on the Omarchy install. Userspace was the installed mesa-aurora (7c86130d).

  • Desktop: Hyprland and quickshell came up on GL (gallium) and rendered normally (screenshot taken).
  • Vulkan smoke:
    • gpubench render.light d1/d32, compute.light d1/d64, sync.signal queues d2 and copy.bw fill d1 all ran;
    • dEQP-VK.api.smoke.* 6/6 passed.
  • Regression gate (cross-queue order and data, 35 s memory pressure, mixed vkstress): pass.
  • Targeted Vulkan CTS at 6 workers (synchronization2 basic/timeline semaphores, command buffers, render passes): 4687 pass, 681 not supported, 0 fail.
  • Kernel: no GPU errors. One informational stamp-less compute retirement notice appeared, which is expected under the gate's load.

This head doesn't carry #235 (J700 display DART handoff), so the internal display path wasn't part of this run; #235 has its own Neo run.

A related fix is coming for this stack: aurora-silicon#555 retires a render group on its pass record when the firmware's completion stamps stall. Without it, about every other boot under load one client's render times out after ~30 s, and on an omacom kernel without the G17 timeout fixes the whole GPU runtime stops. That is the J700 first-boot GPU failure seen on a fresh omarchy-pkgs install. Its omacom mirror will stack on #244.

DjDeveloperr added a commit to omacom/mesa that referenced this pull request Oct 28, 2026
The aurora-wip sync brings drm_asahi_params_global's optional tail,
memory_limit and client_memory_limit, which grows the structure from
600 to 616 bytes. The kernel contract pinned for the ABI check,
7b969982306e, predates it, so check-kernel-abi.py fails on params_size.

Pin the contract to omacom/linux-aurora#229's head, 1032928116c1, the
kernel change that adds the same tail. With it, every compared size,
offset, ioctl number and feature bit matches. This branch therefore
merges after #229.

At runtime, Mesa still works with a kernel that has the 600-byte
structure: it zero-initializes the reply, and such a kernel leaves the
optional tail untouched.

Signed-off-by: DjDeveloperr <hey@djdev.me>
@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Here's an M2 Pro run (J414, MacBook Pro 14") of this PR's current head, with the rest of the stack merged on top.

Kernel: built with omarchy-pkgs' linux-aurora PKGBUILD as 7.2.11.aurora8-9 (release 7.2.11-8-9-ARCH). It's integration/aurora 30a6518 with this PR's head 1032928 (via #264, which carries #244 too), plus #235, #245 and #263, all merged clean. I booted it once on the Omarchy install, next to the regular 7.2.10.

  • Desktop: Hyprland, Xwayland and quickshell came up and render on the GPU. The internal panel runs 3024×1964 at 120 Hz, and brightness reads the same as on 7.2.10.
  • GL: glmark2-es2 on Wayland (build and texture scenes) ran on "Apple M2 Pro (G14S B1)" with the repo Mesa 26.2.4. Score 3795.
  • Vulkan: vkmark, headless, vertex and cube scenes, on vulkan-asahi 26.2.4. Score 13354.
  • Kernel log: no asahi errors, faults or timeouts at boot or after the smoke runs. No oops or WARN, and no failed units.
  • Rest of the machine: the same as the 7.2.10 boot. All 10 CPUs and cpufreq are up. Speakers, headphone jack and speaker sense, keyboard, trackpad and Wi-Fi all work. The kernel log has fewer warnings than on 7.2.10: the tas2764 device-tree parse errors are gone.

I don't have an M3, so the M3 boot still needs you or another tester.

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

@DjDeveloperr thanks, both blockers are fixed, and the Neo and M2 Pro runs cover what I asked for on hardware.

  • M3 params size: AGX3_PARAMS_SIZE is now the end of gpu_hal_generation, with a build-time assert!(… == 600) (m3/m3_client.rs:35-38). That's the same minimum the M3 runtime enforced before the struct grew, so the mesa-aurora on edge keeps its VMs. Since GET_PARAMS copies only what the client asked for, the 16-byte tail stays optional.
  • Memory limits: LEDGER.configure() moved from the common probe into probe_g17() (driver.rs:396-397). It's the only call, and an unconfigured ledger has limit and client_limit at 0, which means no limit. RSS attribution now follows ATTRIBUTE_RSS, which only configure() sets (memacct.rs:171-174, :321-327). So on M1/M2/M3 only the counters change.
  • T6040: the description now says initial and untested. Fine as agreed.

On hardware, the M2 Pro boot with the whole stack (desktop on the GPU, glmark2, vkmark, a clean log) covers the shared driver code on AGX2. The Neo run at this exact head covers G17. Neither tells us about the M3. The M3 runtime also goes through the changed shared MMU code (it adopts the shared UAT, creates shared VMs, binds compute contexts and maps GEM-backed tiler storage), and it picks up the new CPU mapping in timestamp::Buffer. The M4-only paths stay off there (m4_adopted = false). Edge is our qualification channel, so I'll accept that risk and not hold the merge for it. An M3 cold boot (desktop, GL/VK smoke) will be the first edge check once this is pinned.

Approving. #244 can land right after this.

@chriskearney chriskearney left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please restore const MODULE: Option<&'static kernel::ThisModule> = Some(&crate::THIS_MODULE); in AsahiDrmDriver before merging.

At reviewed head 1032928116c13840efaf0ba6ae68fee4e1cd70ea, commit 4b7aa809ff5 removes that override. The unchanged drm::Driver::MODULE default is None; UnregisteredDevice::GEM_FOPS passes it to create_fops, which sets fops.owner = NULL. drm_gem_prime_export also inherits that owner for exported DMA buffers.

For CONFIG_DRM_ASAHI=m, this loses the module reference that open DRM files and exported buffers need to retain their callback code. Unloading with those objects still live can therefore leave callbacks into unloaded code. It affects every Asahi backend, including the M3 configuration, and is inherited by #244. Restoring the existing override addresses the regression.

This finding is from the exact-head source and callback-owner wiring; no live module-unload test was attempted. Please retain regression coverage for the non-null owner in modular builds.

The G17 sync (4b7aa80) took drivers/gpu/drm/asahi/driver.rs from
aurora-silicon, whose Rust DRM layer derives the file_operations owner
from the driver's OwnerModule type. This tree's layer still takes it
from drm::Driver::MODULE, which defaults to None, so the sync dropped
the AsahiDrmDriver override that set it to THIS_MODULE.

With DRM_ASAHI=m, the GEM file_operations and the dma-bufs that
drm_gem_prime_export() creates then have a NULL owner. Open DRM files
and exported buffers no longer hold a reference on the module, so it
could be unloaded while their callbacks still point into it.

Restore the override, and assert at build time that MODULE is set, so a
later sync that drops it fails to compile.

Signed-off-by: DjDeveloperr <hey@djdev.me>
DjDeveloperr added a commit that referenced this pull request Oct 29, 2026
…0261027

Pick up #229's restored DRM module owner (6c66b41). No conflicts.

Signed-off-by: DjDeveloperr <hey@djdev.me>
DjDeveloperr added a commit that referenced this pull request Oct 29, 2026
…mp-fallback-20261028

Pick up #229's restored DRM module owner (6c66b41) through #244. No conflicts.

Signed-off-by: DjDeveloperr <hey@djdev.me>
DjDeveloperr added a commit that referenced this pull request Oct 29, 2026
…ity-20261028

Pick up #229's restored DRM module owner (6c66b41) through #244. No conflicts.

Signed-off-by: DjDeveloperr <hey@djdev.me>
DjDeveloperr added a commit that referenced this pull request Oct 29, 2026
…se-light-20261028

Pick up #229's restored DRM module owner (6c66b41) through #244 and #270. No conflicts.

Signed-off-by: DjDeveloperr <hey@djdev.me>
DjDeveloperr added a commit to omacom/mesa that referenced this pull request Oct 29, 2026
#229 gained 6c66b41a ("drm/asahi: restore the DRM driver's module owner"),
so its head moved from 1032928116c1. Re-pin the kernel contract to the
new head. The UAPI header is the same in both, so the ABI check is
unchanged. This branch still merges after #229.

Signed-off-by: DjDeveloperr <hey@djdev.me>
@DjDeveloperr

Copy link
Copy Markdown
Collaborator Author

Thanks, you're right. The G17 sync (4b7aa80) took aurora-silicon's driver.rs, and aurora's Rust DRM layer derives the file_operations owner from the driver's OwnerModule type, so it has no MODULE override. This tree's layer still reads drm::Driver::MODULE, which defaults to None, so the sync dropped an override that omacom needs.

Fixed in 6c66b41:

  • The const MODULE: Option<&'static kernel::ThisModule> = Some(&crate::THIS_MODULE); override is back, as at 30a6518.
  • const _: () = assert!(<AsahiDrmDriver as drm::driver::Driver>::MODULE.is_some()); next to the impl makes a later sync that drops it fail to compile. I checked that removing the line fails with E0080.

Testing:

The fix is merged forward into #244, #264, #270 and #271. aurora-silicon/linux needs no change, since its layer sets the owner from OwnerModule.

@chriskearney

Copy link
Copy Markdown
Collaborator

M3 Pro J516S/T6030 combined-kernel A/B/A regression test completed. Boot, GUI, OMT comparison, native GL/Vulkan readbacks and all benchmark/control runs passed. Single-submit CPU latency remains variable; these samples do not establish the initial apparent 21% kernel regression.

Tested source: base 30a651868a25 + #235 07d64c6b829a + #229 1032928116c1 + #244 10fe9098667a; union tree e7fba0c356c16110e55b17583b1ecc1462bb4596. #244 already contains #229. No #245/#263/#264 changes were added. The package was built natively; kernel archive SHA256 5488f726d891f44ec911e994e0639392d395ffde14bc3ff8cc3fa2b5baa4571a. Config SHA256 f1bdda16b2b0069eb9c3e7fdcce85d3034b77db3badc0e2ef754d0a3640dc801 is identical to the baseline, with G15 and M3_T8122 enabled and Asahi modular. All 115 DTB hashes and the 1,916-module set match the baseline. Mesa 7f0206e79f9 and Stage 2 bc79acc4 stayed fixed.

A1 and A2 booted the original 7.2.11-9-1-ARCH; B booted 7.2.11-9-3504.1-ARCH. Each job had installed identity MATCH before/booted/after. OMT 0.1.14 status maps were identical in all three arms: 38 pass, 10 existing fail, 25 skip. The candidate native checks completed 9,383 GL and 8,570 Vulkan iterations over 3 seconds each, with zero wrong pixels and no owned processes left.

The same pinned Vulkan helper and provider files ran in every arm: one warm-up plus three measured rounds of seven workloads, with clean and deliberately corrupted compute controls first. All 90 runs were valid; the negative controls detected exactly the injected error. Below are median CPU-side submit-and-wait times in milliseconds (lower is better, n=3 per cell).

Workload Original A1 Combined B Restored A2
raster 20.306 20.473 20.273
texture 42.959 42.855 43.044
compute 21.269 21.472 21.481
copy 51.101 51.189 51.850
submit-single 15.808 19.188 18.354
submit-batched 1.950 1.768 1.939
bo-lifetime 5.232 5.253 6.427

Single-submit B is +21.4% versus A1 but +4.5% versus A2; the restored original itself shifted +16.1%. Raw ranges overlap: A1 15.36–18.87 ms, B 17.22–19.32 ms, A2 17.58–22.42 ms. GPU timestamp medians were 1.582 / 1.583 / 1.595 ms. CPU placement was not pinned. A small CPU-side difference remains unresolved and needs controlled follow-up; this run cannot attribute the initial 21% difference to the kernel. Single-run OMT scores were glmark2 1949 / 1911 / 1901 and vkmark 6178 / 6362 / 5957.

The candidate logged G15: UAT leaf self-check passed and firmware READY. No new GPU/DART fault or watched memory-accounting/cleanup failure appeared. The raw kernel-log comparison remains REVIEW_REQUIRED: B added three TAS2764 probe-error lines versus A1, and all three also reproduced on the restored original A2. Audio tone testing was skipped.

Original packages, module trees, boot files and writer state were restored, both transaction audits were clean, and an additional audit after A2 was clean. The temporary test-agent update was reverted to its exact original binary; audio settings match the initial snapshot and leases are released. The first submission was refused before any test boot for an agent-version mismatch and was fully restored before retry. A2’s local wrapper initially rejected labd’s two implicit identity-test entries; the original rejection is retained, and the saved result was revalidated offline with all six actual tests required and passing.

Host/source coverage: 21 non-known host suites passed; two documented preexisting harness failures remain (apple-dart-range mocks and check-backlight include). Two independent shared-code reviews and a focused M3 review identified the module-owner regression reported above. DJ’s successor 6c66b41a restores the exact baseline owner line and adds a compile-time assertion; positive/negative controls passed on Rust 1.85.0 and 1.98.1. #244 successor 071f1581 has the verified fixed merge tree f56154aff85f782215d8a38eff3db399d17700fc. Those follow-ups were source-checked; the hardware results above are for the earlier frozen union. Fresh CI remains a separate gate.

Coverage is M3/G15 regression testing. Neo/G17 hardware, full conformance, suspend/hotplug and ordinary-login qualification are outside this run.

@chriskearney chriskearney left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The requested module-owner regression is addressed by 6c66b41a: the original MODULE = Some(&crate::THIS_MODULE) override is restored, and the new compile-time assertion rejects its removal. Positive/negative controls passed on Rust 1.85.0 and 1.98.1.

The pre-fix frozen #235+#229+#244 combination passed our M3/G15 boot, correctness and A/B/A regression run with exact restoration. Full results. Single-submit CPU timing remains variable (B +4.5% versus restored A2, overlapping samples); it does not establish the initial apparent 21% regression. This approval covers the shared-code/M3 regression review and owner repair. Updated-head hardware, Neo/G17 hardware and full conformance were not run here; fresh CI and normal merge requirements remain.

@maralcbr
maralcbr added this pull request to the merge queue Oct 29, 2026
Merged via the queue into integration/aurora with commit f9d9dbd Oct 29, 2026
13 checks passed
ludagoo pushed a commit to ludagoo/linux-aurora that referenced this pull request Oct 30, 2026
drm/asahi: G17 leak fix, render notifications and hop fixes from aurora (stacked on omacom#229)
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.

3 participants