tx: TxMode::no_agg keeps a frame out of an A-MPDU (Jaguar3) - #459
Conversation
PR Summary by QodoHonor per-frame NOAGG requests on Jaguar3 transmitters
AI Description
Diagram
High-Level Assessment
Files changed (15)
|
Code Review by Qodo
1.
|
josephnef
left a comment
There was a problem hiding this comment.
Reviewed at 8619a75. Built clean, ctest 80/80 (the new radiotap_noagg included), vendor recipe cross-checked against reference/rtl88x2eu/hal/rtl8822e/usb/rtl8822eu_xmit.c (BK=1 for every data frame it does not aggregate, AGG_EN left 0) and the halmac SET_TX_DESC_BK bit position (dword2[16]). Mechanism and wire form are right.
Requesting one change: no_agg is dropped for rate-less frames
Qodo's bug 2 is real. In build_tx_block the rate-less fallback (src/jaguar3/RtlJaguar3Device.cpp ~L2586) copies fixed_rate/vht/sgi/ldpc/stbc/bwidth from _tx_mode_default but not no_agg, and no_agg is only ever set from a radiotap TX_FLAGS field. txdemo's QoS frame is rate-less by design (rate comes from SetTxMode), so DEVOURER_TX_RATE=MCS5/NOAGG under DEVOURER_TX_AMPDU_MODE still aggregates. CLAUDE.md and RadiotapBuilder.h now advertise /NOAGG in the DEVOURER_TX_RATE grammar, and that path is inert. The on-air harness never exercises it because only the ALT frames (which carry their own radiotap) get the flag.
Fix is one line in that block:
no_agg = no_agg || _tx_mode_default->no_agg;(per-packet radiotap rate still wins, as for the other fields.) Worth a sentence in the TxMode::no_agg comment that the default applies to rate-less frames only.
Measured here: the 8822C die passes
You listed the 8822C as unmeasured. Ran tests/tx_no_agg_onair.sh unchanged on this rig with an RTL8812CU (chip-id 0x13, USB high-speed) transmitting and a Comfast CF-924AC (RTL8822BU, external antennas, the rig's qualified ground station) as witness. ch36, 0/6, 4 senders, 1000 B, MCS5/MCS0 alternating:
| arm | odd (MCS0) at own rate | even (MCS5) at own rate | heard |
|---|---|---|---|
| noagg #1 | 100.0 % | 100.0 % | 1159 fps |
| control #2 | 23.8 % | 100.0 % | 2913 fps |
| noagg #3 | 100.0 % | 100.0 % | 1156 fps |
| control #4 | 24.6 % | 100.0 % | 2749 fps |
Verdict tx_no_agg_ok: true. The fold is deeper here than on your 8812EU (24 % vs 40 % own-rate in the control) and the every-other-frame cost is correspondingly larger (−60 % heard vs your −47 %). Please fold that into the AdapterCaps::tx_no_agg_ok comment and docs/aggregation.md so the 8822C row reads as measured (one 8812CU unit) rather than "shares the recipe".
Could not repeat the 8812EU arm: this rig's bare BL-M8812EU2 module drops off the USB bus about one second after the TX bring-up reset (dmesg USB disconnect then re-enumeration; build/doctor grades it HEALTHY on EFUSE/fw/RX). That is a supply problem on this bench, unrelated to the diff. Your EU numbers stand as the only EU measurement.
Nits
- CLAUDE.md
DEVOURER_TX_ALT_RATEentry: keep the var + one clause, move the parity/witness mechanics to the script header where they already are (Qodo's point 1, agree). stamp_counteris called unconditionally on the single-frame path and behindif (qos_stamp)on the batch path. Harmless since the helper checksqos_stampitself, but pick one.
build_tx_block's rate-less fallback copied every TxMode field from the SetTxMode default except no_agg, so DEVOURER_TX_RATE=.../NOAGG was inert for frames without their own rate radiotap. Propagate it; a frame with its own rate still takes no_agg from its own TX_FLAGS. tests/tx_no_agg_onair.sh gains a basenoagg arm that flags the rate-less base frames, the path the harness never exercised. On air (8812EU -> 8812EU, ch36, 0/6, 4 senders, 1000 B, MCS5/MCS0): basenoagg 100.0 % of both parities at their own rate (x2) with the fix; with the propagation line removed the same arm folds like the control (38.5 / 40.1 % vs 39.1 %). Also: the 8822C row reads as measured (one 8812CU, reviewer's rig) in AdapterCaps and docs/aggregation.md, the CLAUDE.md DEVOURER_TX_ALT_RATE entry is cut to one line, and txdemo's batch path calls stamp_counter unconditionally like the single-frame path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@josephnef all four items addressed in 7662ab6.
So the new arm fails on the bug and passes with the fix. The first 8822C: your 8812CU run is now in the Nits: the CLAUDE.md ctest 76/76. |
|
@josephnef one more 8822C ask, if the rig is still set up. The ARMS="basenoagg control basenoagg" DUT_PID=<8812CU PID> WIT_PID=<witness PID> \
sudo -E bash tests/tx_no_agg_onair.shPass means both parities are at their own rate in |
Supersedes the fork's earlier cut of the same feature (0acffd0). The four conflicts (RadiotapBuilder.cpp, RadiotapTxFlags.h, TxMode.h, FrameParserJaguar3.h) differed only in comments and take the PR side; radiotap_txflags_selftest.cpp returns to upstream's version, with the no_agg coverage in the PR's radiotap_noagg selftest. The Jaguar3 descriptor path merged to the PR's code exactly, including the rate-less SetTxMode propagation fix. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
josephnef
left a comment
There was a problem hiding this comment.
Re-reviewed at 7662ab6. The fallback line, the TxMode::no_agg comment, the basenoagg arm, the caps/aggregation.md update and both nits are as asked. Build clean, ctest 80/80.
basenoagg on the 8812CU, as requested. Same rig and witness as before (RTL8812CU transmitting on USB high-speed, CF-924AC RTL8822BU witness), ch36, 0/6, 4 senders, 1000 B, MCS5/MCS0, script unchanged:
| arm | odd (MCS0) at own rate | even (MCS5) at own rate | heard |
|---|---|---|---|
| basenoagg #1 | 100.0 % | 100.0 % | 1189 fps |
| control #2 | 23.4 % | 100.0 % | 2995 fps |
| basenoagg #3 | 100.0 % | 100.0 % | 1183 fps |
Verdict tx_no_agg_ok: true. The rate-less path through the SetTxMode default behaves identically to the per-frame radiotap path on the 8822C die: same 100 % own-rate, same ~−60 % heard for every-other-frame flagging, control fold unchanged from the 28 Sep run (23.4 % vs 23.8/24.6 %). Fold it into docs/aggregation.md as you offered; nothing else blocking.
Approving.
Under SetAmpduMode the MAC folds consecutive co-queued data frames into one
PPDU aired at the FIRST MPDU's rate and bandwidth, so a frame's own
MCS/BW/LDPC/STBC are silently replaced whenever it lands behind a frame of
another rate. A caller mixing rates in one aggregated stream (a robust
control frame among video, a probe at another rate) cannot rely on the rate
it asked for.
TxMode::no_agg (rate grammar token /NOAGG) rides a devourer-private radiotap
TX_FLAGS bit, kRadiotapTxFlagNoAgg = 0x0100 (RadiotapTxFlags.h; radiotap
assigns only 0x0001-0x0020, so a future registration of 0x0100 would
collide). The HT radiotap stays 13 bytes, and a default TxMode is
byte-identical. Jaguar3 reads the bit in build_tx_block and writes the
descriptor AGG_EN=0 + BK=1 (dword2[16]) after the A-MPDU overrides - the
vendor rtl8822eu xmit recipe for data frames it does not aggregate. Same
queue, so ordering is unchanged. AdapterCaps::tx_no_agg_ok advertises it
(adapter.caps "tx_no_agg"): true on Jaguar3 only; Jaguar1/2, Kestrel,
RTL8733B and the MT7612U ignore the bit.
On air, tests/tx_no_agg_onair.sh (one 8812EU transmitting, an 8812EU
witness, ch36, A-MPDU 0/6, 4 senders, 1000 B, MCS5 and MCS0 alternating by
frame counter via the new txdemo DEVOURER_TX_ALT_RATE):
arm MCS0 frames at MCS0 MCS5 at MCS5 heard fps
no flag (x2) 40.3 % / 40.4 % 100 % 2372
/NOAGG (x2) 100.0 % / 100.0 % 100 % 1250
/NOAGG, descriptor write 39.8 % 100 % 2391
disabled
The counterpart: a flagged frame breaks the aggregate around it, and
flagging every other frame (this harness's worst case) cut the heard rate by
47 %. The cost of occasional flagged frames is not measured, nor is the
8822C, which shares the descriptor recipe.
The script aborts rather than passes when the unflagged control shows no
fold (no mixed aggregates formed, so nothing was tested). Headless:
radiotap_noagg covers every builder layout with NOACK both ways and the
/NOAGG parse; removing the builder OR or the parse token fails it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C8fMvzDQNYJSePWPBmUP8f
build_tx_block's rate-less fallback copied every TxMode field from the SetTxMode default except no_agg, so DEVOURER_TX_RATE=.../NOAGG was inert for frames without their own rate radiotap. Propagate it; a frame with its own rate still takes no_agg from its own TX_FLAGS. tests/tx_no_agg_onair.sh gains a basenoagg arm that flags the rate-less base frames, the path the harness never exercised. On air (8812EU -> 8812EU, ch36, 0/6, 4 senders, 1000 B, MCS5/MCS0): basenoagg 100.0 % of both parities at their own rate (x2) with the fix; with the propagation line removed the same arm folds like the control (38.5 / 40.1 % vs 39.1 %). Also: the 8822C row reads as measured (one 8812CU, reviewer's rig) in AdapterCaps and docs/aggregation.md, the CLAUDE.md DEVOURER_TX_ALT_RATE entry is cut to one line, and txdemo's batch path calls stamp_counter unconditionally like the single-frame path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
7662ab6 to
7b5f759
Compare
The problem
Under
SetAmpduModethe MAC folds consecutive co-queued data frames into one PPDU aired at the first MPDU's rate and bandwidth. A frame's own MCS/BW/LDPC/STBC are silently replaced whenever it lands behind a frame of another rate. A caller mixing rates in one aggregated stream (for example a robust control frame among video, or a probe at another rate) cannot rely on the rate it asked for.The change
TxMode::no_agg(rate grammar token/NOAGG) is carried per frame in a devourer-private radiotap TX_FLAGS bit,kRadiotapTxFlagNoAgg = 0x0100(src/RadiotapTxFlags.h).0x0001–0x0020, so a future registration of0x0100would collide; the declaration says so.TxModeis byte-identical.build_tx_blockand writes the descriptorAGG_EN=0+BK=1(dword2[16]) after the A-MPDU overrides.rtl8822eu_xmit.crecipe for data frames it does not aggregate (EAPOL/ARP/DHCP included).AdapterCaps::tx_no_agg_ok(adapter.capsfieldtx_no_agg) advertises support: true on Jaguar3 only. Jaguar1/2, Kestrel, the RTL8733B and the MT7612U ignore the bit, and their caps say so.DEVOURER_TX_ALT_RATE=<spec>: odd-counter QoS frames carry their own rate radiotap from this spec, and even frames keep the default. The witness separates them byrx.seqpctr parity.Measured
tests/tx_no_agg_onair.sh: one RTL8812EU transmitting, an RTL8812EU witness, ch36, A-MPDU0/6, 4 senders, 1000 B, MCS5 and MCS0 alternating by frame counter./NOAGG(×2)/NOAGG, descriptor write disabledThe counterpart: a flagged frame breaks the aggregate around it. Flagging every other frame, this harness's worst case, cut the witness's heard rate by 47 %.
The script aborts rather than passes when the unflagged control arm shows no fold, because then no mixed aggregates formed and nothing was tested.
Headless:
radiotap_noaggcovers every builder layout, with NOACK both ways, plus the/NOAGGparse. Removing the builder OR or the parse token fails it. ctest: full 76/76, without Jaguar3 76/76, Jaguar3-only 67/67.Not covered
tx_no_agg_okstays false there.🤖 Generated with Claude Code