Skip to content

anxwifipi: 32 posted reads (static 100M BPS) and ~1% inbound frames dropped as UnknownTypesReceived #89

Closed

Description

@tinic

anxwifipi gets only 32 posted reads, and inbound TCP on the CM4 sees ~1% frames dropped as UnknownTypesReceived.

Sizing (proven, main dfd6fb6):

  • anxwifipi reports a static info->BPS = 100000000 (third_party/wifipi/src/unit.c:1488, fork 1750732). It is not a queried rate.
  • ami_sana2_rx_ladder (src/sana2/sana2_rx.c:2566) maps bps <= 100,000,000 to AMI_SANA2_RX_DEPTH_LAN = 32 (src/sana2/sana2_internal.h:88-97). Above that rung is the ring, AMI_SANA2_RX_MAX_DEPTH = 128.
  • Live planner inputs on the A1200 CM4 (pool 4106, 3 interfaces, no IPREQUESTS) compute exactly 32 IPv4 reads for wifiN.
  • A frame that finds no queued CMD_READ is an orphan: UnknownTypesReceived++ (third_party/wifipi/src/packet.c:1832), offered to S2_READORPHAN listeners, else dropped. baddata and overruns do not count it.

Observed correlation (measured; causation NOT proven):

  • 2026-09-26, A1200 CM4, beta4 (bsdsocket 1.0.0-beta4, anxwifipi 66960e8), Emu68 0ba3a899, dtparam=ant2 (live DT: ant2 output-high), 5 GHz ch46, RSSI -65/-68.
  • IN (real iperf 2.2.1 playhouse3 -> Amiga): 17.80 Mbit/s, then 17.95 in the diagnostic run. OUT: 58.6 Mbit/s (the Pi4 figures were 35.5-35.8 IN / 58.4 OUT).
  • UnknownTypesReceived delta per IN run: +151 and +153, against ~5 at idle over the same span. Sender retransmits in the diagnostic run: 149 segs (0.92%), a ~1:1 match.
  • Sender ss: cwnd 25 = ssthresh, srtt 14.8 ms, minrtt 5.07; 25 x 1460 B / 14.8 ms = 19.7 Mbit/s.
  • pcap: advertised window median 804,768 B (about 20x BDP), so not rwnd-limited. The Amiga sent 77 dupACKs.
  • Drain bursts reach up to 10 SDIO frames at ~5 packets per read, which can exceed 32.

Unproven: that the 32-read depth causes the orphans, and that a larger read count fixes IN. The one causal trial (IPREQUESTS=64 on wifiN) was aborted: see the stall issue. Reporting a "negotiated PHY rate" in BPS needs a real rate query first. The current value is static.

Related: the S2_OFFLINE stall hazard and the S2_OFFLINE reads issue (cross-linked below).

