Remove the device-ID one-shot: it made Swiss see no adapter at all
id_phase was set at reset and cleared permanently by the GC's first NCRA reset, after which a command-space read of register 0 returned 0x00000000. Swiss calls EXI_GetID from bba_exists() AND again from bba_requires_init(), long after init, and matches the result against EXI_MX98730EC_ID -- so with the one-shot spent no case matched and Swiss reported NO ADAPTER, not a broken one. Running gc_bba_test was enough to spend it, so the adapter would "disappear" after any test session. The justification in the comment was wrong. It claimed the fast path would otherwise hijack address 0 so the GC could never read NCRA back -- but NCRA is REGISTER space (0x80/0xC0 header) while the fast path requires byte 0 == 0x00, i.e. COMMAND space. They were never ambiguous, and no driver reads command register 0 for anything else (libogc2 reads 0x01/0x03/0x0B/0x0F, Swiss 0x03). Real hardware answers EXI_GetID whenever asked; that is how EXI enumerates devices. id_arm is now tied high, and the id_phase output, the FFSynchronizer that crossed it into the pin domain, and the BBATop wiring are all gone. The port stays only so the PHASE_METER build can disarm the fast path, which would otherwise send ID bytes instead of its constant 0x80. bba_top T1b reads the device ID AFTER an NCRA reset, which T1 (before any reset) structurally cannot catch. Mutation-tested: disarming the fast path returns 00 00 00 00 for both, exactly what Swiss saw. gc_bba_test: the ID tests no longer skip. A wrong ID is a FAILURE again, with no iface_alive() discrimination and no ordering requirement between suites -- the ID is readable at any point in a run. g_ncra_reset_done and iface_alive() are removed outright rather than left as a dead flag. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+13
-49
@@ -5,54 +5,31 @@
|
||||
#include <unistd.h>
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
|
||||
int g_ncra_reset_done = 0;
|
||||
|
||||
static void msleep(u32 ms) { usleep(ms * 1000); }
|
||||
|
||||
/* ───────────────────────── suite 1: identity ───────────────────────── */
|
||||
|
||||
/* Is the EXI link demonstrably healthy apart from address 0?
|
||||
/* The device ID is answerable AT ANY TIME, so these tests no longer skip.
|
||||
*
|
||||
* Needed because `id_phase` is a ONE-SHOT in the FPGA, cleared by the first
|
||||
* NCRA reset, and g_ncra_reset_done only tracks resets THIS RUN of the test
|
||||
* app issued. That flag is software state standing in for hardware state, and
|
||||
* the two come apart as soon as a build is delivered over the wire: netboot
|
||||
* replaces the DOL and restarts the app with the flag clear, while the FPGA
|
||||
* keeps running with id_phase already spent by the previous run. The ID tests
|
||||
* then query address 0, get NCRA back -- correct behaviour -- and report a
|
||||
* FAILURE for it. Reflashing the FPGA is the only thing that restores it.
|
||||
* It used to be a one-shot in the FPGA -- `id_phase`, cleared by the GC's
|
||||
* first NCRA reset -- so these tests had to guess whether a wrong answer meant
|
||||
* a spent one-shot or a real fault, and they ran in a fixed order to get a
|
||||
* reading at all. That was a deviation from real hardware, which answers
|
||||
* EXI_GetID whenever the GC asks (it is how EXI enumerates devices). The
|
||||
* deviation broke Swiss outright: it calls EXI_GetID from bba_exists() and
|
||||
* again from bba_requires_init() long after init, and with the one-shot spent
|
||||
* got 0x00000000, i.e. NO ADAPTER AT ALL.
|
||||
*
|
||||
* HIPR and NWAYS are hardwired constants in the register file and do not
|
||||
* depend on id_phase, so if BOTH read correctly the EXI path is fine and a
|
||||
* wrong answer at address 0 can only be a spent id_phase. If they are wrong
|
||||
* too, something real is broken and the test must still fail. */
|
||||
static int iface_alive(void)
|
||||
{
|
||||
return bba_r8(REG_HIPR) == HIPR_PRESENT &&
|
||||
bba_r8(REG_NWAYS) == NWAYS_LINKUP;
|
||||
}
|
||||
|
||||
* With that removed, a wrong ID is simply a FAILURE again -- no skip, no
|
||||
* iface_alive() discrimination, and no ordering requirement between suites. */
|
||||
static int t_devid(char *m, size_t n)
|
||||
{
|
||||
u8 b[4];
|
||||
int rc;
|
||||
if (g_ncra_reset_done) {
|
||||
snprintf(m, n, "skipped: id_phase is a one-shot; reflash/reset the FPGA");
|
||||
return 2;
|
||||
}
|
||||
if ((rc = bba_devid(b)) < 0) { snprintf(m, n, "EXI error %d", rc); return 1; }
|
||||
if (b[0]==0x04 && b[1]==0x02 && b[2]==0x02 && b[3]==0x00) {
|
||||
snprintf(m, n, "%02X %02X %02X %02X (want 04 02 02 00)",
|
||||
b[0], b[1], b[2], b[3]);
|
||||
return 0;
|
||||
}
|
||||
if (iface_alive()) {
|
||||
snprintf(m, n, "%02X %02X %02X %02X: id_phase spent, reflash FPGA",
|
||||
b[0], b[1], b[2], b[3]);
|
||||
return 2;
|
||||
}
|
||||
snprintf(m, n, "%02X %02X %02X %02X (want 04 02 02 00)", b[0], b[1], b[2], b[3]);
|
||||
return 1;
|
||||
return (b[0]==0x04 && b[1]==0x02 && b[2]==0x02 && b[3]==0x00) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int t_hipr(char *m, size_t n)
|
||||
@@ -130,7 +107,6 @@ static int t_ncra_reset(char *m, size_t n)
|
||||
{
|
||||
int i, v;
|
||||
if (bba_w8(REG_NCRA, NCRA_RESET) < 0) { snprintf(m, n, "write failed"); return 1; }
|
||||
g_ncra_reset_done = 1;
|
||||
for (i = 0; i < 50; i++) {
|
||||
v = bba_r8(REG_NCRA);
|
||||
if (v < 0) { snprintf(m, n, "read failed"); return 1; }
|
||||
@@ -269,14 +245,6 @@ static int t_raw_id(char *m, size_t n)
|
||||
u8 b[8];
|
||||
int i, at = -1, rc;
|
||||
u16 h = 0x0000;
|
||||
/* Fast path for a reset this run issued. Note this flag can be STALE
|
||||
* (see iface_alive): it is clear after a netbooted update even though the
|
||||
* FPGA's id_phase is long gone, which is why the result is also checked
|
||||
* against iface_alive() below rather than trusted to this. */
|
||||
if (g_ncra_reset_done) {
|
||||
snprintf(m, n, "skipped: id_phase is a one-shot; reflash/reset the FPGA");
|
||||
return 2;
|
||||
}
|
||||
if ((rc = begin_raw()) < 0) { snprintf(m, n, "EXI error %d", rc); return 1; }
|
||||
EXI_Imm(BBA_EXI_CHAN, &h, 2, EXI_WRITE, NULL);
|
||||
EXI_Sync(BBA_EXI_CHAN);
|
||||
@@ -287,10 +255,7 @@ static int t_raw_id(char *m, size_t n)
|
||||
snprintf(m, n, "%02X %02X %02X %02X %02X %02X %02X %02X | 0x04 %s%d",
|
||||
b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7],
|
||||
at < 0 ? "absent" : "at slot ", at < 0 ? 0 : at);
|
||||
if (at == 0)
|
||||
return 0;
|
||||
/* Same discrimination as t_devid: a spent id_phase is not a fault. */
|
||||
return iface_alive() ? 2 : 1;
|
||||
return at == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/* ───────────────────────── suite 5: ethernet ───────────────────────── */
|
||||
@@ -527,7 +492,6 @@ static int t_init_sequence(char *m, size_t n)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
g_ncra_reset_done = 1;
|
||||
/* The sentinels must still read correctly afterwards -- if any write in
|
||||
* that list had been misdecoded, the most likely casualty is the state
|
||||
* these two report. */
|
||||
|
||||
Reference in New Issue
Block a user