Skip to content

RX: keep multiple bulk-IN URBs in flight (mirror kernel's always-posted model)#107

Merged
josephnef merged 1 commit into
masterfrom
fix/8814-rx-multiurb
Jun 26, 2026
Merged

RX: keep multiple bulk-IN URBs in flight (mirror kernel's always-posted model)#107
josephnef merged 1 commit into
masterfrom
fix/8814-rx-multiurb

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

What

The monitor-mode RX loop did one synchronous libusb_bulk_transfer at a time, leaving a window between transfers where no URB is posted. usbmon ground-truth on the same hardware shows the kernel (rtw88) instead keeps 4 bulk-IN URBs always posted, re-submitting each ~20 µs after completion.

With a single posted URB, the RTL8814AU's RX-DMA ring pauses in the parse gap and, under sparse traffic, intermittently wedges after a short burst — the "8814 RX stalls after ~10 frames" symptom (the 8812/8821 tolerate it; the 8814 does not).

Change

Run infinite_read() from a small worker pool (default 4) instead of a single loop. infinite_read() is already reentrant — local 32 KB buffer + local FrameParser, and libusb is thread-safe — so the workers simply restore the always-posted behaviour the kernel has. packetProcessor is serialised under a mutex. Frame order across workers isn't preserved, which is fine for monitor-mode RX.

DEVOURER_RX_URBS overrides the worker count (1 restores the old single-transfer behaviour).

Validation

  • usbmon-confirmed: the pool keeps 4 bulk-IN URBs in flight (matching the kernel).
  • Regression-clean: RTL8812AU and RTL8821AU RX 300+ frames; RTL8814AU healthy. ctest green.
  • Diagnosed against a known-good kernel reference (88XXau/rtw88_8814au) which receives thousands of frames where devourer's single-URB path stalled — confirming the 8814 RX hardware is healthy and the stall was a host-side single-URB issue, not RF/rig degradation.

Honest caveat

The intermittent 8814 stall this targets is timing-dependent and was dormant at commit time, so this hardens the RX path to match the kernel's proven always-posted model rather than being confirmed against a live reproduction. It is low-risk (reentrant call, mutex-serialised delivery, env escape hatch) and regression-validated on all three Jaguar chips.

🤖 Generated with Claude Code

…ed model)

The monitor RX loop did one synchronous libusb_bulk_transfer at a time, so
between transfers no URB is posted. usbmon ground-truth shows the kernel
(rtw88) instead keeps 4 bulk-IN URBs always posted and re-submits each ~20us
after completion. With a single posted URB the 8814's RX-DMA ring pauses in
the parse gap and, under sparse traffic, intermittently wedges after a short
burst — the "8814 RX stalls after ~10 frames" symptom (8812/8821 tolerate it).

Run infinite_read() from a small worker pool (default 4) instead of a single
loop. infinite_read() is already reentrant — local 32KB buffer + local
FrameParser, and libusb is thread-safe — so the workers just give the same
always-posted behaviour the kernel has; packetProcessor is serialised under a
mutex. Frame order across workers is not preserved, which is fine for
monitor-mode RX. DEVOURER_RX_URBS overrides the worker count (1 restores the
old single-transfer behaviour).

Validated: usbmon confirms 4 bulk-IN URBs in flight; regression-clean on
RTL8812AU / RTL8821AU (300+ frames) and RTL8814AU. ctest green.

Note: the intermittent 8814 stall it targets is timing-dependent and was
dormant at commit time, so this hardens the RX path to match the kernel's
proven model rather than being confirmed against a live repro.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@josephnef josephnef merged commit 7701ec5 into master Jun 26, 2026
6 checks passed
@josephnef josephnef deleted the fix/8814-rx-multiurb branch June 26, 2026 09:04
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