DF-2214 / rig_tail.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 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | /* * DF-2214 verbatim-code rig - TAIL * Matrix driver + module glue. Runs the UNMODIFIED production function * (rv770_copy_dma, concatenated above from tree lines 42-94) and the FIXED * variant (rv770_copy_dma_fixed, fix.diff applied + renamed) over the exact * input domain that flips the claimed bug and prints, per case: * - the ndw the function tried to reserve (== num_loops*5+8) * - every DMA_PACKET_COPY header emitted into the ring (count, chunk sizes) * - whether a success fence was emitted * - bytes the DMA engine was actually told to move vs bytes requested * - canary integrity around the ring buffer (host-memory-safety check) */ #define CANARY_ZONE 4096 #define CANARY_WORD 0xCAFEBABEu #define RIG_SRC_BASE 0x123456789ABCLL /* nontrivial 44-bit GPU addrs */ #define RIG_DST_BASE 0xFEDCBA987654LL struct rig_case { unsigned pages; unsigned ring_bytes; /* ring buffer geometry */ const char *ring_tag; }; static const struct rig_case rig_cases[] = { /* --- big ring (4 MiB, plenty for every reservation below) --- */ { 0x000FFFFFu, 0x400000u, "big4M" }, /* 2^20-1: last non-wrapping */ { 0x00100000u, 0x400000u, "big4M" }, /* 2^20 : exact wrap to 0 */ { 0x00100001u, 0x400000u, "big4M" }, /* 2^20+1: wraps to 4 KiB */ { 0x00100800u, 0x400000u, "big4M" }, /* 2^20+2048: wraps to 8 MiB */ { 0xC0000000u, 0x400000u, "big4M" }, /* 12 TiB request: total loss*/ /* --- realistic rv770 DMA ring: 64 KiB (rv770.c:1968) --- */ { 0x00008000u, 0x010000u, "real64K" }, /* 128 MiB move: fits, control */ { 0x000FFFFFu, 0x010000u, "real64K" }, /* 4 GiB-4K: loud ENOMEM (fixed/correct) vs silent no-op (buggy) */ { 0x00100000u, 0x010000u, "real64K" }, /* 4 GiB: the money shot */ }; static int rig_canary_ok(u32 *buf, unsigned ring_bytes) { unsigned i, words = CANARY_ZONE / 4; for (i = 0; i < words; i++) if (buf[i] != CANARY_WORD || buf[words + ring_bytes / 4 + i] != CANARY_WORD) return 0; return 1; } static void run_case(int fixed, const struct rig_case *c) { static const struct radeon_asic asic = { .copy = { .dma_ring_index = R600_RING_TYPE_DMA_INDEX }, }; struct radeon_device rdev; struct reservation_object resv; struct radeon_fence *fence; u32 *buf; unsigned i; int err = 0; u64 requested, scheduled; int canary; int is_err_ptr; memset(&rdev, 0, sizeof(rdev)); rdev.asic = &asic; lockinit(&rdev.ring_lock, "df2214lk", 0, 0); /* ring geometry per radeon_ring_init (radeon_ring.c:404-411) */ { struct radeon_ring *ring = &rdev.ring[R600_RING_TYPE_DMA_INDEX]; ring->idx = R600_RING_TYPE_DMA_INDEX; ring->ring_size = c->ring_bytes; ring->ptr_mask = (ring->ring_size / 4) - 1; ring->ring_free_dw = ring->ring_size / 4; ring->align_mask = 0; /* boundary state: no commit padding */ ring->ready = 1; } /* ring buffer bracketed by canary zones */ buf = kmalloc(c->ring_bytes + 2 * CANARY_ZONE, M_TEMP, M_WAITOK | M_ZERO); for (i = 0; i < CANARY_ZONE / 4; i++) { buf[i] = CANARY_WORD; buf[CANARY_ZONE / 4 + c->ring_bytes / 4 + i] = CANARY_WORD; } rdev.ring[R600_RING_TYPE_DMA_INDEX].ring = buf + CANARY_ZONE / 4; memset(&g_stats, 0, sizeof(g_stats)); g_stats.min_chunk = 0xFFFFFFFFu; g_stats.max_chunk = 0; requested = (u64)c->pages << RADEON_GPU_PAGE_SHIFT; /* rig-side 64-bit truth */ if (fixed) fence = rv770_copy_dma_fixed(&rdev, RIG_SRC_BASE, RIG_DST_BASE, c->pages, &resv); else fence = rv770_copy_dma(&rdev, RIG_SRC_BASE, RIG_DST_BASE, c->pages, &resv); is_err_ptr = IS_ERR(fence); if (is_err_ptr) err = (int)(intptr_t)fence; scheduled = g_stats.sum_chunk_dw * 4; canary = rig_canary_ok(buf, c->ring_bytes); kprintf("DF2214 CASE variant=%s pages=0x%08x ring=%s(%u bytes)\n", fixed ? "FIXED" : "BASELINE", c->pages, c->ring_tag, c->ring_bytes); kprintf("DF2214 requested_bytes=%llu (0x%llx) attempted_ndw=%u lock_rc=%d\n", (unsigned long long)requested, (unsigned long long)requested, g_stats.attempted_ndw, g_stats.lock_rc); if (is_err_ptr) { kprintf("DF2214 ERR_PTR(%d): ring reservation refused, ZERO packets, NO fence - loud failure\n", err); kprintf("DF2214 VERDICT: ERR_PTR_FAIL\n"); } else { unsigned loops = g_stats.attempted_ndw ? (g_stats.attempted_ndw - 8) / 5 : 0; kprintf("DF2214 num_loops=%u copy_packets=%u sum_chunk_dw=%llu max_chunk=%u min_chunk=%u ring_writes=%lu\n", loops, g_stats.copy_packets, (unsigned long long)g_stats.sum_chunk_dw, g_stats.max_chunk, g_stats.min_chunk, g_stats.writes); kprintf("DF2214 first_pkt=0x%08x (cmd=%u n=%u) first5=[%08x %08x %08x %08x %08x]\n", g_stats.first_pkt, (g_stats.first_pkt >> 28) & 0xF, g_stats.first_pkt & 0xFFFF, g_stats.first5[0], g_stats.first5[1], g_stats.first5[2], g_stats.first5[3], g_stats.first5[4]); kprintf("DF2214 scheduled_bytes=%llu (%lu.%04lu%% of request) fence_emitted=%d ring=%d seq=%llu\n", (unsigned long long)scheduled, (unsigned long)(scheduled * 100 / (requested ? requested : 1)), (unsigned long)((scheduled * 1000000 / (requested ? requested : 1)) % 10000), g_stats.fence_emits, g_stats.fence_ring, (unsigned long long)g_stats.fence_seq); kprintf("DF2214 integrity: canaries=%s count_dw_final=%d underruns=%d drm_errors=%d sync{c=%d r=%d g=%d f=%d} commit=%u\n", canary ? "INTACT" : "CLOBBERED", rdev.ring[R600_RING_TYPE_DMA_INDEX].count_dw, g_stats.underruns, g_stats.drm_errors, g_stats.sync_create, g_stats.sync_resv, g_stats.sync_rings, g_stats.sync_free, g_stats.committed); if (scheduled == requested) kprintf("DF2214 VERDICT: FULL_COPY\n"); else if (g_stats.fence_emits) kprintf("DF2214 VERDICT: SILENT_TRUNCATION (fence says success, %llu of %llu bytes scheduled)\n", (unsigned long long)scheduled, (unsigned long long)requested); else kprintf("DF2214 VERDICT: INTERNAL_ERROR\n"); } if (!is_err_ptr && fence) kfree(fence, M_TEMP); kfree(buf, M_TEMP); lockuninit(&rdev.ring_lock); } static void rig_matrix(void) { size_t i; kprintf("DF2214 RIG start: kernel-resident verbatim rv770_copy_dma (baseline) + fix.diff variant\n"); for (i = 0; i < sizeof(rig_cases) / sizeof(rig_cases[0]); i++) run_case(0, &rig_cases[i]); for (i = 0; i < sizeof(rig_cases) / sizeof(rig_cases[0]); i++) run_case(1, &rig_cases[i]); kprintf("DF2214 RIG done\n"); } static int df2214_modevent(module_t mod, int type, void *arg) { switch (type) { case MOD_LOAD: rig_matrix(); return 0; case MOD_UNLOAD: return 0; default: return EOPNOTSUPP; } } static moduledata_t df2214_mod = { "df2214_rig", df2214_modevent, NULL }; DECLARE_MODULE(df2214_rig, df2214_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_VERSION(df2214_rig, 1); |