Activity

  1. tinic commented on Sep 26, 2026

    @tinic
    OwnerAuthor

    Cross-links: #90 (the unbounded S2_OFFLINE DoIO stall hazard, which aborted the IPREQUESTS=64 causal trial) and #91 (S2_OFFLINE does not return queued CMD_READs).

  2. tinic commented on Sep 27, 2026

    @tinic
    OwnerAuthor

    Focused CM4 hardware A/B (2026-09-27). Same A1200 beta4, anxwifipi, external ant2, playhouse3 sender, real iperf2, one 10-second inbound arm each. Stock config (computed 32 IPv4 reads): 19.68 Mbit/s; UnknownTypesReceived +243 over +18,154 received packets. IPREQUESTS=64 after an A1200-only warm reboot: 35.09 Mbit/s; UnknownTypesReceived +177 over +32,077 received packets. Same peer, port and duration; no FORCE removal or broad matrix. The 64-read setting improved throughput about 78% and lowered the orphan fraction, but did not eliminate unmatched reads. RSSI was not sampled during both arms and the reboot is a possible confound. The original interface file was restored byte-for-byte (MD5 0db6fbe2239524632a660565bd3ea5ce), followed by a second warm reboot; wifipi is back online with the default config. Leave this issue open while residual drops are understood; 64 reads is supported as a mitigation, not a complete fix.

  3. tinic commented on Sep 27, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-27: read depth, counters arm, and what is still unlocalized. Issue stays OPEN.

    Setup, the same for every arm below. A1200 CM4, beta4 stack, dtparam=ant2 external antenna, RhodeIsland5 5 GHz ch 46. Real iperf2 from playhouse3, one 10 s inbound arm each.

    IPv4 read depth.

    reads IN Mbit/s UnknownTypes per MB
    32 (computed default) 17.8-19.7 +151 to +243 ~7
    64 (IPREQUESTS) 35.1 +177 / 32,077 pkts —
    128 (IPREQUESTS) 59.0 +82 / 53,483 pkts 1.1
    • 256 is not reachable: IPREQUESTS is clamped at AMI_SANA2_RX_MAX_DEPTH = 128.
    • OUT is 58.6 Mbit/s.
    • UnknownTypesReceived is a no-queued-read orphan counter (packet.c:1797-1832), not a radio error counter. It is reported independently of sender retransmits; the two are not subtracted.

    Counters arm (128 reads). Artifact: WiFiPi zz9k/89-rx-counters-beta4 @ 39e2e2c, which is the shipped 97ea7faa plus receive counters only. anxwifipi.device sha256 ad0ecbb8f27f8ecf06cc4a3436acd77c3de1b272fb4a96b80d981a4e8d7dd4f7, built in the v1.0.0-beta4 tree. That tree reproduces the shipped driver byte-identical (sha256 947c2081…dca4). The artifact was loaded from RAM: only and restored by warm reboot, with the on-disk hashes re-verified.

    • Result: 73.9 MB / 10.30 s = 60.2 Mbit/s, lost 0.
    • Receive path, over 8,692 SDPCM frames and +53,328 SANA packets:
      • rx CMD53 failures, all phases: 0
      • repeated headers (stale-buffer replay): 0
      • garbage headers: 0
      • glom subframe errors: 0
      • rx sequence mismatches, all bins including behind-by-1: 0
      • mailbox NAK / firmware halt / flow control: 0
      • flow-control mask changes: 0
      • longest drain: 43 frames
    • For this arm only, that rules out rx CMD53 failures, stale-header replay and SDPCM sequence gaps. It does not rule them out in general.
    • UnknownTypes +235 (0.44%); sender retransmits 443.

    TX and the unlocalized gap.

    • netstat -s: ip sent +1,507 = wifipi +1,305, eth0 +203, genet +1.
      • dropped on send 0; transmit errors 0 on every interface.
      • UDP and ICMP sent +0.
    • WiFiPi frames sent +1,306. This counter increments when the receiver dequeues the write (packet.c:1177), before the void SendPKT. It means dequeued/marked sent, not confirmed on the air.
    • sdio_sendpkt ignores CMD53 failure, and SendGlomDataPacket replies success unconditionally. So a TX CMD53 failure is invisible to every current counter.
    • playhouse3 (ens18, 0 kernel drops) captured 801 frames from .137 plus 1 ARP. The sender's ss shows segs_in 791 at its last sample.
    • Gap: about 500 fewer frames were observed at playhouse3 than the Amiga dequeued and marked sent. The stage is unknown: it could be the chip, firmware, air, AP or bridge. RF loss is not claimed.
    • Only pre-allocation ACK failures in the stack are unmeasured. Post-bookkeeping IP drops were 0.

    Next. A counters-only design, no hardware arm yet:

    • TX CMD53 fail/phase in sdio_sendpkt
    • glom versus single TX
    • firmware counters (txfail / txretry / txnoack) and bus:txglom before/after
    • orphan split by EtherType (IPv4 / ARP / IPv6 / other) and unicast/multicast

    Related.

    Evidence: ~/anxd-evidence/89-cnt-b4 (pcap md5 8a9d21f4…) and ~/anxd-evidence/89-ipr128.

  4. tinic commented on Sep 27, 2026

    @tinic
    OwnerAuthor

    The 2026-09-27 counters-only run on the A1200 (wifipi 7a4a7f2) stopped at the first firmware counter read and returned no measurement. A probable cause of the missing reply was found in source afterwards. It is not proven, and it is not a proven root cause of the #89 throughput gap.

    What was sent:

    • FwCountersSnapshot called PacketGetVar("counters", buf, 2048).
    • PacketGetVar sets c_Length = 2048 and transmits the full request buffer, so about 2,076 bytes of SDPCM + BCDC went to the firmware.

    What Linux does: Linux brcmfmac caps host→firmware BCDC ioctl input at BRCMF_TX_IOCTL_MAX_MSG_SIZE = ETH_FRAME_LEN + ETH_FCS_LEN (1,518 bytes). The constant is in core.h, lines 34-37. bcdc.c (lines 100-127) sends at most that many bytes of cmd+data, and keeps the requested output length separately.

    What WiFiPi has sent before (shipped 97ea7faa):

    • The largest control frame in normal use is the CLM upload: PacketSetVar("clmload", UploadHeader + MAX_CHUNK_LEN 1400) at packet.c:2709 and :2763, about 1.45 KB with headers.
    • The largest GET is "ver" at 128 bytes (unit.c:1575).

    So the counters read was the first control frame above the Linux cap that this firmware received from WiFiPi.

    Consequence: WiFiPi's wait for the reply had no deadline and held wu_Lock (#93), so the stack's reads queued behind it and Wi-Fi stopped until the rollback.

    Next steps, emulator only; the oversized run is not to be repeated:

    • Separate the transmitted input length (capped at 1,518) from the requested output length, as bcdc.c does.
    • Test a minimal bounded GetVar that sends only the name and requests 2,048 bytes of output, in the emulator, before any hardware run.
  5. tinic commented on Sep 27, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-27 07:43–07:46Z: one RAM-only arm with the no-firmware counters build. The issue stays OPEN.

    Setup

    • Build: WiFiPi 38aa181 (device sha256 6eaeb3b8…).
    • Same A1200 CM4 beta4 / ant2 / RhodeIsland5 setup, IPREQUESTS 128.
    • One 10 s inbound iperf2 run from playhouse3: 59.6 Mbit/s, ss retrans 0/314.
    • Counters were snapshotted outside the transfer. Rolled back to stock and verified afterwards.

    Driver deltas across the transfer

    counter delta
    data frames handed to CMD53 +1293 (= NetDevStats packets sent)
    tx CMD53 failed (block / remainder) 0 (0 / 0)
    sends split block+remainder +10
    wake-ups stalled on TX credit 0
    data gloms over 0x40 credit / control without credit 0 / 0
    TX gloms 1 / 2-3 / 4-7 / 8-15 +271 / +440 / +20 / +3
    rx frames +8604
    rx CMD53 failed, garbage, repeat, glom-subframe errors 0
    orphans IPv4 / ARP / IPv6 / EAPOL / other +130 / 0 / 0 / 0 / 0
    firmware records unavailable by design in this build

    Wire (playhouse3 tcpdump, 0 kernel drops)

    • Frames from the Amiga MAC: 786 (785 TCP ACKs plus 1 ARP).
    • Frames to the Amiga: 13462.

    Reading

    • Of the 1293 frames the driver handed over, 507 were not seen on the wire. Every one of the 1293 CMD53 writes completed without error.
    • TX CMD53 failure and over-credit gloms are therefore excluded as the cause.
    • This does not prove 507 frames were lost:
      • A successful CMD53 proves neither firmware acceptance nor RF delivery.
      • The capture filter was host 192.168.1.137, so any IPv6 traffic from the Amiga would not appear. 507 such frames in 10 s is implausible, but it is not excluded.

    Next

    • Localizing further needs the firmware tx counters (txfail / txnobuf / txerror). That means a bounded counters GET.
    • WiFiPi currently transmits the full ~2064-byte BCDC request for a 2048-byte GET. Linux bcdc.c caps the transmitted header+data at 1518 (BRCMF_TX_IOCTL_MAX_MSG_SIZE) and still advertises the full length.
    • That cap is being implemented on a separate branch. It is a plausible cause of the earlier hung diagnostic, not a proven throughput root cause.

    Evidence: ~/anxd-evidence/89-nofw-arm (s2–s7 logs, in5.pcap/ss/iperf, wstat_delta.txt).

  6. tinic commented on Sep 27, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-27 09:05Z. The issue stays OPEN: about 8% loss remains, and the beta7 gitlink has not been bumped yet.

    Merged into WiFiPi maint/beta4

    A1200 A/B tests. RAM-only, codex GO for each, rolled back to stock afterwards. Metric: IPv4 IDs from .137 that never appear on the wire.

    run WiFiPi Mbit/s IN missing IDs
    08:21 A stock 97ea7faa 58.5 37.2%
    08:22 B stock + chain pad 62.9 8.5%
    08:44 A stock + chain pad 61.0 7.6%
    08:45 B2 + single-frame Linux header 59.4 9.7%
    • The chain pad removes about 78% of the loss.
    • The single-frame header change had no effect, so it is parked.
    • The remaining ~8% happens after a successful CMD53: in the firmware, on the air, or at the AP. Missing IDs are a proxy, not proof of ACK loss.
    • Next: read the firmware tx counters (txfail/txnobuf/txnoack) with the now-capped counters GET, under its own GO.

    Evidence: ~/anxd-evidence/89-ab, ~/anxd-evidence/89-ab2.

  7. tinic commented on Sep 27, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-27 14:22Z. Correction: the IPv4-ID gap metric does not measure Wi-Fi loss. The issue stays OPEN.

    AmiNetXDuo has one NX_IP (src/netstack/netstack.c), and AMINETXDUO_IP_ID_RANDOMIZATION defaults off, so one IPv4 ID counter is shared by every interface. IDs spent on eth0 (.219) and genet (.158) during a run show up as holes in a Wi-Fi-MAC-only capture.

    figure status
    37.2% -> 8.5% missing IDs (glom chain-pad A/B) upper bounds on Wi-Fi loss, confounded by other-interface traffic
    arm F 13:15Z: 113 of 1328 IDs missing (8.5%) upper bound; the capture filtered the Wi-Fi MAC only, so it cannot be re-derived
    throughput A/B (the chain-pad fix) still a measurement
    arm F counters: driver frames 1312, firmware txframe 1216 aggregate only; different populations and windows, no attribution

    No attribution or release claim rests on ID gaps.

    Next: a per-frame trace in a diagnostic build only.

    • Record points:
      • A: requests accepted by this driver, with their IPv4 key.
      • B: frames submitted over SDIO, with glom position and credit.
      • G: the SDIO completion of each write.
    • Capture: all three Amiga MACs, with 0 kernel drops.
    • Classes: only B-submitted keys can count as Wi-Fi loss. They are split into driver drop, SDIO-reported failure, and post-SDIO. Post-SDIO covers the chip, air and AP, and cannot be split per frame.
    • Status: the design is reviewed (deepseek-v4, claudecode, codex). Emulator validation comes before any hardware arm.
  8. tinic commented on Sep 27, 2026

    @tinic
    OwnerAuthor

    Correction (2026-09-27): the IPv4-ID gap figures are upper bounds, not measured Wi-Fi loss.

    AmiNetXDuo has one NX_IP (src/netstack/netstack.c), so a single nx_ip_packet_id is shared by every interface, and AMINETXDUO_IP_ID_RANDOMIZATION is off by default. IDs spent on eth0 and genet, including replies to HTTP polls and a web shell session during the runs, appear as holes in a Wi-Fi-only capture.

    Figure Status
    37.2% -> 8.5% missing IDs (A/B, glom pad) Upper bounds, confounded by eth0/genet traffic
    113 of 1,328 missing IDs (firmware-counter run) Upper bound; other-interface IDs were not captured, so it cannot be corrected
    Inbound throughput 58.5 -> 62.9 Mbit/s Measured; unaffected
    Driver sent 1,312 vs firmware txframe 1,216 Aggregate discrepancy only; different frame populations and windows, not a loss location

    No attribution or release claim rests on ID gaps. The next step is the per-frame trace (design v1.5): per-frame keys at driver accept and SDIO submission, a capture of all three interfaces, and loss counted only for frames submitted to Wi-Fi.

  9. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-28 — #89 stays OPEN. This supersedes the beta4-only status in the issue description and the earlier IPv4-ID interpretation.

    Inbound/read depth. #107 landed on main at 95e3983a: WiFiPi interfaces now ask for 128 posted IPv4 reads when IPREQUESTS is absent; explicit values and the pool cap still apply. The original 32-read state is historical. Focused A1200 arms with explicit 128 reads reached about 59–60 Mbit/s versus about 18–20 Mbit/s with the old 32-read default, with fewer inbound orphans. The generated-NI/default-selection path passed emulator tests. Final beta7 archive hardware validation is still pending.

    Separate outbound discrepancy. In a qualified RAM-only trace on the beta4 stack plus reviewed WiFiPi maintenance driver, 3,193 host-submitted IPv4 frames were joined to peer capture: 2,969 matched and 224 were absent after successful host CMD53 completion; none were classified as lost before CMD53. No bad TCP checksums, reported TX CMD53 failures, ring drops, or capture drops in that arm. CMD53 success does not prove firmware transmission or RF delivery. Firmware TX counters and peer capture totals are unmatched aggregates, so this does not distinguish firmware, air, AP/bridge, or capture. This is not a beta6-stack loss rate. IPv4-ID holes in older WiFi-only pcaps are only confounded upper bounds because the stack shares one ID counter across WiFi, eth0, and genet.

    Content and timing of absent frames. Many are pure TCP ACKs later superseded by newer ACKs. A harmful subset is a pair of flight-final ACKs absent at the peer; the sender sends one new, sequence-contiguous 1,460-byte probe about 53 ms later, and a delayed ACK on our side makes roughly 0.15–0.24 s gaps. The beta6 stack has a 50,176-byte ACK threshold and GRO of up to 16 frames. Host-side trace analysis finds a roughly 67 KB median positive ACK advance, making those flight-final ACKs sparse. This is a plausible stack-side amplification of downstream ACK disappearance, not proof the stack caused the disappearance or that the radio is defective. AmiTCP_NG 4.1.7 exhibited a different ACK/traffic pattern during a beta6 comparison, but the runs are not equivalent enough for a root-cause claim.

    Next discriminator. A beta6-only 8-MSS ACK-ceiling variant (11,680 bytes; GRO maximum unchanged) is under offline build/rehearsal. Measure actual ACK cadence and the harmful gap class before any merge or release claim. No hardware result from it yet. WiFiPi multi-frame F2 chain padding remains a measured throughput improvement (58.5 -> 62.9 Mbit/s in a focused A/B), not a validated loss percentage. Beta6 is public and unchanged; beta7 is unreleased and still gated on residual #89 and final archive verification.

  10. 8 remaining items

  11. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-28 06:43Z — hw28, GRO 16 vs GRO 8 on frozen main 7fd931de; #89 remains OPEN.

    One 5 GHz leg per arm, 240 s inbound, TCPACKMAX=11680 + TCPGROWRTT=2, same interface file. The two libraries differ in one functional immediate: the GRO run cap, cmpiw #15 → #7 at text 0x21771 (sana2_rx.c:1417); the other 6 differing bytes are the version tag.

    GRO 16 (ad50a25c) GRO 8 (6f024baf)
    Throughput 51.3 Mbit/s 52.0 Mbit/s
    Median advancing-ACK advance 23,360 B 21,900 B
    Hole repairs 432 / 1.448 MB 481 / 1.588 MB
    Gaps > 150 ms 0 0
    • The predeclared criterion (median advance ≤ ~11,680 B) failed, and the repair difference is inside run-to-run variation. GRO 8 is not merged.
    • The Amiga's wstat out counter counts every submitted Ethernet frame, while the peer figure counts ACKs of the test flow only. The two cannot be subtracted, so no ACK-loss rate is inferred from them.
    • Stock rollback on the A1200 passed after both legs.
    • The residual hole-repair class with a grown window remains unattributed.
  12. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Debug ring-trace review package (#89, 2.4 GHz ACK-less stalls). Diagnostic only; not for merge or release.

    Source. WiFiPi.device branch debug/89-ringtrace, head b10df171dd6670fc820d048bc802d8522cbe40d8, based on the pinned maint commit c0782c2: tinic/WiFiPi.device@maint/beta4...debug/89-ringtrace

    • 1d78eb2: all the driver code, behind #ifdef WIFIPI_RINGTRACE, which is off by default.
    • 1190db7 and b10df17: tests and tools/ringtrace.py only.

    Build. AmiNetXDuo 7fd931d, preset default, pinned toolchain 3869b4427396 (GCC 16.2.0b).

    Artifact sha256 Size
    Flag off 9112bc1fabee8e91aa8e5c13200234ae7af8bac6a426131760845d10621c5d3f 55,628 B
    Flag on (-DWIFIPI_RINGTRACE) 8dbabbdc6f1cf7bf22bbfb1749501cdaf0614d15c2354791ce38966467119e2c 58,156 B
    ringdump c9c67965a03473775d0ca09565523ced4b33bb02b507613087fcc99cc722d7c0 3,232 B
    • The flag-off build is byte-identical to the beta7 release driver.
    • The flag-on $VER is anxwifipi.device 1.0.0-beta7 (27.9.2026) AmiNetXDuo 7fd931d-dirty any.

    Overhead (flag on, against the base):

    • Code: text +2,644 B. No new data or bss.
    • Static RAM: +4 B (s_Ring in struct SDIO).
    • Ring: 2^22 records × 16 B, allocated once at receiver start. It halves on AllocMem failure down to 4,096 records.
    • Stack deltas per frame: receiver +60, poller +28, SendGlomDataPacket +24, CtrlTransact +28 (caller's task). The receiver stack is 64 KB and the poller's 8 KB.

    Records (16 B, CLO 1 MHz timestamp):

    • every SDIO header read, including empty looks, with its glom frame count and bytes;
    • every receiver wake, with reasons and credit;
    • tick scheduled delay against actual wake;
    • poller hit, wake and sleep;
    • per-wake RX queue: posted reads, delivered frames, orphans;
    • each TX glom, with count, credit and TXSeq/MaxTXSeq;
    • TX credit: the initial state and every zero/non-zero change;
    • every firmware event frame;
    • S2_GETNETWORKS, escan and scan-done;
    • every synchronous control transaction's entry, send, reply and exit;
    • alignment pings.

    Loss semantics.

    • The ring overwrites its oldest records. The dump header carries the total written, the first sequence number, the count, lost and the capacity.
    • All writers run in tasks under Forbid, and the dump copies under Forbid, so records are never torn. The host test detects tearing when the lock is removed.
    • Read-out is private device command 0xF089, via the ringdump tool. It writes only the used records: 32 + 16 × count bytes, at most 64 MiB.

    Clock alignment. Five pings at leg start and five at leg end are seen at both ends.

    • Per ping: θ = ((A2 − T1) + (A3 − T4)) / 2 and δ = (T4 − T1) − (A3 − A2).
    • The offset and drift come from the tightest ping at each end.
    • The error bound is max(δ) / 2, measured on each run.
    • CLO wrap (about every 71.6 min) is unwrapped in write order.

    Host test. tests/host_ringtrace.c: 31/31 pass on macOS clang and on Linux gcc 14. It covers layout, wrap, multi-lap overwrite, short dumps, a dump during concurrent writes, and sequence numbers near 2^32.

    Coverage rule. A candidate cause is refuted only when lost=0, or when the first dumped record comes before the start pings.

    Run identities.

    Identity
    Slot library bsdsocket-7fd-b7grw-8a0f624c.library (8a0f624cc60342ad805018a46e78420be46ec994caabddbc262f957f32984d9f, TOKEN b7grw)
    NI a69505f0…: grow2 with DEVICE=RAM:anxwifipi.device
    Stock rollback (P0/rb from hw27) lib 9b7e56f6…, driver 773f5ad1…, ANI b56154cd…, NI 2cb939fc…, User-Startup 5dc5e2d7…, ENVARC prefs 5e9636cb…
    Runner ackab-115.sh 34cbfaa6…
    Wrapper ring24-v2 d5156525… (zz9k: NO BLOCKER)
    Leg script ring1-v4 cc50a098…

    Leg. One leg on 2.4 GHz channel 6, DUR=240.

  13. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-28 10:05Z: hw30, 2.4 GHz ring-trace leg (correction); #89 remains OPEN.

    hw30 ran one 240 s inbound leg on 2.4 GHz channel 6 with TCPACKMAX=11680 and TCPGROWRTT=2.

    Item Value
    Debug driver 8dbabbdc… (WiFiPi debug/89-ringtrace 1d78eb2)
    Slot library 8a0f624c…
    Result 33.7 Mbit/s, 8 data gaps over 150 ms
    Ring capacity 4194304, 625862 records, lost=0
    Clock alignment 10 pings paired, bound ±6.466 ms, drift −1.4 ppm, 0 causality violations

    The alignment is sound: 99.4 % of the 43094 Amiga frames at the peer have a ring TX record 0–20 ms before them (p50 2.3 ms).

    Correction. The first per-gap reading was off by 4.127 s: gap times were taken from the first pcap packet, not the first data frame. Every in-gap TX and RX claim based on those windows is retracted.

    Corrected windows, the four gaps in which the peer saw no Amiga frame:

    Gap start (epoch) Length RX frames in ring READ gloms: start edge / interior IP-ID advance across the gap
    1790587601.789 188.9 ms 12 / 0 0
    1790587661.719 211.2 ms 18 / 15 0
    1790587690.902 156.1 ms 0 / 17 0
    1790587721.682 152.5 ms 54 / 32 0

    The start edge is the first 6.466 ms of each window. Inside these gaps the peer sent no data except the one exit frame.

    • The ring records no scan, control transaction or firmware event inside these gaps.
    • TX credit never reached zero.
    • The driver woke at least every 10.4 ms throughout.
    • The ring records carry no packet identity, so neither a host ACK hold nor an AP, air or chip RX hold is established.

    Next (source only): a per-frame RX identity record at the host receive-to-stack handoff, used with the existing per-frame TX identity record to follow each packet end to end. No hardware run is authorised yet.

    Evidence on playhouse2:

    • ~/anxd-evidence/89-trace/hw29-ring24/G/ (ring dump, pcap, run.log)
    • ~/claudecode-hw30-analysis/ (marks.tsv, align.txt, win2-*.txt)
  14. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    hw31: one 2.4 GHz leg (2437 MHz), RX/TX identity ring trace, at 7fd931d + debug driver a3c995a (RAM only). LEG_VALID, ring lost=0, clock bound ±3.310 ms.

    gap direction edge
    1 data unavailable (no host ACK arrived at the peer in the gap)
    2 data unavailable (trigger read ambiguous: a retransmitted copy)
    3 data unavailable (no host ACK arrived at the peer in the gap)
    4 ACK read_delay 337.002 ±3.310 ms, ack_production 0.938 ±0.001 ms
    5 ACK read_delay 348.447 ±3.310 ms, ack_production 1.067 ±0.001 ms

    Gaps 1+4 and 3+5 are the same two stall events. In both, the driver polled the chip at least every 10.4 ms and got nothing (64 and 34 empty reads). There was no scan, no credit starvation and no late tick, and the held frames reached the SDIO read together.

    Reading: in the two attributable stalls, the delay is before the host's SDIO read of the frame (air, AP or chip firmware). It is not host ACK production. This leg cannot separate those three. Three of the five gaps have no attributable edge. No root cause is claimed.

    Next: source-only debug firmware RX-counter snapshot (wl_cnt v10) before/after a leg. No hardware until reviewed.

    Evidence: playhouse2 ~/anxd-evidence/89-trace/hw31-ring24/G. Repro: python3 tools/ringtrace.py rxjoin T-ring.bin tr_T.pcap START END --times tr_T.times (WiFiPi.device 5579af5), with START/END from T-gaps.txt.

  15. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    hw32: one 2.4 GHz leg (2437 MHz), 180 s, 7fd931d + RAM debug driver f3998bff (ring trace + firmware counters snapshots, taken before and after the leg only). LEG_VALID, ring lost=0, clock bound ±4.636 ms, runtime driver proof ok. 27.3 Mbit/s.

    Release-ACK edges (10 gaps; data 2-5 and ACK 7-10 are the same four events)

    gaps read_delay (peer TX → host read) ack_production (host read → host ACK TX) larger
    2 / 7 154.712 ±4.636 ms 1.161 ms upstream_delivery
    3 / 8 272.696 ±4.636 ms 1.961 ms upstream_delivery
    4 / 9 133.982 ±4.636 ms 0.721 ms upstream_delivery
    10 88.176 ±4.636 ms 1.806 ms upstream_delivery
    6 2.411 ±4.636 ms 131.227 ms host_ack_production
    1, 5 unavailable
    • Gap 1 had 35 non-advancing ACKs and no advancing one. Gap 5 had no host ACK inside it; its ACK half is gap 10.
    • Gap 6 is about 5.4 s into the leg, during ramp-up and settling, and is a single case (n=1). The 131 ms falls between the driver's handoff and the ACK reaching the driver's TX path.

    Host TX during gaps 2 and 4

    • The host's ACKs written during the gap were held too. Every one the peer saw arrived at the gap END, in one burst: seen delays run 162→7 ms (gap 2) and 165→22 ms (gap 4).
    • The unseen ones (15 of 26 and 13 of 20) are pure ACKs with write=ok. Leg-wide, 3831 of 31863 host frames were unseen at the peer (20.6/s, all pure ACKs), so in-gap unseen density is about 4x that rate.
    • Unseen does not locate the loss beyond "after the SDIO write". A superseded ACK dropped inside that burst would look the same.

    Firmware counters (leg-wide only; wl_cnt v10/848; 188.0 s; rxframe +423775)

    • rxnobuf +19058 (rxerror = rxnobuf), rxtoolate +17548, rxf0ovfl +2, rxf2ovfl +9 (labelled obsolete).
    • Zero: rxoflo, DMA, PMQ, reset, reinit.
    • Ambient: rxcrc = rxbadfcs +54798.
    • The header defines neither whether these count all RX or only frames to us, nor how they overlap. No baseline exists for any band. None of these become a loss percentage or a per-gap attribution.

    Causality limits

    • In the attributable stalls, both directions were held and released together at the gap end, before the host's SDIO read (RX) and after its SDIO write (TX): air, AP or chip firmware. This leg cannot separate those three.
    • Host ACK production is not the stall in 4 of the 5 attributable events. The exception is the single startup gap 6.
    • No root cause is claimed.

    Evidence: playhouse2 ~/anxd-evidence/89-trace/hw32-ring24/G. Repro: python3 tools/ringtrace.py rxjoin|txjoin T-ring.bin tr_T.pcap START END --times tr_T.times (WiFiPi.device 5579af5), with START/END from T-gaps.txt; python3 tools/wlcnt.py delta T-wlcnt-PRE.bin T-wlcnt-POST.bin (bdf1e2d3).

  16. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Correction to the hw32 comment above: the in-gap unseen ACKs are not excess loss. In gaps 2 and 4, all of them (15/15 and 13/13) are superseded by a later ACK on the same flow with a higher ack that the peer did see. The seen ACKs reached the peer in one burst at the gap end: 11 within 2.9 ms, and 7 within 0.1 ms. This is the benign superseded-ACK thinning class, not 28 harmful losses. Where they were dropped is still unknown. The rest of the comment stands.

  17. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    hw33: one 2.4 GHz T leg (2437 MHz), 180 s, 7fd931d + RAM debug driver d3d2ccfe (WiFiPi.device debug/89-wlsample 0b585b68).

    • Instrumentation: ring trace, pre/post firmware counters, and an in-leg 50 ms counters sampler.
    • Validity: LEG_VALID; ring lost=0; clock bound ±5.908 ms; runtime proof 0xF089/0xF08A/0xF08B answered.
    • Throughput: 26.5 Mbit/s, 3 data gaps >150 ms (201.0 / 198.7 / 178.3 ms). The earlier references are hw31 29.3 and hw32 27.3, so the effect of the sampler on throughput is unknown.

    Sampler: 3502 samples, 0 lost, 0 late, 0 skipped during traffic. Cadence mean 53.6 ms, max 73.7 ms. 32.8 KB/s over SDIO. Every hold had 2-4 eligible windows, i.e. windows lying wholly inside the hold with valid endpoints.

    Inside the holds (7 gaps: 3 data plus 4 ACK-direction, overlapping; 20 eligible windows)

    Counter Reading
    txframe, txretrans, txnoack 0 in every in-hold window; only the release window of gap 6 has txframe=2
    rxbeaconmbss equal to tbtt in every window, about 1 per 70 ms, the same rate as outside holds
    rxframe 0, except the first windows of data gap 1 (103, 48) and the release windows
    rxnobuf 0 in every in-hold window
    rxcrsglitch 25-67 per ~60-70 ms window, against a leg average of 22424 / 191 s ≈ 117/s

    Ring cross-check (data gap 1, 201 ms): inside the window the host made 191 RX reads and wrote 18 ACKs to the chip (write=ok, which means SDIO transfer only). Meanwhile the sampled windows show no chip TX attempt. 12 of the 18 were later superseded.

    Edges: gap 4: read_delay 104.8 vs ack_production 0.7 ms; gap 6: 360.8 vs 1.5 ms (both ±5.9 ms, upstream_delivery). Gap 5: 150.7 vs 162.9 ms, a single frame within about 2× the bound, so unresolved. Gaps 1-3 and 7 have no attributable edge.

    Limits

    • Sampler windows do not prove a continuous zero across the unsampled intervals between them.
    • The readings are descriptive associations only.
    • CCA/air, AP, and an internal TX block in the chip all remain unresolved.
    • No root cause is claimed, and no btc_mode claim is made.
    • The rollback completed: stock hashes, RAM empty, all doors up.

    Evidence: playhouse2 ~/anxd-evidence/89-trace/hw33-ring24/G (ring1.out has the full wlsample.py samples output). Repro:

    PYTHONPATH=wlsample-lib-5579af5 python3 wlsample-0b585b6.py samples T-ring.bin T-marks.tsv T-gaps.txt
    
  18. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-28 15:25Z: hw34, a btc_mode bracket at 2.4 GHz. #89 remains OPEN.

    • Setup: one run in one test boot, three 120 s T legs B1 / Z / B2, at 7fd931d with RAM debug driver d7f67cff (WiFiPi.device debug/89-btc 792bc57a).
    • Only change between legs: btc_mode 1 → 0 → 1, set at runtime.
    • Instrumentation (as hw33): ring trace, pre/post firmware counters, 50 ms in-leg counter sampler.

    Validity

    • LEG_VALID: ring lost=0 (2 696 862 records); runtime proof 0xF089/0xF08A/0xF08B/0xF08D.
    • Sampler: 7523 valid samples, 0 lost, 0 late.
    • btc_mode readbacks:
      • ORIG = 1;
      • SET 0, read back 0, before Z;
      • SET 1, read back 1, before B2;
      • final 1.
    • All 14 ops returned rc=0, and the ring records match the tool.
    • btc_flags=0 and btc_dos_status=1 before and after every leg.
    • Gaps: 38 raw, of which 4 between-leg idle gaps were excluded, leaving 34 in-leg.
    • RING24_P0_PASS: stock restored.
    Leg btc_mode Data holds >150 ms Mbit/s Sampled in-hold windows with txframe flat
    B1 1 4 26.2 8 of 9
    Z 0 2 (180.0, 184.8 ms) 24.8 4 of 5
    B2 1 9 24.2 20 of 24

    Reading. The rule was declared before the run, drift first: |B1 − B2| = 5 ≥ 3, so the result is INCONCLUSIVE, whatever Z shows. With n this small, the drift between the two btc_mode=1 legs exceeds any difference Z could show. The GET readback proves the iovar value; live application is unproven. Counters are sampled only; a flat sampled window is not a continuous zero. No causal or coexistence claim is made.

    Evidence: playhouse2 ~/anxd-evidence/89-trace/hw34-btc-bracket/G (ring1.out, T-btc-ops.txt, T-btc-ring.seq, T-btc-reads.txt).

  19. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-28 16:05Z: hw35, a single 2.4 GHz leg. #89 remains OPEN.

    • Setup: one 180 s T leg (2437 MHz), 7fd931d, RAM debug driver 258a4a9d (WiFiPi.device debug/89-btc bfbe2ec0). Decoded with wlsample.py 6ae38baa (bafbdfa2).
    • Instrumentation: the sampler now reads 22 firmware counters every ~54 ms.
    • btc_mode: untouched.

    Validity:

    • LEG_VALID; ring lost=0 (1 338 146 records); runtime proof 0xF089/0xF08A/0xF08B.
    • 3520 valid samples, 0 lost or late.
    • 23.8 Mbit/s, 13 data holds >150 ms.
    • Stock rollback verified (ROLLBACK_P0_PASS, RING24_P0_PASS).
    • The decode was reproduced independently by a second reviewer.

    RTS in the holds. Counter semantics come from WHD whd_wlioctl.h:2061-2062: txrts = dot11RTSSuccessCount, txnocts = dot11RTSFailureCount. So RTS attempts = txrts + txnocts. Attempts count retries, not distinct frames.

    • Controls: duration-matched out-of-hold windows in the same leg, about 3300 per hold. 97.5-98.7% of them show attempts. Median about 147 attempts/s, of which about 110/s are answered.
    • Expected = control median rate × sampled in-hold time (not the gap length).
    Data hold Sampled in-hold ms RTS attempts Expected at control rate Answered Unanswered
    g0 105.6 2 15.8 0 2
    g2 176.0 6 25.9 0 6
    g4 109.5 6 16.1 1 5
    g6 112.6 26 16.6 16 10 (38.5 %)
    g8 110.8 15 16.3 1 14
    g12 174.7 20 25.7 0 20
    g1, g3, g5, g7, g9, g10, g11 105-200 each 0 ~15-30 each - -
    • 6 of the 13 data holds show sampled RTS attempts. Four of them (g0, g2, g4, g12) are below the control-rate expectation, and two (g6, g8) are at or above it.
    • 7 of the 13 show no attempt in the sampled windows. That does not establish zero attempts throughout the hold.
    • Beacons from other BSSs continue to be counted in every hold, so the chip is still receiving on the channel.

    Limits: descriptive association only. An unanswered RTS means no CTS arrived in time; it is not frame loss and not an attribution to the AP. There is no AP, firmware or CCA attribution and no fix claim. Internal hold versus CCA deferral remains unresolved.

    Evidence: playhouse2 ~/anxd-evidence/89-trace/hw35-wide-leg/G. The full re-decode is ~/anxd-89-wlcnt/hw35-wlsample-bafbdfa.txt. Repro:

    PYTHONPATH=<ringtrace lib> python3 wlsample.py samples T-ring.bin T-marks.tsv T-gaps.txt
    
  20. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Update 2026-09-28 17:02Z — #89 remains OPEN. hw35 is the latest hardware evidence; its sampled RTS counters do not distinguish DUT-side CCA/backoff, chip-internal TX hold, or AP/air behavior. The next discriminator is a passive channel-6 802.11 capture, but no non-disruptive monitor radio is currently available: the lab hosts have no radio; playhouse2 is an LXC container (a USB radio must attach to its Proxmox host); this Mac’s en0 is the live uplink and has no active wired alternative. No further diagnostic hardware leg is scheduled until a capture path is demonstrated. A future capture must first show target BSSID/STA and adequate out-of-hold coverage; seeing a frame proves it aired, but not seeing one, or seeing apparently idle air, cannot alone prove chip suppression or rule out DUT CCA. No root cause, fix, merge, or release claim follows from this equipment blocker. Beta7 remains unpublished.

  21. tinic commented on Sep 28, 2026

    @tinic
    OwnerAuthor

    Reviewed #89 disposition on frozen main 7fd931d (2026-09-28): the original 32-posted-read WiFiPi condition is addressed by merged 95e3983. In that code, an absent IPREQUESTS selects 128 for anxwifipi.device/wifipi.device, while explicit settings and the pool budget still apply. The hw35 NI readback (a69505f0) has no IPREQUESTS override. I independently decoded hw35 T-ring.bin (SHA-256 b8dad38dc28fc8b98ca36373b07d6fb6277b7dd01eeb9b44af4095d4d19932e0): 36,300 RT_RXQ records, 36,200 with two openers; total posted reads p50=130, p90=138, max=139. This supports runtime operation around the new default, without another boot. RT_RXQ counts all openers and packet types, so it is not a direct IPv4-only count.

    The remaining 2.4 GHz >150 ms holds are real but separate from the original 32-read state. Delay is predominantly upstream of host read/ACK production in attributable hw31-35 events, not universally: hw32 startup gap 6 had 131 ms of host ACK production, and hw33 gap 5 was unresolved with read/ACK delays close together. The traces do not distinguish DUT CCA/backoff, chip-internal hold, or AP/air behavior, and do not prove a new NetX defect or a firmware/RF cause. GRO8 and selective ACK-glom drafts did not meet their criteria and remain unmerged. I classify this as a documented open residual follow-up, not a supported beta7 code-fix blocker; passive 802.11 capture is deferred until a non-disruptive monitor path exists. This is a release disposition, not a root-cause or fix claim. Beta7 remains unpublished pending the exact-final archive and WirelessManager gate review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions