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;