I went down the rabbit hole on this one. Deep enough to let Claude find the firmware’s log obfuscation on the Aeonsemi AS21011 PHY, firmware 1.9.2 (XOR 0x16, should anyone ever need it).
So:
Symptom: after some link-ups the link silently eats about 900 frames per GB in one direction. After other link-ups it’s perfectly clean. Roughly a 50/50 coin flip per link-up, and every error counter on every device swears everything is fine — no FCS errors, no drops, nothing. Only TCP retransmits give it away.
Setup: BPI-R4 → SFP+ 10GBASE-T module (Broadcom BCM84891 or Aquantia AQR113C, i recon others too…) → copper → BPI-R4 Pro’s onboard 10G port (Aeonsemi AS21011 PHY, firmware 1.9.2). Kernel: frank-w’s 7.1-main.
What it turned out to be: 10GBASE-T resolves a timing master and a timing slave at every autonegotiation, and per IEEE 802.3 the choice is seeded randomly each time. When the AS21011 lands master → clean. When it lands slave → it loop-times its clock from the link partner, and firmware 1.9.2 apparently mis-clocks the internal datapath toward the SoC/switch side: constant ~1.2×10⁻⁷ corruption per bit, invisible to all counters because the frames die at the PCS before anything counts them. The copper line itself is provably fine in both roles (0 LDPC codeword failures, SNR 35 dB, PCS errored-block counter flat over ~30 GB of lossy traffic) — it’s purely the slave-role clocking inside the PHY.
Reproduce it yourself (any R4 Pro with something on the 10G copper port, phytool installed, PHY at MDIO address 0x18 for lan6 / 0x1c for wan):
# restart line autoneg (rolls the dice):
v=$(phytool read lsfp/0x18:7/0); phytool write lsfp/0x18:7/0 $(( v | 0x200 ))
# after relink, which role did you get?
phytool read lsfp/0x18:7/33 # bit 14 set (0x4xxx) = master, clear = slave
# now run iperf3 THROUGH the router (not from it) and watch Retr
For me: master = single-digit retransmits per 5 s, slave = ~2500. Twelve out of twelve link-ups matched the role, and forcing each role made it 8/8 clean vs 8/8 lossy. As deterministic as it gets.
Workaround: force the master role. One-shot:
v=$(phytool read lsfp/0x18:7/32)
phytool write lsfp/0x18:7/32 $(( (v | 0x8000) | 0x4000 )) # manual cfg = master
v=$(phytool read lsfp/0x18:7/0); phytool write lsfp/0x18:7/0 $(( v | 0x200 ))
Caveat: forcing master only works if the other end doesn’t also force master (then autoneg fails and you get no link — register 7.33 bit 15 tells you). Against normal auto partners (SFP modules, most CPEs — my ISP’s CPE accepted it fine) it’s safe.
TL;DR: if your R4 Pro’s 10G copper link is sometimes fast and sometimes mysteriously sad, and bouncing the link “fixes” it half the time — it’s not you, it’s the coin flip.
Also if you know Aeonsemi let them know to fix it. The reproduction is fully deterministic under forced roles.