From 799692a5f430e1c250965907b2cef72e7c2a42ae Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Fri, 9 Oct 2026 19:09:05 +0200 Subject: [PATCH] netboot: stop with the summary before booting Swiss The transfer completes on hardware -- 293/293 blocks, 299908 bytes in 15.7 s -- but roughly a third of blocks needed a retry, and the numbers that say WHY are printed by the GC and then scrolled away when Swiss boots. So the one side that knows whether an ACK failed to transmit or was lost on the wire could not be read. netboot now stops after writing the SD card and waits for a button press, and the summary carries the counters that separate the cases: desc@+0=N +1=M bad=N lapped=N txto=N txto is the discriminator: it counts ACKs where TI never set, meaning the frame never reached the W5100. High txto alongside the host's retries points at the TX path; txto near zero points at frames sent but lost. Co-Authored-By: Claude Opus 5 --- gc_bba_test/README.md | 19 ++++++++++++++++++- gc_bba_test/source/main.c | 9 ++++++++- gc_bba_test/source/netboot.c | 25 +++++++++++++++++-------- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/gc_bba_test/README.md b/gc_bba_test/README.md index e6b9717..97c51a3 100644 --- a/gc_bba_test/README.md +++ b/gc_bba_test/README.md @@ -163,7 +163,24 @@ one block per round trip, so block size sets the speed. A missing ACK is not fatal: the host retransmits, and the GC re-ACKs a duplicate block rather than ignoring it, so a lost ACK recovers in one -timeout. `txto=N` in the status line counts ACKs where TI never set. +timeout. + +**The GC stops with its summary before booting Swiss** — press a button to +continue. Those counters are the only place the *reason* for a retry shows up: + +``` +desc@+0=N +1=M bad=N lapped=N txto=N +``` + +- `txto` — ACKs where TI never set, i.e. the frame never reached the W5100. + High `txto` with many host-side retries means the TX path is the problem. +- `txto` near zero with many retries means ACKs were sent but lost on the wire + or at the host. +- `desc@+1` — frames whose ring descriptor landed at page offset +1 instead of + +0. Still unexplained; the reader handles both. + +Measured 2026-10-09: 299908 bytes in 293 blocks took 15.7 s with roughly a +third of blocks retried — the retries, not the data, dominate the time. ### Stop-and-wait is load-bearing diff --git a/gc_bba_test/source/main.c b/gc_bba_test/source/main.c index 06ae956..89720ae 100644 --- a/gc_bba_test/source/main.c +++ b/gc_bba_test/source/main.c @@ -152,7 +152,8 @@ static void do_netboot(char *status, size_t nstatus) * round trips. */ printf(C_DIM " temp+verify+rotate; keeps .prev.dol; boots /boot.dol\n" C_RESET); - printf(" Blocks until done or it times out (30 s idle, 5 s mid-xfer).\n\n"); + printf(" Blocks until done or it times out (30 s idle, 5 s mid-xfer).\n" + " Stops with the summary before booting Swiss.\n\n"); if (!s_stage) { snprintf(status, nstatus, "net-update: staging region unavailable"); @@ -176,6 +177,12 @@ static void do_netboot(char *status, size_t nstatus) return; } + /* Stop here so the transfer summary can actually be READ. Booting + * straight into Swiss scrolled it away, which meant the one set of + * numbers that says WHY blocks needed retrying -- txto, the descriptor + * split, bad/lapped counts -- was never visible. */ + nb_pause("update written to the SD card"); + printf("\n booting /boot.dol ...\n"); VIDEO_WaitVSync(); VIDEO_WaitVSync(); diff --git a/gc_bba_test/source/netboot.c b/gc_bba_test/source/netboot.c index 0e00c12..0c4bd92 100644 --- a/gc_bba_test/source/netboot.c +++ b/gc_bba_test/source/netboot.c @@ -413,14 +413,23 @@ int netboot_receive(void *dst, u32 maxlen, void (*status)(const char *msg)) memcpy(s_dest, frame + NB_HDR, plen); s_dest[plen] = 0; } - if (status) { snprintf(line, sizeof(line), - "received %u bytes, %u blocks " - "(desc@+0=%u +1=%u, %u bad)", - (unsigned)got, (unsigned)nblocks, - (unsigned)s_shift_hits[0], - (unsigned)s_shift_hits[1], - (unsigned)bad); - status(line); } + if (status) { + snprintf(line, sizeof(line), + "received %u bytes in %u blocks", + (unsigned)got, (unsigned)nblocks); + status(line); + /* txto distinguishes the two reasons an ACK can go + * missing: TI never set (the frame did not reach the + * W5100) versus sent-but-lost. The host reports the + * retries; only the GC knows which kind they were. */ + snprintf(line, sizeof(line), + "desc@+0=%u +1=%u bad=%u lapped=%u txto=%u", + (unsigned)s_shift_hits[0], + (unsigned)s_shift_hits[1], + (unsigned)bad, (unsigned)lapped, + (unsigned)s_tx_timeouts); + status(line); + } return (int)got; } if (frame[18] != NB_OP_DATA) continue;