DF-5223 / sim_accounting.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | /* * DF-5223 sim_accounting.c — static arithmetic simulator of the radeon * DMA-ring dword accounting for rv770_copy_dma() (sys/dev/drm/radeon/rv770_dma.c). * * It mirrors, 1:1, the kernel semantics: * * radeon_ring_alloc() [radeon_ring.c:106-131]: * ndw = (ndw + ring->align_mask) & ~ring->align_mask; // :114 * ... * ring->count_dw = ndw; // :124 * (alloc loop guarantees ring_free_dw - 1 >= ndw at reservation time) * * radeon_ring_write() [radeon.h:2708-2716]: * if (ring->count_dw <= 0) * DRM_ERROR("radeon: writing more dwords to the ring than expected!"); * ring->ring[ring->wptr++] = v; // written ANYWAY * ring->wptr &= ring->ptr_mask; * ring->count_dw--; * * radeon_ring_commit() [radeon_ring.c:157-185]: * while (ring->wptr & ring->align_mask) * radeon_ring_write(ring, ring->nop); // :173 * * rv770_copy_dma() consumers on the R600 DMA ring (rv770_dma.c:59-91): * - S semaphore-wait packets emitted by radeon_sync_rings() * [radeon_sync.c:187 -> r600_dma_semaphore_ring_emit, r600_dma.c:319-321] * = 3 dwords each; on RV770 the possible source rings are GFX and UVD * (same-ring fences excluded, radeon_fence.c:768-770) => S in {0,1,2}, * built from resv excl + shared-list fences (radeon_sync_resv, * radeon_sync.c:101-123; shared fences added for read-only relocations, * radeon_cs.c:182 + ttm_execbuf_util.c:203-206). * - num_loops copy packets = 5 dwords each (rv770_dma.c:74-78). * - fence emit = 5 dwords (r600_dma_fence_ring_emit, r600_dma.c:292-297). * * Reservation: radeon_ring_lock(rdev, ring, num_loops * 5 + 8) [rv770_dma.c:59]. * align_mask for the DMA ring is 16-1 (r600.c:2798). wptr at lock time is * 16-aligned because every prior commit padded it (radeon_ring.c:173). * * The simulator prints every (S, L) combination for which writes exceed the * reserved window — i.e. exactly the conditions in which the kernel emits * dwords past its reserved ring window (DRM_ERROR + wptr advancing past the * region the alloc-loop guaranteed free; if the ring was at its minimum free * space (reserved+1), wptr overtakes rptr and un-executed GPU commands from * previously committed work get overwritten). */ #include <stdio.h> int main(void) { const unsigned ALIGN_MASK = 16 - 1; /* r600.c:2798 (DMA ring) */ const unsigned PTR_MASK = 0xFFFFFu; /* big enough: no wrap in spans modeled */ int hits = 0; printf("DF-5223: rv770_copy_dma DMA-ring accounting simulation\n"); printf("reserve = num_loops*5 + 8 (rv770_dma.c:59)\n"); printf("consumers= 3*S semaphore waits (radeon_sync.c:187, r600_dma.c:319-321)\n"); printf(" + 5*num_loops copy dwords (rv770_dma.c:74-78)\n"); printf(" + 5 fence dwords (r600_dma.c:292-297)\n"); printf(" + commit nop padding to 16 (radeon_ring.c:173)\n\n"); for (int S = 0; S <= 2; S++) { for (int L = 1; L <= 64; L++) { unsigned req = (unsigned)L * 5 + 8; /* rv770_dma.c:59 */ unsigned res = (req + ALIGN_MASK) & ~ALIGN_MASK; /* radeon_ring.c:114 */ int count_dw = (int)res; /* radeon_ring.c:124 */ unsigned wptr = 0; /* 16-aligned: prior commit padded */ unsigned over = 0; unsigned consumed = 0; for (int i = 0; i < S; i++) /* semaphore waits */ for (int j = 0; j < 3; j++) { if (count_dw <= 0) over++; count_dw--; consumed++; wptr = (wptr + 1) & PTR_MASK; } for (int i = 0; i < L; i++) /* copy packets */ for (int j = 0; j < 5; j++) { if (count_dw <= 0) over++; count_dw--; consumed++; wptr = (wptr + 1) & PTR_MASK; } for (int j = 0; j < 5; j++) { /* fence emit */ if (count_dw <= 0) over++; count_dw--; consumed++; wptr = (wptr + 1) & PTR_MASK; } while (wptr & ALIGN_MASK) { /* commit pad */ if (count_dw <= 0) over++; count_dw--; consumed++; wptr = (wptr + 1) & PTR_MASK; } if (over) { printf("DEFICIT: S=%d num_loops=%-3d reserved=%-4u " "consumed=%-4u overflow=%u dwords past reserved window" " (DRM_ERROR; wptr may overtake rptr)\n", S, L, res, consumed, over); hits++; } } } printf("\n%d (S,L) combinations overflow the reservation.\n", hits); printf("%s\n", hits ? "DEFICIT CONFIRMED (static arithmetic; hardware-gated runtime)" : "no deficit found"); return hits ? 1 : 0; } |