Skip to content

AVD: safety and recovery (park DMA on retire, rest instead of retire, strict DART flushing for media/ML engines) - #758

Merged
RyanTheTide merged 4 commits into
aurora-wipfrom
avd/safety-recovery
Nov 1, 2026
Merged

RyanTheTide merged 4 commits into
aurora-wipfrom
avd/safety-recovery

Conversation

@RyanTheTide

Copy link
Copy Markdown
Contributor

Follow-up to #725, for decoder hang safety. One series, four commits:

  1. media: apple: avd: keep DMA blocked once the decoder is retired. Retiring now quiesces first: interrupt off, CM3 stopped, empty IOMMU domain attached and left attached. A reset that fails after DMA was blocked also keeps it blocked. The domain is detached at remove.
  2. media: apple: avd: rest the decoder instead of retiring it on a reset storm. A third recovery within a minute used to retire the decoder until a module reload. On the M2, the H.264 conformance suite retired it within 3 s, because a few vectors use features the hardware rejects. Now the decoder is parked until the window ends, frames fail fast without touching the hardware, and the next frame after that wakes it (reset with DMA blocked, restore, boot). Only a failed reset, restore or boot retires it.
  3. iommu/apple-dart: use strict flushing for media and ML engine clients. The kernels build with CONFIG_IOMMU_DEFAULT_DMA_LAZY=y, so a freed buffer's IOVAs keep translating for up to 10 ms after its pages return to the allocator. A late coprocessor write in that window corrupts unrelated memory and never faults. Clients whose DT compatible is apple,<soc>-avd, -ave, -ane, -isp or apple,isp now get a strict DMA domain, chosen in apple_dart_def_domain_type(). DT-driven, no knob.
  4. media: apple: avd: run the frame watchdog on the unbound system workqueue. Removes the "enqueued on deprecated workqueue" line from the first watchdog of each boot.

Why

The J616s hard hangs on 2026-11-01 (analysis: reports/engines-20261031/avd/HANG-ANALYSIS.md, 11-01 addendum) all followed decoder resets or stream teardown with DMA in flight, and none left a panic or a pstore record. On the M2 with #725, the DMA-after-error was observed directly. After a VP9 H8 error and recover: stop firmware, the DART logged ten translation faults on the empty domain within 2 ms. The engine keeps writing after it reports an error. Commits 1 and 3 close the two remaining ways such writes could reach memory: the retire path, and the lazy-flush window after any free.

Tests

  • Builds:
    • AVD: external module against 7.3.0-aurora-tt3 with W=1, no warnings, for each AVD commit.
    • apple-dart: KUnit 26/26 under qemu arm64 with 16K pages, including the new apple_dart_test_strict_engines, which covers every engine compatible in our DTs plus look-alikes that must not match. apple-dart.o builds W=1 clean with the fleet config.
    • tools/asahi/run-host-tests.py on this branch: 158/158.
  • Hardware (tt3, module swap, 2026-11-01). The AVD module tested was media: apple: avd: safety fixes for the current driver (mailbox, early completion, reset, AV1, FFmpeg HEVC) #725 plus commits 1 and 2:
    • M2 (T8112):
      • Three forced VP errors within a minute: two quiesced recoveries, then "decoder resting ... up to 60 s".
      • Frames during the rest failed fast. Then "recover: wake after rest" and a clean decode, bit-exact at H.264 1080p 503 fps and HEVC 848.
      • 40 random SIGKILL teardowns clean.
      • No DART fault outside a recovery.
    • M1 Pro (T6000):
      • Every row bit-exact: H.264 1080p 276 fps, HEVC 540, VP9 236, H.264 4K 112.
      • N=2 and N=4 bit-exact.
      • ffmpeg -hwaccel v4l2request framemd5 identical to software for H.264, HEVC and VP9 at 1080p and 4K.
      • 40 SIGKILL teardowns clean. One forced VP error gave a 9 ms quiesced recovery.
    • Neo (T8140):
      • 32 avd-bench rows (H.264, HEVC, VP9 and AV1, 1080p and 4K, N=1/2/4) plus 8 ffmpeg hwaccel clips, all bit-exact, with zero AVD or DART kernel lines.
      • HEVC through FFmpeg: 1080p 286 fps, 4K 88.
  • Strict-flush cost (commit 3). The same domain type was selected at runtime through /sys/kernel/iommu_groups/N/type with the driver unbound, and compared on the same boot.
    • AVD on the M2, N=1 Q4 lazy vs strict: H.264 1080p 503 / 502, 4K 189 / 190; VP9 369 / 369, 123 / 123; HEVC 849 / 839 (-1.2 %), 337 / 335 (-0.5 %). N=4 equal within 1 %.
    • ANE on the M1 Pro, MobileNetV1, 1000 runs (ANE lead): p50 1618.9 µs strict vs 1623.2 µs lazy, so no measurable cost. The ANE and AVD groups are already strict by default there.
    • AVE on the Neo (AVE lead): its group is already strict, at 110 / 100 fps for H.264 / HEVC.

