Jaguar USB RX: 16 KB URBs + matching agg caps — restore the MediaTek host fix#317
Merged
Conversation
Closed
…host fix (#314) Some MediaTek Android xhci/usbfs stacks (Dimensity 810, Helio G99, MT6765) never complete a bulk-IN read larger than 16 KB — LIBUSB_ERROR_TIMEOUT forever, zero RX with a green init (OpenIPC/PixelPilot#6). floppyhammer's #19 fixed this with 16 KB host reads plus ≤16 KB device-side RX aggregation; the async-ring rewrites (#158/#164/#168) and the #213 transport split (40e3a2a) kept the aggregation half but regressed the host reads to 32 KB URBs on every 11ac generation. PixelPilot#104 shipped the first Android build of the async ring and the no-video reports came straight back. - Jaguar1/2/3 RX rings: 16 KB URBs (DeviceConfig::Rx::urb_bytes, env DEVOURER_RX_URB_BYTES, clamped >= 4096). Free on healthy hosts: with aggregates capped ≤16 KB a 32 KB URB never filled past 16 KB anyway — each aggregate ends its URB via short packet. - Jaguar2/3 halmac agg page-threshold 0x05 (20 KB) -> 0x03 (≤12 KB): an aggregate must never span two URBs or the next_offset walk breaks. Deliberate divergence from the kernel's 0x05, documented at both sites. - Kestrel untouched: the 8852C RXAGG LEN_TH (~20 KB) requires its 32 KB ring; the knob is documented as 11ac-only. - Docs: CLAUDE.md hardware gotcha + performance-tuning.md lever entry. ctest 36/36. Desktop bench (regress 2x2, goodput A/B) and on-device MTK validation via PixelPilot#6 volunteers tracked in #314. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
josephnef
added a commit
to OpenIPC/PixelPilot
that referenced
this pull request
Jul 20, 2026
…RX ring Fixes the #6 regression reported on 2026-07-19. PR #104 bumped devourer past the transport split that deleted RtlUsbAdapter.cpp: the device-side half of floppyhammer's fix (16 KB RX aggregation caps) survived, but the host side regressed from 16 KB reads to 32 KB URBs — the exact transfer shape some MediaTek xhci/usbfs stacks (Dimensity 810, Helio G99, MT6765) never complete: LIBUSB_ERROR_TIMEOUT forever, zero RX, no video. - devourer submodule -> b7c50ec (OpenIPC/devourer#317, merged master): 16 KB URBs on all 11ac generations + matching Jaguar2/3 aggregation caps, tracked in OpenIPC/devourer#314. Bench-validated at delivery parity on RTL8812AU / RTL8812BU / RTL8812EU. - WfbngLink.cpp: cfg.usb.rx_zerocopy = false — keep the RX ring on plain heap buffers; the dev-mem zerocopy path is unvalidated on Android vendor kernels and every previously working Android build shipped the heap path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 20, 2026
Open
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.
Closes #314.
What
Restores the host-side half of @floppyhammer's MediaTek no-video fix (#19), lost when the RX path moved to the async URB ring and the #213 transport split deleted
RtlUsbAdapter.cpp:DeviceConfig::Rx::urb_bytes(envDEVOURER_RX_URB_BYTES, clamped ≥ 4096).0x05→0x03(20 KB → ≤12 KB): an aggregate must never span two URBs or thenext_offsetwalk breaks. Deliberate divergence from the kernel's value, documented at both sites.CLAUDE.mdhardware gotcha +docs/performance-tuning.mdlever entry.Why it's free on healthy hosts
The device-side aggregation caps (Jaguar1
rxagg_usb_size0x3/0x1 — the surviving half of #19) mean every aggregate is ≤16 KB and ends its URB via short packet: a 32 KB URB never filled past 16 KB. The URB size change costs nothing; it only removes the shape MediaTek hosts can't complete.The regression chain
libusb_bulk_transfer→LIBUSB_ERROR_TIMEOUTforever (diagnosis by @floppyhammer, Jan 2025).bbc7385, Mar 2026): 16 KB reads + ≤16 KB aggregation. Validated on-device by two reporters. PixelPilot#97 pins it.40e3a2a): aggregation half survives, host reads regress to 32 KB.Validation
tests/regress.pymatrices + delivery A/B 32K-vs-16K URBs — parity on J1/J2/J3 (table below)🤖 Generated with Claude Code
Bench results (2026-07-20, local rig)
Delivery A/B, devourer-RX cells, 15 s flood cells (
tests/regress.py,DEVOURER_RX_URB_BYTEScontrol arm):Drift between arms matches the kernel-RX control cells (7217→7401→7355) — the URB size is invisible on healthy hosts, as predicted: with ≤16 KB aggregates each aggregate ends its URB via short packet, so a 32 KB buffer never filled past 16 KB. The J2/J3 agg
0x05→0x03change shows no delivery cost (98.8% / 96.5% flood delivery, in line with this rig's history). Full 2×2 kernel-driver matrices pass on J1/J2 (ch 6 + ch 36); the J3 kernel cells are structurally absent (no kernel driver for the EU on this host). No 8814AU on the rig today — its delta is nil by construction (DMA-agg is 2 KB, far under either URB size; the multi-URB pool is untouched).