Add flow-control to radio.conf #134
|
@jnilo1 while working radio firmware, I realized that the currently
|
Replies: 30 comments 1 reply
|
Thanks @hlyi — you put your finger on a real design smell, and I've implemented the split rather than just answering it, so it's already live on The conflation you spottedThe DT What shipped (bridge driver v1.5)Two layers, mirroring the
So on the G4 you no longer encode flow control in the DTB at all: the board says "I don't wire RTS/CTS" once, and you pick the firmware mode at runtime (or just leave it — the default is already The old DT One consequence in
|
|
@jnilo1 It is great that you made more improvements 👍 I tested v4.0.0-pre branch on G4, it worked as expected so far. One question: when configured with sw flow control, I don't see |
|
Also, do you know if otbr-agent supports SW flow-control natively? If not, do we need to patch it? Thanks |
|
Glad the G4 came up cleanly on Q1 — no
|
|
@jnilo1 Thanks for the answers. I have a few followup questions:
I tried to test ethernet performance per your request, but stuck at initial step: I could not compile iperf3. Could you please let me know how to fix this? |
|
First, a correction I owe you: I sent you down a dead end. Those two The upside is that the error you hit was a real bug in our build script, not your environment — and it's now fixed. The iperf3 build error — fixediperf-3.18's public callback setters ( The one-line fix is in That downgrades it back to a warning. If you'd rather not pull the branch, just add that flag to your local
Q1 — letting the Linux serial driver do SW flow control wouldn't be lower latencyThe catch is where native termios software flow control lives: it's implemented by the N_TTY line discipline (and the serial core's throttle path it drives), both of which assume a tty with a userspace consumer. The bridge deliberately has no line discipline — it binds the So "let the serial driver handle it" would mean reinstalling an ldisc, which reintroduces the per-byte ldisc processing and the extra buffer copy that the And your back-pressure intuition is exactly right; it's just implemented in the bridge rather than delegated. A radio XOFF sets Q2 — on the Zigbee path the bridge never needs to XOFF the radioFor radio→host, the thing that keeps the radio from outrunning a stalled Home Assistant isn't the bridge — it's ASH itself. ASH (the EZSP transport the bridge carries byte-transparently) runs a sliding window with ACK/retransmit, so the NCP won't get more than its window ahead of the host's ACKs. A slow HA stalls the ASH ACKs → the NCP stops sending. The byte stream is self-limiting one layer up, so the bridge doesn't have to throttle the radio — which is also why it deliberately never emits XOFF (injecting a The one case ASH windowing doesn't cover is raw byte-rate overrun of the SoC's RX FIFO when the radio does burst faster than the SoC services the UART. That's what RTS/CTS protects against on the Lidl board (#89) — and it's exactly the gap on a board without RTS/CTS. Which is your Q3. Q3 — agreed it's worth doing; the framing is free, the host side is small, the firmware side is the real workYour risk analysis is sound and I don't want to wave it off: 460800 (4× NCP) + no RTS/CTS + RF-variable burst timing is a genuine RX-overrun exposure, and an overrun that only appears under certain RF conditions is miserable to reproduce. In-band XON/XOFF at 460800 is a reasonable thing to want to try. The framing is already done for you. OpenThread's HDLC encoder already escapes XON/XOFF — What's missing is the actuation, and it's lopsided. Host side is small. Unlike the in-kernel bridge (Q1), otbr-agent opens The firmware side is the real work — and "complicated" is Silabs' own assessment, not mine. The OT-RCP UART path (
The root tension is that UARTDRV is DMA-first (chosen for throughput) while XON/XOFF is intrinsically a per-byte, low-latency reaction. Bolt them together and your reaction time is bounded by the DMA-chunk callback cadence — with the 128-byte receive buffers here, an XOFF you emit (or one you honor) only takes effect a buffer-ful late. At 460800 that lag is exactly the window in which the overrun happens. That's the substance behind "partial," and the reason the host half is an afternoon and the firmware half is the actual project. That maps the work without my getting ahead of you on it: the framing's already there, the host |
|
@jnilo1 Thanks for fixing iperf3 build error. Here is the result from my unit: It seems that RX is okay, but TX is worse than your expectation (~73Mb/s). How to debug this further? Thanks for answering my questions! What you said makes sense to me. I was surprised that SiLab didn't fully implement SW Flow control because their GSDK has the option and the OT RCP firmware doesn't have other application code almost all code from Silab. Anyway, turning off SW flow control maybe is the right path for now. I glad that you implemented FIRMWARE_FLOW_CTRL to make this possible. |
|
Thanks for running it — and good, that result is more reassuring than it first looks. Reading the two columns: the left is the script's embedded v3.4.1 reference (RX 93.7 / TX 70.0), the right is your G4 measurement (RX 94.1 / TX 67.5). RX confirms the port is healthy94.1 is line rate — a hair above the reference, in fact. That matters more than it sounds, because RX and TX stress completely different things on this SoC, and RX is the one that proves the bring-up is sound. On the receive path the switch DMA engine writes straight into DRAM and the CPU only invalidates cache lines (~58 cycles/packet); ring management, DMA, the PHY and the switch fabric all have to be working at near line-rate for RX to sit at 94. So the G4 port's data path is healthy. Nothing to chase there. TX is the CPU/DRAM-bound direction — which is exactly where a board difference would showTX is a different animal. The Lexra has a write-back L1 and no DMA coherency hardware, so every transmitted byte crosses the DDR bus twice from the CPU's point of view — once when The consequence: TX throughput is set by CPU clock and DRAM write bandwidth, while RX is welded to line rate. So the one direction where a different board could legitimately land at a different number is TX — and that's precisely the shape of your result (RX pinned at 94, TX shifted down). The G4 isn't the Lidl board: different DRAM (64 MiB DDR2 vs the Lidl's 32 MB DDR), and possibly a different LX-bus/CPU clock. Any of those moves the TX ceiling without touching RX. And before reading too much into 67.5: it's a single sample. On the Lidl board TX has ranged 69.3–72.8 across sessions with no code change at all — this CPU has a real ±3 Mbit/s run-to-run spread (I/O-cache layout sensitivity). The What I'd check, in order
If you want to see where the TX cycles actually goThere are optional Fair warning though: that's diagnostic, not a lever. The same doc records a full orthogonal-levers session (kick coalescing, writeback-only flush, NAPI weight 128, full scatter-gather) — only Track A's kick coalescing helped, and only by +1.2%; everything else was flat or negative because the bottleneck is the DRAM write-back and the send stack, not the driver. So the probes would tell you why the G4 lands where it does, but they won't hand you a knob to push it higher. Net: I wouldn't treat 67.5 as a regression yet — RX proves the port is good, TX is the board-and-CPU-bound direction, and you've got one sample against a ±3 spread. Get me the median + the CPU-idle and clock readings and we'll know in five minutes whether the G4 simply has a slightly lower TX ceiling (most likely) or there's something real to chase. |
|
@jnilo1 Thanks for the input. I re-run the test multiple times. Most of them show TX throughput between 65M and 66M. There are some outputs: when trying your suggestion to use a different version with diagnose info, I got the following errors: Any suggestion? |
|
Thanks for putting in the reps — and that's the right move, because it changes how I read the number. A single 67.5 sat close enough to the Lidl floor (69.3) that I called it noise. A cluster at 65–66 across multiple runs is different: it's reproducible, and it's a couple Mbit/s under the floor, so it's no longer run-to-run spread to shrug at — it's a real characteristic of your setup to explain. Good news first, then the two things I genuinely can't tell from the report. The clean part: the link is good
The cheapest check of all — which build are you on?Before anything else: what does
So if your First, the cherry-pick error — and why I'd hold off anyway
But don't chase that yet. The probes only tell you why TX lands where it does — they aren't a knob. The same Thing 1 — is the path direct, and was everything quiesced?This is the piece I can't see from the report, and either half of it would account for the whole delta:
Clean re-run recipe, everything off: /etc/init.d/S70otbr stop # if present / running
/etc/init.d/S50uart_bridge stop # writes 0 to .../parameters/enable
cat /sys/module/rtl8196e_uart_bridge/parameters/enable # expect 0
# (also stop any Z2M / ZHA client pointed at TCP:8888)then the 5-rep TX median again. If the number jumps back toward 69–70 with those stopped, we're done — it was the confounder. Thing 2 — the reading that settles "lower ceiling vs artifact": is the CPU pegged?This is the single most useful measurement, and it's a five-second check. Run a reverse (gateway → host) iperf3 and watch the gateway: top -d1 # during the reverse-TX run
And the clocks, which would confirm a genuine-ceiling reading rather than leave it a guess — the G4 has different DRAM (64 MiB DDR2 vs the Lidl's 32 MB) and may run a different LX-bus/CPU clock: cat /proc/cpuinfo # BogoMIPS
dmesg | grep -i 'cpu\|clock\|mhz' | head # boot-banner clock lineIf the G4's clock differs from the Lidl's, TX scales with it directly and a few-% lower number is expected and correct — and it'd also show up as a different UART divisor, so it's worth knowing regardless. NetWith (a) a clean re-run median (OTBR + bridge stopped, direct cable) and (b) the |
|
@jnilo1 Thanks for the suggestion.
|
|
@jnilo1
@jnilo1 could you please provide your thoughts on this? |
|
Good consolidation — you've got three quarters of it exactly right, and the one correction needed is on point 1, where you're actually giving UARTDRV more credit than it deserves. Let me go through your three statements against the SDK source, because all of this is provable there — no behavioral inference needed. Point 1 (uartdrv_usart) — correction: it implements neither direction automaticallyYour reading was that UARTDRV implements the EFR32-RX side (EFR32 emits XON/XOFF toward the host) but not the EFR32-TX side. The source says it implements neither as a working feature — what it ships is a pair of manual hooks, one per direction, and the decision logic is left entirely to the application:
And the part that decides the outcome for OT-RCP: the OpenThread platform glue, Point 2 (iostream_usart) — confirmed, and you can drop the "not 100% sure": the source settles it
The structural reason iostream can be complete where uartdrv isn't: it's per-byte IRQ-driven rather than DMA-first, so it sees every byte as it arrives and can react at byte granularity — exactly the property XON/XOFF needs, and exactly what a DMA driver gives up for throughput. Your observation (a) is right — the software-flow NCP firmware is built on this driver. On your observation (c) as evidence, one honest caveat: HA connected with one paired device is light traffic, so flow control almost never actually engages at that load — and the NCP path is tolerant anyway (ASH escapes Point (b) — the bridge: correct as stated, and the asymmetry is deliberateYou read the bridge right. In That's a design decision, not a gap: the UART→TCP side handles pressure by dropping at the TCP Put together, your current G4 NCP setup is coherent end-to-end: firmware (iostream) emits XOFF when its RX buffer fills → bridge honors it; in the other direction ASH windowing throttles the radio at the protocol level. Both protections exist, just implemented at different layers. Summary matrix
Where this lands for #142This consolidation is precisely the rationale behind the experimental iostream OT-RCP package on #142: uartdrv-sw gives you nothing in either direction (matching your dead G4), while iostream-sw finally provides both firmware halves — and your IXON patch is the matching host half. So the decisive datapoints are unchanged: iostream-sw at 115200 first (sanity), then 460800 — the speed where uartdrv-sw was dead. If it comes up there, the software-flow path is viable at full speed; if it's still dead, we're back to suspecting the SoC→EFR32 TX side of the G4, per the earlier thread here. |
|
Here is summary of baud=460800 on G4.
|
|
@hlyi : Short answer: no, there is no such parameter — and the knob you are picturing would not help, because your overrun happens in a buffer that XOFF cannot protectYour question assumes the host sends XOFF too late. The kernel source says something stronger: in your setup the host almost certainly never sends XOFF at all, and the data is being lost one stage upstream of anything XOFF governs. Let me walk the chain, because every step is checkable in the tree you build from. Where your kernel message actually comes from
Where the host's XOFF is sent from — and why it never firesWith The physics of the failing stageAt 460800 8N1 a byte arrives every ~21.7 µs, so the 16-byte FIFO gives the CPU ~347 µs of tolerated interrupt latency — on a single-core 400 MHz MIPS. Anything that keeps the RX interrupt from being serviced longer than that loses data, full stop. And there is nothing left to tune at that layer: our kernel already pins the RX FIFO trigger to 1 (the most defensive value this UART allows — see the erratum block with the bench table in Here is the structural reason no software flow control can ever fix this stage: the CPU that would have to send the XOFF is the same CPU that is failing to service the interrupt. During the overrun window the host is, by definition, not executing — it can neither notice the FIFO filling nor transmit anything. Hardware flow control is different in kind, not in degree: auto-RTS is asserted by the UART silicon itself, with zero CPU involvement, which is why FIFO-class protection is RTS/CTS-only. This is the same lesson as issue #89 on the Lidl, and the reason we require hw flow for 460800 there. One testable candidate for your >347 µs windows: the serial console
Three small corrections to your summaryOn your point 1): your uartdrv build never sent any XON/XOFF toward the host — per the source walk earlier in this thread, nothing in that firmware emits them. The Host→RCP direction is robust for a different reason: uartdrv RX is DMA-driven, so the EFR32 has no per-byte interrupt deadline at all — the DMA drains its FIFO in hardware. Second, the fact that uartdrv-sw and iostream-sw produce the identical overrun at 460800 is the strongest single datapoint you collected: two very different radio firmwares, same failure — the wall is on the host side, below any layer the radio firmware can influence. Third, your #142 results 1b vs 2c (none@460800 agent dead, uartdrv-sw@460800 comes up) are odd, because on the wire those two setups behave identically (the sw config drives nothing in uartdrv, and your IXON flag only matters if the radio emits — it does not). Most likely the difference is overrun luck during the init burst; only worth re-running if you are curious. Where this leaves your G4The practical operating point for a board with no RTS/CTS path is software flow at 230400: the FIFO budget doubles to ~694 µs and your own uartdrv+XON test already passed there. If you can confirm iostream-sw at 230400, that completes the picture — that combination is the only one where both halves of software flow control actually function (radio emits and honors, host honors and emits), and it becomes the natural recommended configuration for sw boards. 460800 stays available as best-effort: occasional lost frames become spinel retries, which is exactly what your pairing hiccups look like. And for #142: nothing to walk back on the iostream backend — it does what the source promised at 115200, and the 460800 wall is host silicon, not the driver choice. One practical suggestion: rebase your tree on v4.0.0-rc5Your local builds are rc4-based, and rc5 (released yesterday) ships the whole batch that came out of your #140→#143 threads: the |
|
@jnilo1 thanks for the diagnose and explanation What’s the downside reducing baud rate to 230400? I will flash the unit to rc5 |
|
@hlyi : The downside of 230400: for a Thread border router, essentially none — here are the numbersWire capacity: at 8N1 a byte costs 10 bit times, so 230400 baud moves 23,040 bytes/s ≈ 184 kbit/s of payload (460800 ≈ 369 kbit/s). What the radio can actually deliver: 802.15.4 at 2.4 GHz is 250 kbit/s on air, but that is the line rate, not sustained goodput. Every acknowledged unicast frame carries mandatory dead time around it — 192 µs RX/TX turnaround, ~352 µs for the ACK itself, 640 µs inter-frame spacing, plus CSMA backoff (mean ≥ 1.1 ms on the first attempt) around each ~4.3 ms max-size frame. Run the arithmetic and even a saturated, error-free, single-hop link sustains roughly 155–185 kbit/s of frame bytes. So the spinel UART at 230400 (~184 kbit/s) is approximately matched to the most the radio can physically hand it; what 460800 buys is per-frame latency headroom, not sustained throughput. Latency: serializing a max-size spinel frame goes from ~3 ms to ~6 ms — and that same frame already spends over 4 ms on air before any backoff. Invisible at Thread timescales, and a border router's spinel link idles the overwhelming majority of the time anyway (typical traffic is small command/report frames). The comparison that actually matters is not "fast vs slow", it is "lossless 230400 vs lossy 460800". Every FIFO overrun at 460800 corrupts a whole HDLC frame, which costs a spinel retry/timeout or a dropped 802.15.4 frame — your pairing hiccups were that cost, and it is orders of magnitude larger than the 3 ms you save on serialization. At 230400 the 16-byte FIFO's latency budget doubles to ~694 µs, and your own uartdrv+XON run already passed there. For reference, the Lidl NCP path defaults to 115200 and carries full Zigbee networks; 230400 is twice that. One easy observable to confirm you are clean: after a pairing session at 230400, Since you are flashing rc5: you would be the first to run the whole G4 path end-to-end — please exercise itEverything from the #140–#143 batch shipped in rc5, all keyed on 1. Bootloader md5 first (#140 — still the GA gate). Before anything overwrites your current bootloader: Expected: 2. Full RTL8196E install. 3. OT-RCP at 230400 — the datapoint from my previous post, now on the shipping config. One caveat we owe you a fix for: The build auto-selects the iostream backend for a 4. Z3 router, when you have time (#143 — the open hardware validation). What is left to prove there is simply that it joins a Zigbee network and answers on the CLI. So after your rc5 pass we would have: the #140 md5 (GA gate), your experience with the per-board install path, the iostream-sw@230400 result (ideally with the |
|
@jnilo1
b. without XON in otbr-agent, Since ERF32 with sw-flow-control enabled, it will cause problem when ERF32 sending XON char, and otbr-agent sees raw XON char can treat it as data? |
|
@hlyi : On 4a — the slcp baud: cosmetic, but you caught a real inconsistencyGood eye, and the short version is reassuring: the firmware you built was running at 230400. What you saw is a stale value in the project file, not what got compiled. The build overwrites On 4b — you are right, and we are going to adopt your patch rather than work around itYour question is exactly the right one, and it corrects something I framed too optimistically earlier in this thread. The iostream-sw firmware the selector builds for a sw board does emit XON/XOFF (watermark-driven), and a stock otbr-agent has no IXON, so a raw 0x11/0x13 from the radio lands in the HDLC decoder as frame data, the FCS fails, and the frame is dropped — the exact mechanism I described back in the #142 thread. So "stock, no IXON" is not actually a clean shipping config for an emitting firmware; I was wrong to imply it was. I checked whether there is any way to get IXON without touching otbr-agent, precisely because a local fork of OpenThread is something we would rather avoid. There is not: in the pinned OpenThread source we build from ( What we would like you to validate — your own patch, in the exact form we would shipSince you build otbr-agent yourself, this is just the two diffs below applied to your rc5 tree and rebuilt — no binary from us. They are your patch, re-anchored to the rc5 sources so your result certifies the exact configuration we would commit for v4.0.0.
if (aRadioUrl.HasParam("uart-flow-control"))
{
tios.c_cflag |= CRTSCTS;
}
+ else if (aRadioUrl.HasParam("uart-sw-flow-control"))
+ {
+ tios.c_cflag &= ~CRTSCTS;
+ tios.c_iflag |= IXON;
+ }
else if (aRadioUrl.HasParam("uart-init-deassert"))
case "$val" in
- none|sw) FC_PARAM="" ;;
+ none) FC_PARAM="" ;;
+ sw) FC_PARAM="&uart-sw-flow-control=true" ;;
esacThen the test that matters: the canonical rc5 OT-RCP for the G4 ( If it comes up clean, we adopt your patch into the build: a committed patch file applied to the openthread submodule in |
|
@jnilo1 Thanks for thorough analysis on openthread source code. Based upon your instruction, I updated The changes have flashed into the unit, and it has been running for about 4 hours now (I paired matter devices multiple times) . no |
Keep
|
|
@jnilo1 For baudrate being tested on G4, it is 230400 based upon your earlier instruction. It is running for 18 hours. error in kernel log. No and |
230400 — that closes itThat is the datapoint, and it is the good one: 230400 is exactly the operating point we are recommending for a board without RTS/CTS, so an 18-hour clean run with repeated Matter pairings certifies the shipped configuration rather than merely the principle. It is now in the changelog in those terms, credited to you. Two things your raw report confirms beyond the headline, worth putting on the record because they are the premise of the whole patch rather than a consequence of it: Your And on the One heads-up for when you take v4.0.0Your Nothing further needed from you here. v4.0.0 is still gated on the issue #99 field soak; I will leave this discussion open until it ships, and if the G4 is still running clean by then that is a bonus line in the release notes rather than a condition of it. |
|
@jnilo1 There is one occurrence of input overrun for about 60 hours. And the overrun coincides with timing window of hardware bug mentioned in #99 |
This is the first phantom ever observed at 230400 — a genuinely new datapoint for #99Everything previously on record for the It is also a first on two other axes: first phantom on a Sengled G4 (EFR32MG13 peer), and first with software flow control (no AFE/RTS-CTS in the loop) — which retires a couple of "maybe it is AFE-specific / board-specific" side-theories in one shot. And the rc5 quirk did exactly what it was designed to do: four rate-limited log lines and a healthy box. Pre-rc5, occurrence #1 would have been a level interrupt re-asserting forever, and with the idle gaps your network shows, very likely the 20 s softlockup → watchdog reboot documented in #99. Nothing to do on your side — the warnings are the fix working, not a problem to fix. Your overrun coincidence is sharper than you may realize
Our driver pins the RX FIFO trigger at 1, so the FIFO tolerates ~15 character-times of interrupt-service latency before OE: ~651 µs at 230400. Your log therefore records one event where interrupt service stalled for more than ~650 µs — and it landed ~42 ms after phantom #1 (kernel ts 110721.954 vs 110721.996). One extreme latency event, two signatures: the phantom is born when the FIFO drain races the character-timeout latch, and a long stall is precisely what maximizes that window. Your It also quantifies why 230400 was the right call for the G4: the latency budget before an overrun is ~651 µs at 230400 but only ~326 µs at 460800 — your measured 280 µs interrupt stall alone nearly consumes the 460800 budget. One overrun in 60 h is a latency-tail event no baud fully eliminates (at 115200 the budget would be ~1.3 ms), and the HDLC/spinel layer retransmits the affected frame; it does not retract the 230400 recommendation. Two asks, to make the datapoint fully comparableFirst: the working currency of the #99 model is phantoms per ttyS1 interrupt, and we have your timestamps but not your interrupt count. Could you run this on the box, all in one shot, and post the raw output? The four lines have to come from the same moment: the last Second, a pattern worth watching: the gap #1→#2 is 29 235 s and #2→#3 is 29 215 s — equal within 20 seconds, about 8 h 07 min. If anything in your setup runs on an ~8-hour cycle (controller re-sync, periodic backup, mDNS re-registration), it may be the burst source that opens the timeout window. If a 5th occurrence lands ~29 200 s after #4, that is signal, not noise. Where this fitsThis slots straight into the #99 cross-read: my Lidl OTBR@460800 at ~15/day, your G4 OTBR@230400 at ~1.6/day, and my Zigbee/NCP production box freshly moved from 115200 to 460800 (pre-registered in #99) to separate baud from stack. Your datapoint already answers one question that matrix could not: the window does not need to be 87 µs — 174 µs is enough when the traffic cooperates. v4.0.0 remains gated on the #99 soak; your box staying up while logging these is precisely the evidence that gate exists to collect. |
|
@jnilo1 Thanks for full detailed analysis. Here the information you requested: For the overrun condition occurred at |
|
@hlyi : You are right — the overrun was caused by our own warning message, and I am withdrawing my earlier interpretationI went through the mechanics in the tree, and your hypothesis is correct in every detail except one, which makes it worse rather than better: it is not the printk formatting that is slow (that is microseconds of string work), it is the synchronous emission to the serial console behind it. The chain, verified in the source: the v1.5 warning is a Now hold that against your log: phantom #1 stamped at 110721.954400, the overrun message at 110721.996040 — +41.6 ms. That is ~38 ms of console write plus ~3 ms for the post-print FIFO drain and the line-discipline worker that prints And your board is the only one in the fleet that can lose bytes this way, which is the cleanest confirmation of all: on RTS/CTS boards the auto-flow hardware deasserts RTS as the FIFO fills and the radio pauses, so the same 38 ms window is loss-free — consistent with zero So, for the record: my previous post called your phantom + overrun pair "one long IRQ-latency tail event producing both signatures — the strongest field evidence tying phantom birth to latency tails". That interpretation was wrong and I withdraw it. The overrun was self-inflicted by the fix's own warning and is evidence of nothing except our console being slow. What remains as platform latency-tail evidence is the Your denominator, and the 8-hour pattern4 occurrences / 6,663,545 interrupts = 6.0e-7 per interrupt at 230400 (23.9 IRQ/s average) — about 8× below my production box at 460800 (4.9e-6), directionally what the narrower timeout window predicts. And the quasi-period broke: no 5th occurrence ~29,200 s after #4 — the gap since #4 is already ≥63,100 s, longer than every previous gap (29,235 / 29,215 / 46,762 s). So no strict 8-hour driver in your network; the process is bursty, not periodic. One falsifiable check going forward, since your board is the sensitive instrument here: under this mechanism every future To be clear about the practical impact on your box: the warning itself stays useful — it is the field confirmation signal this whole campaign runs on — and the worst this artifact costs you is one retransmitted HDLC frame on the rare occasion the radio happens to be mid-transmission when a phantom fires. This correction goes into the #99 record credited to you — nothing further needed on your side, and thanks: a question that sharpens the analysis is the best kind of review. |
|
@jnilo1 Thanks for detailed explanation! that makes a lot of sense. I have two additional questions:
Thanks |
Short version: yes it applies to the Lidl too, and v4.0.0 removes the window rather than just shortening itTaking your three points in order, then what actually happens in the release. 1. Does the ~38 ms block apply to the Lidl?Yes — identically. It is the same driver, the same ISR, and the same 38400-baud legacy console, so a v1.5 warning holds interrupts off for the same ~38 ms on a Lidl as on your G4. What differs is only the consequence. On the Lidl, and every RTS/CTS box, the auto-flow hardware deasserts RTS as the RX FIFO fills, the radio pauses, and the window is loss-free — which is exactly why 241 phantom warnings on hardware-flow boxes to date have produced zero 1a. Any latency-sensitive radio↔host transaction hurt by it?No — nothing breaks. The hard real-time deadlines on the radio link (802.15.4 ACK turnaround, CSMA backoff) all live on the EFR32 itself, not across the UART. What the UART carries is the host↔radio control protocol — EZSP, CPC or spinel — and every one of those is a reliable, sequence-numbered transport with retransmission and timeouts measured in hundreds of milliseconds to seconds, far larger than 38 ms. So the worst a stall costs cpcd or otbr-agent is one frame delayed, and on your board occasionally one frame retransmitted. It never turns into a protocol failure, because the layer that would notice is built to absorb exactly this. 1b. Can the EFR32 hold its pending TX during the stall?Your arithmetic is the right order of magnitude — ~925 bytes at 230400 over 40 ms, and it would be ~1.8 kB at the Lidl's 460800. When the host deasserts RTS, the EFR32's USART stops after its current byte, and the bytes that would have gone out do not sit in the tiny hardware buffer — they wait in the firmware's TX frame queue in RAM, the spinel or CPC transmit path. Those queues are sized for far more than a single 40 ms hiccup, so a one-off event is held and nothing is lost; and if a stall ever were long enough to exhaust them, the reliable layer above retransmits rather than corrupts. I am deliberately not quoting an exact buffer size — it is a per-image build constant I would have to read out of the specific firmware — but the design point stands regardless of the number: what holds the data is the RAM frame queue and the retransmit guarantee, not the UART FIFO. 2. Can the console print move out of the IRQ? — v4.0.0 does better: it removes itThis is the real answer, and it is your question turned into the fix. v4.0.0 ships driver v1.6, which follows the mainline dw8250 precedent for precisely this phantom RX-timeout condition: recover silently. The ISR does the one dummy read that clears the stuck latch and increments a counter, and that is all — no You do not lose the observability, though. Two module parameters replace the log line:
A silent counter beats a deferred print here: a workqueue print would still do work per event and fill the log, whereas the counter costs nothing and answers the same question on demand. Net for your boxOn rc5, which is what you run today, the window exists but is harmless on a hardware-flow Lidl and costs your G4 at most one retransmitted HDLC frame on the rare occasion the radio is mid-transmission when a phantom fires. On v4.0.0 the window is gone by default and you get a |
|
@jnilo1 Thanks for clarifying the questions. And great to hear that upcoming v4.0.0 will not have 38ms blockage. Since you implemented sw flow control, (thank you for that), I am closing this discussion. |
Keep
IXON | IXOFF— it is the right call, though for a different reason than the one you gaveThe part that actually fixes 4b is
IXON. On a Linux tty,IXONmeans "act on flow characters received from the peer": the tty pauses its own transmit on XOFF, resumes on XON, and — the part that matters here — consumes those 0x11/0x13 so they never reach otbr-agent's HDLC decoder. That is the "escape them properly" behaviour you are after, andIXONalone delivers it.IXOFFis the other direction: it lets the host emit XOFF/XON to the radio when its own input buffer runs low (n_tty throttles when fewer than 128 bytes of the 4096-byte buffer are free). That is not needed to fix 4b — but it is not de…