The J616s (T6041) is where commit 3 changes AVE and ISP from lazy to strict. Its AVE lazy-vs-strict receipt comes with the AVE performance PR's J616s run.

🤖 Generated with Claude Code

When the recovery budget runs out, or a reset fails, the decoder is
retired: its jobs fail without touching the hardware until the module is
reloaded. The frame that triggered it is still finished with an error,
so its buffers go back to userspace while the engine that just timed out
may still be running, which is the DMA-after-free pattern behind the
J616s hangs.

Retire through the same first steps as a recovery: disable the
interrupt, stop the CM3 and attach the empty IOMMU domain, then leave it
attached. A still-running engine can then only fault at the DART. A
reset that fails after DMA was blocked keeps it blocked as well. Detach
the empty domain at remove so a reload starts from the DMA domain.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
… storm

A third recovery within a minute retired the decoder until the module
was reloaded. That is too harsh for a desktop: on an M2 the H.264
conformance suite retired it within three seconds, because a few
vectors use features the hardware rejects with a VP error, and every
later stream failed until a reload. A user with a bad file would lose
hardware decode until a reboot.

Recoveries are now quiesced (DMA blocked at the DART before the reset)
and have held up under forced errors, so the budget only needs to bound
their rate. When it runs out, park the decoder (interrupt off, CM3
stopped, DMA blocked) and fail new frames without touching it until the
budget window ends. The next frame after that resets it with DMA still
blocked, restores the DMA domain and boots the firmware. Only a reset,
restore or boot that fails retires the decoder.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
The video decoder, video encoder, neural engine and camera ISP are run
by their own coprocessor firmware, which can still have DMA in flight
after the host driver gives up on a job: a frame timeout, a reset, a
stream torn down mid-frame. With deferred flushing a freed buffer's
IOVAs keep translating to its pages until the flush queue drains, while
the pages are already back in the allocator, so such a late write
corrupts unrelated memory without any fault. The M4 Pro hard hangs
under AVD stress all followed decoder resets and left no panic and an
empty pstore, which fits this.

Give these clients a strict DMA domain, chosen from the client's device
tree compatible ("apple,<soc>-avd", "-ave", "-ane", "-isp" and
"apple,isp"), so a late write faults at the DART instead. They map
their buffers once per stream or model, so the per-unmap invalidate
stays off the hot path. Per-stream T8140/T8142 DARTs were already
strict through apple_dart_capable().

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
…ueue

The first frame watchdog of every boot logged "workqueue: work func
avd_watchdog_func enqueued on deprecated workqueue" because it was
queued with schedule_delayed_work() and mod_delayed_work(system_wq).
The watchdog has no CPU affinity to keep, so queue it on system_dfl_wq.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
@RyanTheTide
RyanTheTide merged commit 0529247 into aurora-wip Nov 1, 2026
@RyanTheTide
RyanTheTide deleted the avd/safety-recovery branch November 1, 2026 00:56
RyanTheTide added a commit that referenced this pull request Nov 1, 2026
Brings in #758 follow-ups and #773 (PMC performance floor with the AVD
perf-domain consumer). The one conflict is probe: keep the rewrite's
avd_pm_enable() and firmware probe boot, and settle the attached domain
links to suspended before it, as #773 does for the stock driver.

Assisted-by: LLM
Signed-off-by: Ryan Murray <ryan@aurorasilicon.org>
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.

1 participant