Repository navigation
drm: apple: av: let the AV endpoint's AFK slots be reused - #3
Closed
nekolyanich wants to merge 4 commits into
Closed
nekolyanich wants to merge 4 commits into
nekolyanich wants to merge 4 commits into
Conversation
added 4 commits
October 14, 2026 07:44
afk_recv_handle_reply() dropped a reply shorter than the command header. Its caller then waited the command out; if the command had already timed out (free_on_ack), its DMA buffers and its cmd_map bit were never freed, and the service's slot could not be reclaimed. Complete it instead, as failed. The short replies seen are 4 bytes, which looks like a bare IOReturn (an assumption): a nonzero one is passed on, anything else completes with AFK_RETCODE_SHORT_REPLY (~0), so that no caller reads its output buffer as a reply. AFK v2 replies reach this function with a full header and are not affected. Seen with 13.5 firmware on an M2 Pro (downstream trees), always 4 bytes: 28 times on the DCPDPDevice endpoint across 7 boots, the first in each boot for a command still pending (whose caller then timed out), the rest for commands that had already timed out; and once on the AV endpoint, for an audio getElements stuck behind a blocked rx worker. Assisted-by: Claude:claude-opus-5-5 checkpatch Signed-off-by: nekolyanich <me@nekolyanich.com>
DCP announces the AV endpoint's services (DCPAVSimpleVideoInterface and DCPAVAudioInterface) again on every display connect. They are not reusable, so each connect takes two of the endpoint's 16 slots for good: after eight connects in one boot the next display got "AFK[ep:29]: no reusable service slots" and no audio service until a reboot (M2 Pro, a TV on a USB-C to HDMI adapter, under the m1n1 hypervisor). Convert their owners the way commit 5837706 ("drm/apple: pin DP service owners before recycling retired AFK slots") did for the DP service, on which this builds. The audio service keeps an owner pin while asrv->srv points to it, released on its teardown or, after afk_shutdown() on unbind, in av_service_detach(). An announce without a teardown, not seen, warns and drops the older pin, and a late teardown of the older one then leaves the live one alone. The open and close in av_service_connect() and av_service_disconnect(), made without srv_rwsem, pin it for the call. The close no longer disables a torn down service itself: the teardown handler already clears enabled. The video service keeps no pointer to it. Then mark both reusable. Fixes: 02e1582 ("gpu: drm: apple: Set up client of AV endpoint") Assisted-by: Claude:claude-opus-5-5 checkpatch Signed-off-by: nekolyanich <me@nekolyanich.com>
Add the slot index to the "new service" line, and whether the slot was used before, so slot reuse can be told from a table that is merely not full yet. Assisted-by: Claude:claude-opus-5-5 checkpatch Signed-off-by: nekolyanich <me@nekolyanich.com>
is_open said that the audio service had been opened, but not which announce of it: a teardown left it set, and if the display's disconnect came after the teardown, av_service_disconnect() found no service and returned without clearing it, so the next generation was never opened. Keep the generation that was opened instead, counted at each announce, and set it only if no teardown came during the open; a generation torn down meanwhile is not connected to the audio device either. The open and the close checked and changed the state without a lock, and the hotplug, power and start paths call them concurrently (two disconnects 0.7 ms apart seen once): serialise them with open_lock, which the AFK rx worker never takes. Found by reading, not seen to matter in our runs. Assisted-by: Claude:claude-opus-5-5 checkpatch Signed-off-by: nekolyanich <me@nekolyanich.com>
Owner
Author
|
Published as aurora-silicon#299 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DCP announces the AV endpoint's two services (
DCPAVSimpleVideoInterfaceandDCPAVAudioInterface) again on every display connect. Their ops are not reusable, so each connect takes two of the endpoint's 16 slots for good, and after eight connects in one boot the next display getsAFK[ep:29]: no reusable service slotsand no audio service until a reboot. Before aurora-silicon#282 DCP also replugged the sink itself after refusing an audio start, which got there within minutes (seen 2026-10-11: from the 9th connect); with aurora-silicon#282 it takes eight real replugs, which a dock or a KVM switch still reaches. 5837706 kept unconverted owners like these non-reusable on purpose; this converts them, the same way, and builds on itsafk_service_get/put. aurora-silicon#293's 7357e51 defers re-announced DPAV services on AFK v2; it does not reach the AFK v1 AV endpoint, and this series doesn't touch its path.Commits:
drm: apple: afk: complete a command whose reply is too short as failed: a reply shorter than the command header was dropped, so its caller waited the command out, and a command that had already timed out kept its buffers and the slot. It now completes as failed: with the reply's IOReturn if it is nonzero (the 4-byte replies look like a bare IOReturn; an assumption), elseAFK_RETCODE_SHORT_REPLY. On our side (13.5 firmware, downstream trees) these were always 4 bytes: 28 times on the DCPDPDevice endpoint in 7 boots and once on the AV endpoint. This path is AFK v1 only: AFK v2 replies reachafk_recv_handle_reply()as a full synthetic header afterafk_v2_receive()checked them, so they never take it. Not seen onaurora-wip, so it is untested here. b12111f (onsatchlj/j613-25g83-gpu-dt-handoff, not inaurora-wip) handles the 14.7 short results on the std-service path.drm: apple: av: pin the AV services and let their AFK slots be reused: the audio service keeps an owner pin whileasrv->srvpoints to it, dropped on teardown or, afterafk_shutdown()on unbind, in the newav_service_detach(). An announce without a teardown (not seen) warns and drops the older pin. The open and close inav_service_connect()/av_service_disconnect(), made withoutsrv_rwsem, take their own pin; they nest with the get/put thatafk_send_command_timeout_len()and the v2 handlers now take. The video service keeps no pointer. Then both are marked reusable. The AV ops have noprepare, soafk_service_reinit()enables them as before and the owner pin ininitsucceeds.drm: apple: afk: log which slot a service gets: slot index and "(reused)" on the existingnew serviceline. A slot freed byafk_service_discard()logs as not reused. Easy to drop.drm: apple: av: open each generation of the audio service:is_openbecomes the generation that was opened, so a teardown during or before the disconnect no longer leaves the next generation unopened, andopen_lockserialises the open and the close, which the hotplug, power and start paths call concurrently (two disconnects 0.7 ms apart, once). Found by reading; separate so it can be judged or dropped on its own.Testing: MacBook Pro 16" M2 Pro (j416s), DCP firmware 13.5 (AFK v1), under the m1n1 hypervisor, with the bench-only DT change from aurora-silicon#276 (
atc0out of the DCP routes). A TV on a USB-C to HDMI adapter ondcpext0, a Dell over Thunderbolt ondcpext1. The kernel isaurora-wip(bb41967) with this series, aurora-silicon#276, aurora-silicon#277 and aurora-silicon#296; the series has since been rebased ontoaurora-wipafter aurora-silicon#293 (two textual conflicts in afk.c). An initramfs prompts me to replug the TV's adapter (16 times, 30 s after each plug) and starts 2 s of silence (2 ch, 24 bit) on the TV's card about every 7 s, 120 starts in all. Counts are for the TV's DCP (289c00000).aurora-wip(2026-10-11, before aurora-silicon#282)DCPAVSimpleVideoInterfaceslot 0 andDCPAVAudioInterfaceslot 1 (andAppleDCPDP2HDMIslots 0 and 1), each 1 new + 16 reusedno reusable service slotsAll 95 starts that began and ended with the display connected played in full; the other 25 fell around the replugs, while the display was unplugged or not yet back (counted per window, not start by start; 5 of them are prepares that timed out). DCP logged "Capabilities changed" 4 times, each 0.5-1 s after an unplug (DCP's log shows a DPTX link fault before it restarts its AV interfaces), none at an audio start after a plug. No "announced again without a teardown", no short replies, no WARNING, no runtime PM underflow.
On the new base (aurora-wip after aurora-silicon#293, with this series as rebased, aurora-silicon#276, aurora-silicon#277 and aurora-silicon#296), two cold boots under the hypervisor with the TV and the Dell attached: both displays connected, 8 of 8 starts played in full on the TV, no "Capabilities changed", no WARNING, no
no reusable service slots. No replugs there.Not tested: natively on
aurora-wip, other Macs, AFK v2 (H17P/J700), the 12.3 firmware command table, unbind with an audio service up, the short-reply path (commit 1). No KUnit cases yet; the short-reply completion and the owner pin could go next toafk-service-test.cif you want them.Follow-up, not in this PR:
dcp_audiosrv_*holdsrv_rwsemfor write across their AFK calls (up to 1 s each), so a teardown in the rx worker waits behind them, and the calls queued after it time out. Pinning under the read lock, as connect/disconnect do here, would fix that. Andstart_av_service_wqis not cancelled on unbind, so the start work can still open the service afterav_service_disconnect()there.