Repository navigation
drm/asahi: G15 pin module before retaining firmware ownership - #237
Conversation
A started G15 firmware session cannot be stopped, so boot::start pins the module before its first firmware-visible write and never drops the reference. The pin used __module_get(), which increments the count unconditionally, even after an ordinary rmmod has passed its reference check in try_stop_module(). The first start can run while the module is LIVE. Activation attaches synchronously during module init, but a probe deferred for the PMP supplier, or attached asynchronously with async_probe, runs later from the deferred-probe or async worker. If an rmmod has passed its reference check by then, module exit unregisters the driver, which waits for the in-flight probe to finish starting the firmware, unbinds the device and frees the module under the live session and its RTKit callbacks. Take the reference with try_module_get() before RETAINED is set and before anything firmware-visible. Once removal has begun this fails with ENODEV and leaves the firmware untouched, cleaned up as for a failed self-check: the cached-class objects are forgotten, the PMP vote is released and the session stays unretained. A caller that loses the race to set RETAINED drops only its own reference. The policy is in g15/retain.rs so the asahi-g15 host runner covers it: a refused pin marks nothing, the first pin is kept and later calls take nothing, a lost race drops only its own reference, and barrier-synchronized concurrent pins leave exactly one reference. Generated-by: LLM Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Chris Kearney <303316+chriskearney@users.noreply.github.com>
|
M3 Pro/J516S check at 095edba is complete. The native kernel booted in 33 seconds, bound the T6030 G15 driver, exposed no bind/unbind attributes, and had a positive Asahi module reference count. With system Mesa 147a62f619, pinned GL and Vulkan readback probes each ran for 3 seconds with zero wrong pixels. All three displays were active on that same boot. No matched AOP/GPU/DART fault was found in the retained candidate logs. The automated job retains TESTS_FAILED because its first display-topology assertion sampled before the third display appeared. The separately recorded same-boot follow-up saw all three displays and passed both pixel probes; it does not rewrite the original test. OMT comparison reported 0 new regressions, with 33 pass / 13 fail / 27 skipped against the recorded current-kernel baseline. Those existing failures are not a full release pass. The ordinary return to the working kernel completed, the archived boot entry was restored, and protected boot/reference files and the ESP reserve were verified. No unload/rebind experiment, Max hardware test, CTS, suspend, or RC-Mesa-7c86130 hardware qualification is claimed. The full production composition of #230 + #236 + this fix also built with clang/LLD 18.1.8 and Rust 1.85.0. Its actual module contains both corrected backend pin paths, and all 458 undefined symbols resolve against the shipped Module.symvers. This composition is separate build evidence; the physical boot above tested 095edba with the frozen M3 configuration. |
scottjones
left a comment
There was a problem hiding this comment.
We went through this against the current integration/aurora tip (3e8ae2a, which includes #236). It merges cleanly and doesn't touch anything under m3/, so it doesn't interact with #236's claim_start / pin_module.
The ordering looks right to us. try_module_get runs after the self-check and before vote.keep(), Rtkit::new and the ASC RUN write. A refused pin returns ENODEV with RETAINED still clear, so the PMP vote and the power hold are released the same way as on a failed self-check. A caller that loses the race puts only its own reference, and the winner's reference is never put. Built-in (THIS_MODULE is NULL) and CONFIG_MODULE_UNLOAD=n both use the stock try_module_get / module_put stubs, so those are fine too.
What we ran:
- W=1 builds of drivers/gpu/drm/asahi/ at the head and at its merge-base with G15 only, G15+M3_T8122 and M3_T8122 only. No errors in any of them, and the warnings are the same as the base in each config.
- The G15 host suites (run.py plus the eight g15-*-tests.py with --mutations) and m3-batching-tests.rs. All pass.
- Mutations of retain.rs: marking before get, no put on a lost race, putting the winner, dropping the fast path, and ignoring a refused get. The runner catches every one of them.
One gap, which we don't think needs to block this: nothing tests the call site in boot::start. We moved retain_module() back to after shared.started is set and ignored its error, and run.py, g15-retention, g15-probe-init and g15-maintained-handoff all still passed. The helper is well covered, but the ordering this PR is really about is only checked by reading the code. #236 is in the same position. A follow-up that pulls the order of start into something the host runner can check would be nice, but it isn't needed for this PR.
Looks good to us once the M3 Pro boot check is in.
b9221c3
A first deferred or asynchronous G15 probe can race ordinary module removal. The old retain path set
RETAINEDand then called__module_get, which can increment the reference count after unload has already committed to removal. Firmware and RTKit callbacks could then outlive the module.Use
try_module_getbefore marking the session retained or touching firmware. A refused pin returns ENODEV with the session unretained; cached objects follow the existing failed-self-check retention policy and the PMP vote is released. Keep one permanent reference and drop only redundant temporary references. The post-start retain call propagates errors. Existing model, firmware, display and autoload admission rules are unchanged.Validation at 095edba:
try_module_get/module_put; the old unconditional G15 helper is absent. The resolved config differs from the frozen M3 input only in LOCALVERSION, and Image/module/J516S DTB identities agree.This is a separate G15 fix; #236 addresses the T8122 Air runtime. Both should precede enabling the corresponding runtime in #230. #229/#233 are not included.