netboot: sync RRP to RWP at init instead of trusting what we inherited
Pressing Z returned "net-update failed (-2)" -- ring_next() rejecting an RRP outside the ring (pages 1-15) before a single frame was read. The pointer was never ours to assume. Swiss initialises the BBA before launching us and writes RRP itself, and an NCRA reset does NOT restore the register file's copy of either pointer: their init values only apply at FPGA configuration. So RRP can legitimately be anything on entry, including 0, and the previous code treated that as a fatal error instead of a state to establish. netboot_receive() now reads RWP and writes RRP = RWP after the reset, which declares the ring empty and consistent whatever it was, so the first frame read is genuinely the host's first block. RWP itself is still checked, because that one IS the gateware's own pointer and an out-of-range value there would be a real fault rather than inherited state. The ring-error message now reports RRP and RWP and spells out which of the three failures it was (EXI access, RRP out of range, implausible descriptor). Each test costs an SD card copy by hand, so a bare error code is not worth the round trip. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -136,6 +136,31 @@ int netboot_receive(void *dst, u32 maxlen, void (*status)(const char *msg))
|
|||||||
* ring, so frames arrive at the W5100 and go nowhere. */
|
* ring, so frames arrive at the W5100 and go nowhere. */
|
||||||
if (bba_w8(REG_NCRA, NCRA_SR) < 0) return -1;
|
if (bba_w8(REG_NCRA, NCRA_SR) < 0) return -1;
|
||||||
|
|
||||||
|
/* Establish a KNOWN ring state instead of trusting what we inherited.
|
||||||
|
* Swiss initialises the BBA before launching us and writes RRP itself,
|
||||||
|
* and an NCRA reset does not restore the register file's copy of either
|
||||||
|
* pointer -- their init values only apply at FPGA configuration. So
|
||||||
|
* RRP can legitimately be anything, including 0, which is outside the
|
||||||
|
* ring (pages 1-15) and used to abort the whole transfer.
|
||||||
|
*
|
||||||
|
* Setting RRP = RWP declares the ring empty and consistent, whatever it
|
||||||
|
* was, so the first frame we read is genuinely the host's first block. */
|
||||||
|
{
|
||||||
|
u8 wp[2];
|
||||||
|
if (bba_read(REG_RWP_LO, wp, 2) < 0) return -1;
|
||||||
|
if (wp[0] < 1 || wp[0] > 15) {
|
||||||
|
/* RWP is the gateware's own pointer, so this should not
|
||||||
|
* happen -- say so loudly rather than papering over it. */
|
||||||
|
if (status) { snprintf(line, sizeof(line),
|
||||||
|
"RWP=%u outside ring pages 1-15", wp[0]);
|
||||||
|
status(line); }
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
if (bba_w8(REG_RRP_LO, wp[0]) < 0) return -1;
|
||||||
|
if (status) { snprintf(line, sizeof(line),
|
||||||
|
"ring synced at page %u", wp[0]); status(line); }
|
||||||
|
}
|
||||||
|
|
||||||
/* PAR0-5 survives the reset (it is the gateware's power-on MAC), and it
|
/* PAR0-5 survives the reset (it is the gateware's power-on MAC), and it
|
||||||
* is read AFTER the reset so the source address we put in ACKs is the
|
* is read AFTER the reset so the source address we put in ACKs is the
|
||||||
* one the adapter is actually filtering on. */
|
* one the adapter is actually filtering on. */
|
||||||
@@ -147,8 +172,21 @@ int netboot_receive(void *dst, u32 maxlen, void (*status)(const char *msg))
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
int n = ring_next(frame, sizeof(frame));
|
int n = ring_next(frame, sizeof(frame));
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (status) { snprintf(line, sizeof(line), "ring error %d", n);
|
/* Report the pointers, not just the code: -1 is an EXI access
|
||||||
status(line); }
|
* failure, -2 an RRP outside the ring, -3 a descriptor whose
|
||||||
|
* length is implausible. Which one it is, and what the
|
||||||
|
* pointers read, is the whole diagnosis. */
|
||||||
|
u8 rp[2] = {0xFF, 0xFF}, wp[2] = {0xFF, 0xFF};
|
||||||
|
bba_read(REG_RRP_LO, rp, 2);
|
||||||
|
bba_read(REG_RWP_LO, wp, 2);
|
||||||
|
if (status) {
|
||||||
|
snprintf(line, sizeof(line),
|
||||||
|
"ring error %d (RRP=%u RWP=%u) %s", n, rp[0], wp[0],
|
||||||
|
n == -1 ? "EXI access failed" :
|
||||||
|
n == -2 ? "RRP outside pages 1-15" :
|
||||||
|
"descriptor length implausible");
|
||||||
|
status(line);
|
||||||
|
}
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user