Repository navigation
drm/asahi: g17: fence recycled firmware identities and storage - #1176
Conversation
G17 hands a new logical queue the lowest free application context (TTBAT id) and QoS ID, and a new context takes the first matching work-state, descriptor or queue object from the device's object cache. A returned identity or object is therefore taken by the very next queue. The firmware names a context's work by those identities: work-state keys are (context id, state word), and queue records carry the context id and QoS ID. An installed compute queue keeps its record after its last owner exits: the scheduler page and work storage stay retained for it, but the context id goes back to the allocator as soon as the scheduler release is consumed. Short-lived Vulkan devices that create and destroy many queues (mesa#184 v1 reserved all eight at vkCreateDevice) hit this on the J616s (M4 Pro, fleet27): aurora: G17: recovery MMU fault bank 0: address 0x7061df9800 write Unmapped unit Unknown(217) (0xd9) level 0 vm_slot 15, slot_mask 0x0 aurora 28a600000.gpu: RTKit: co-processor has crashed (EL1t, ESR 0x96000044, FAR 0x0, x0 = work-state object + 0xf40) The first is a compute-side write through context 15 into the kernel lower arena with no tracked job; the second is the firmware appending to a work list through a node whose links read zero, the state of a freshly recycled work-state object. Give each identity the lifetime of the records that name it: - A context holds its execution identity (mmu::ContextHold), and so does every retained queue record that names it. While a hold remains the identity is handed out only if no other context is free. - Once the firmware has seen an identity, the last hold fences it: it is reused only after the firmware consumed a device-control record published after that point. The firmware consumes control records in order, so that record proves it finished the release that retired the owner. The control producer counts published records across firmware restarts, and every publication and service pass records how far the consumer got. QoS IDs follow the context the same way. - Returned identities are reused oldest first, as the VM slot allocator already does for G13 to G16; mmu::pick_returned is the shared helper. - The object cache reuses the object returned longest ago once its fence is met. A younger one is reused only when its family has no room for a fresh cached mapping, since an uncached one is unmapped as soon as its owner drops it. Under churn every closing queue publishes its own release, so fences clear within a pass or two; in a lull the reuse order keeps fenced identities at the back. Nothing is refused for a fence: when every free context waits, the one with the oldest fence is taken and counted. debugfs capacity reports fenced and overrun counts. Assisted-by: LLM Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com>
|
Baseline row without this PR: J616s on its fleet27 default (7.3.0-aurora-fleet27, boot b701e6ec, up ~4 h with a GNOME session on seat0, no reboot), Enforcing, the same kit (kits/test/20261108-gpuk), 14:40-14:47.
0 firmware crashes, 0 G17 recoveries, 0 MMU faults, 0 device lost, 0 watchdog, 0 AVC on every fleet27 row. The debugfs capacity counter shows So the race did not reproduce on demand without the fix either, which matches GPUX2's 0 in 9. The fix-vs-no-fix rows have no reproducing case to compare. The case for this PR is the code analysis plus the two fleet27 incidents (05:03 MMU fault vm_slot 15, 05:09 RTKit crash), not a reproducer. Timing on the tsem rows is the same within noise. The only behavioural difference the rows show is the fix's debugfs fence/overrun counters under heavy load. Evidence: traces/gpu/20261108-j616s-gpuk-fw-id-fence/fleet27base (S500): seq/run logs, per-row kernel logs and capacity snapshots, full |
|
fleet30 rows on the J616s, with and without this PR. fleet30 is the new default and already contains #1146. The fixed kernel is 7.3.0-aurora-gpuk2: fleet30 50d5865 plus this PR's commit cherry-picked cleanly (b08bbf1d), built with the same recipe as gpuk1, config identical to fleet30. It ran as a guarded one-shot. With the fix (gpuk2, boot 6518a211, 16:33-16:40):
0 firmware crashes, recoveries, MMU faults, device lost, watchdog hits and AVC. The debugfs fence counters after tsem6 read Without the fix (fleet30 default, boot bf7b1fd3, right after): tsem 6-shard v1 x2 gave 6 and 1923 pass. In run 1 all six shards hit vkCreateDevice OOM at once. The tsem 4-shard v1 pass that followed crashed the GPU firmware at 16:44:17: That is the 05:09 signature (EL1t, ESR 0x96000044, FAR 0, x0 at work-state object + 0xf40). All four shards segfaulted, with 4 device-lost and 4 EIO. A plain reboot to fleet30 brought the GPU back. This is the first on-demand reproduction. The fleet27 baseline above never crashed, and neither did GPUX2's nine runs. The difference is probably #1146: on fleet27, refused queue creation spun (26.9M refusals in my baseline), which throttled the churn. fleet30 refuses without spinning, so ids recycle faster. On fleet30 the same tsem v1 load crashes the firmware without the fix, and with the fix it ran 4x tsem4, 2x tsem6, churn and heavy rows clean on the same machine minutes earlier. One crash is not a rate, but the result points the same way as the code analysis. The 6-shard pass counts are dominated by how many shards OOM at device creation (6 to 1923 without the fix), so I don't read anything into the gpuk2 1284. The external display had dropped its link 33 s before the crash (dock power save). I don't think that is related, but I'm noting it. Evidence (S500): traces/gpu/20261108-j616s-gpuk-fw-id-fence/{gpuk2-fleet30,fleet30ctl} (README updated). The J616s is back on fleet30, gpuk2 is removed, Enforcing, 0 AVC. |
|
Merge-train rows so far (MTR3, 2026-11-08). Test kernel 7.3.0-aurora-f4mtr3g = integration/aurora af6d986 + #1122 + #1123 + #1124 + #1176, built with 0 warnings. Each Mac got one silent one-shot boot. The checks were our FLEET regression suite vs the same Mac's fleet31/fleet30 rows, plus keyboard/trackpad/HID/DART/MSI error counts and gpubench, test boot vs default boot:
Not merged yet: the plan was to merge after the M1 Pro row. The kit is kits/test/20261108-f4mtr3g on the S500, and the row script is work/linux/mtr3-20261108/comborow.sh (M1 Pro, TID=0). |
|
M1 Pro row done (the last of the four), 7.3.0-aurora-f4mtr3g = integration af6d986 + #1122 + #1123 + #1124 + #1176, one-shot vs the fleet31 default:
Rows passed on all four Macs (M2, Neo, J616s, M1 Pro). The trial merge onto integration d4d2678 is clean. Merging. |
Brings #1122, #1123, #1124 (T8142 DART/MTP/MSI), #1176 (G17 fw-id fence), #1201 (J700 speaker full scale) and the rest of integration since 11943fb into aurora-wip. Conflicts were in four device-tree binding documents only, where aurora-wip has the T8152 versions and integration the T8142/T8152/T6050 generalisation: - apple,admac: keep both the lone apple,t8152-admac and the apple,t6050-admac/apple,t8140-admac pair. - apple,t8152-aop: take integration (it still allows a lone apple,t8152-aop, one or two mailboxes). - apple,t8152-aop-audio: take integration and keep a lone apple,t8152-aop-audio compatible. - apple,dwc3: keep the T8152 host-mode rules, and require resets and usb-role-switch on every enabled non-T8152 controller. Signed-off-by: Ryan Murray <81541646+RyanTheTide@users.noreply.github.com> Assisted-by: LLM
G17 recycles firmware-visible identities straight away, lowest first: a new logical queue gets the lowest free application context (TTBAT id) and QoS ID, and a new context gets the first matching work-state, descriptor or queue object from the object cache, zeroed. The firmware keys work by (context id, state word), and installed queue records carry the context id and QoS ID. An installed compute queue keeps its record after its owner exits, but the context id goes back to the allocator as soon as the scheduler release is consumed, so the next queue created can take an id that a record still names.
With mesa#184 v1 (eight eager kernel queues per VkDevice) the J616s hit this twice on fleet27:
The first is a compute-side write through context 15 into the kernel lower arena, with no tracked job. The second is the firmware appending to a work list through a node whose links read zero, which is what a freshly recycled work-state object looks like. Evidence: traces/gpu/20261108-j616s-g17-capacity-j6am and 20261108-j616s-mesa184-bisect-gpux2 (S500).
Change
mmu::ContextHold) and its QoS ID (Arc<QosLease>). While a hold remains, the identity is handed out only if no other context is free.g17/channel.rscounts published records across firmware restarts, and every publication and service pass records how far the consumer got.mmu::pick_returnedis the shared helper. Application contexts and QoS IDs both use it.capacitygainsexecution_contexts_fenced free_waiting= overruns=andcached_objects_fenced waiting= overruns=.Cost is a scan of at most 64 contexts, 128 QoS IDs or 64 cache slots at queue or context creation, plus one atomic add per control record. The submit path is unchanged.
Receipts
Test kernel 7.3.0-aurora-gpuk1 is fleet27 95e30d5 plus #1146 and this commit. Its config is identical to fleet27, and its GPU driver source is byte-identical to this PR's head (integration's driver equals fleet27 plus #1146).
J616s (M4 Pro), one-shot on boot d4daba0c, Enforcing, 0 AVC:
Under the heavy run (40 open queues plus 19 idle installed compute queues holding ids, against 58 contexts), contexts overran their hold 444 times and the object cache 448 times, both oldest first. The no-refusal fallback did its job. The debugfs counters show it.
M2 (G14), one-shot: no regression. qchurn 12/12. qual (nosuspend): GPU dmesg 0, AVC 0, warn/err classes 4/1 = baseline 4/1. glmark2 4159/5596/4681/4377 vs fleet27 4612/4549/4387/4696, within post-boot noise. The G13/G14 path does not run the changed code.
Host tests:
tools/asahi/run-host-tests.py195/195.g17-growth-testsstubs the newobserve_controlcall. New KUnitasahi_mmu_execution_contextcovers the pick order and the fence and hold fallback. Driver compiles without warnings.Still to do: a same-boot fleet27 baseline of the same qchurn and tsem rows on the J616s, which needs a slot after the morning audible run. The incidents never reproduced on demand (GPUX2: 0 in 9 runs), so the baseline is evidence, not a gate. Possible follow-up: release an idle compute queue's context id under id pressure, so heavy load needs no hold overrun.
Kit: kits/test/20261108-gpuk. Traces: traces/gpu/20261108-j616s-gpuk-fw-id-fence (S500).
🤖 Generated with Claude Code