DF-4549 / viapm_wait_offbyone_demo.c
/* DF-4549 — host-side demonstration of the viapm_wait() off-by-one. * * Replicates the EXACT control flow of sys/dev/powermng/viapm/viapm.c:567-605 * with the hardware register read replaced by a fixture, to show the two * failure modes of the `while (count--)` / `if (!count)` pair: * * (A) controller never completes (perpetual SMBHST_BUSY): after the loop * exhausts, count == -1, so `!count` is FALSE -> SMB_ETIMEOUT is NEVER * set -> viasmb_recvb/readb/readw/bread return SMB_ENOERR ("success") * with stale SMBHDATA0/1 register contents as data. * * (B) completion lands exactly on the 10000th (final) poll: break leaves * count == 0 -> `!count` is TRUE -> a SUCCESSFUL transaction is * spuriously failed with SMB_ETIMEOUT. */ #include <stdio.h> #define SMB_ENOERR 0x0 #define SMB_ETIMEOUT 0x20 #define SMBHST_BUSY 0x01 #define SMBHST_INTR 0x02 static int fake_smbhst; /* fixture: SMBHST register value */ static int viapm_wait_fixed_point(int fake_STS_register_on_every_poll) { int count = 10000; int sts = 0; int error; fake_smbhst = fake_STS_register_on_every_poll; /* --- verbatim loop shape from viapm.c:574-581 --- */ while (count--) { /* DELAY(10); VIAPM_INB(SMBHST) */ sts = fake_smbhst; if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) break; } error = SMB_ENOERR; /* --- verbatim timeout test from viapm.c:587-588 --- */ if (!count) error |= SMB_ETIMEOUT; return error; } int main(void) { int r; /* Case A: wedged bus — BUSY forever. Expected correct: SMB_ETIMEOUT. */ r = viapm_wait_fixed_point(SMBHST_BUSY); printf("case A (perpetual BUSY, real timeout): error=0x%x %s\n", r, (r & SMB_ETIMEOUT) ? "-> timeout correctly reported" : "-> *** SMB_ETIMEOUT MISSING: kernel reports SUCCESS on wedged bus ***"); /* Case B: completion on the very last poll iteration. */ fake_smbhst = 0; /* patched below for last-iteration only */ { int count = 10000; int sts = 0; int error = SMB_ENOERR; while (count--) { sts = (count == 0) ? SMBHST_INTR /* last poll: done */ : SMBHST_BUSY; if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) break; } if (!count) error |= SMB_ETIMEOUT; printf("case B (INTR on final poll, success): error=0x%x %s\n", error, (error & SMB_ETIMEOUT) ? "-> *** SPURIOUS SMB_ETIMEOUT on successful transaction ***" : "-> success correctly reported"); } return 0; } |