DF-4304 / bfe_walk_harness.c
/* * bfe_walk_harness.c - index-space + loop-termination proof for the * bfe_rxeof()/bfe_txeof() DMA-status walks (if_bfe.c:1064-1083, :1105-1147). * * Constants from sys/dev/netif/bfe/if_bfereg.h: * BFE_STAT_CDMASK 0x00000fff (:69, 12-bit "current descriptor" offset) * BFE_DESC (size) 8 bytes (:434-437, two uint32_t) * BFE_RX_LIST_CNT 511 (:406) valid indices 0..510 * BFE_TX_LIST_CNT 511 (:405) * BFE_INC(x,y) x = (x == y-1) ? 0 : x+1 (:426) * * Driver arithmetic under test: * bfe_txeof: chipidx = (CSR_READ_4(BFE_DMATX_STAT) & CDMASK) / 8; :1064-1065 * while (i != chipidx) { ...; BFE_INC(i, 511); } :1070-1083 * bfe_rxeof: current = (CSR_READ_4(BFE_DMARX_STAT) & CDMASK) / 8; :1106-1107 * while (current != cons) { ...; BFE_INC(cons, 511); } :1109-1147 * * The 12-bit field encodes byte offsets 0..4095 -> indices 0..511. * 511 is NOT a valid ring index (ring is 0..510) and BFE_INC can never * produce it, so any hardware-reported offset in [4088..4095] makes both * loops non-terminating (interrupt context, serializer held). * The driver itself programs 511*8 = 4088 into BFE_DMARX_PTR * (if_bfe.c:549), so the off-ring encoding is an architecturally used * value on this register interface, not a purely theoretical one. */ #include <stdio.h> #define BFE_STAT_CDMASK 0x00000fffu #define DESC_SZ 8u #define LIST_CNT 511u int main(void) { unsigned max_idx = BFE_STAT_CDMASK / DESC_SZ; unsigned cons, current; long steps; int terminated = 0; printf("bfe walk harness: CDMASK=0x%03x desc_sz=%u ring=%u entries " "(valid 0..%u)\n", BFE_STAT_CDMASK, DESC_SZ, LIST_CNT, LIST_CNT - 1); printf("encodable descriptor indices: 0..%u -> index %u is OUTSIDE " "the ring (ring max %u)\n", max_idx, max_idx, LIST_CNT - 1); printf("offsets encoding the off-ring index: [%u..%u] " "(driver itself writes %u (511*8) to BFE_DMARX_PTR at if_bfe.c:549)\n", max_idx * DESC_SZ, BFE_STAT_CDMASK, LIST_CNT * DESC_SZ); /* simulate bfe_rxeof's walk: cons starts at 0, BFE_INC cycles 0..510 */ for (current = 0; current <= max_idx; current++) { cons = 0; steps = 0; while (current != cons) { cons = (cons == LIST_CNT - 1) ? 0 : cons + 1; /* BFE_INC */ if (++steps > 1000000L) { printf("current=%3u: walk NEVER TERMINATES " "(no cons in 0..%u equals it; >1e6 steps)\n", current, LIST_CNT - 1); if (current == max_idx) terminated = -1; break; } } if (steps <= 1000000L && current == max_idx) printf("current=%3u: terminated after %ld steps " "(UNEXPECTED)\n", current, steps); } printf("RESULT: off-ring index %u => %s\n", max_idx, terminated ? "bfe_rxeof/bfe_txeof walk cannot terminate " "(interrupt-context livelock holding the serializer)" : "walk terminated (analysis wrong)"); return terminated ? 0 : 1; } |