diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-19 10:20:17 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-19 10:21:03 -0400 |
| commit | a9ad97f0a2342fe821d682d463d85dd8add9d360 (patch) | |
| tree | 88f886aa8f7597affafdd7c4e84728d5820e9956 /kernel | |
| parent | fc203ded15863dc343442b7bb5fd0c796c5af503 (diff) | |
| download | open-iov-a9ad97f0a2342fe821d682d463d85dd8add9d360.tar.gz open-iov-a9ad97f0a2342fe821d682d463d85dd8add9d360.zip | |
vgsp: fail4 r249-r252 - GRCE slot-run rule + arg-rec order fix; probe fully green
Two fixes on top of c66a0172:
1. Slot rule for LOAD_INLINE_DATA runs: in the UVM upload pushes
each run fills a whole 32 KB slot - its data runs to the next
run header (or to the next 0x8000 boundary for the last run),
regardless of the count field (observed slot starts every
0x8000: cnt=4095 and cnt=2497/2753 variants). Compact pushes
keep the count*4 reading. The old reading truncated each slot
run to half its data and walked the tail as methods.
2. Argument-ring order: the bridge's arg-block search must see the
run's START as the inline-write destination; the new cursor
advance must not leak into rec->dst_va (an end-of-run dst_va
made the QMD param patch miss and the engine never consumed the
launch - regression found and bisected against the pre-session
ko via victory_mail).
Verified one boot (r251/r252, standard params): ctaid_probe RAWA
0 1 2 3 4 5 6 7 + last8 16376..16383, PROBE1/PROBE2/PROBE2B bad=0;
transformer STATUS OK; victory_mail STATUS OK.
Residual (distinct class, NOT the H2D delivery): streams2
bad=65534, memcpy_roundtrip bad=8388608, victory_multikernel
bad=2883066. Their big spans collapse to a single rec/bank entry in
the launch tables ('bank 0 hit @0x168: VA -> reloc' for one page of
the span) and the engine write-back replicates one page across the
span (OUT-ALIAS-WIT partners) - the original span-aliasing class on
the large-buffer paths.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 66 |
1 files changed, 59 insertions, 7 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index a5b1d93..6dd83c9 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -7504,11 +7504,58 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, */ if (op == 3 && subch == 1 && addr == GRCE_M_LOAD_INLINE_DATA && count && off + 4 + count * 4 <= len) { + /* + * fail4 slot rule: in the UVM upload pushes each + * LOAD_INLINE_DATA run fills a whole 32 KB slot - its + * data runs from the header to the next run header + * (or to the next 0x8000 boundary when this is the + * last run), regardless of the count field. A compact + * push (no room for a following slot) keeps the + * count*4 reading (the small parameter banks). The + * old count*4 reading truncated the big runs to half + * their slot and left the tail to be misparsed as + * methods (the split-upload bug). + */ + bool slot_run = (off + 0x8000 < len); + u32 slot_end = off + 0x8000; + u32 slot_bytes = 0; + /* + * fail4: the bridge's argument-block search needs the + * run's START as its destination; the cursor advance + * below must not leak into the rec (an end-of-run + * dst_va makes the QMD param patch miss and the + * engine never consumes the launch). + */ + u64 run_dst = st.offset_out; + + if (slot_run) { + u32 p; + + for (p = off + 4 + count * 4; + p + 4 <= slot_end && p + 4 <= len; p += 4) { + u32 h2; + + memcpy(&h2, buf + p, 4); + if (((h2 >> 29) & 0x7) == 3 && + ((h2 >> 13) & 0x7) == 1 && + ((h2 & 0x1fff) << 2) == + GRCE_M_LOAD_INLINE_DATA && + ((h2 >> 16) & 0xfff)) { + slot_end = p; + break; + } + } + slot_bytes = slot_end - (off + 4); + if (slot_bytes > 0x8000 - 4) + slot_bytes = 0x8000 - 4; + } if ((trusted || allow_ops) && !gsp_sema_skip_ops && st.have_out && st.line_length) { - u32 bytes = st.line_length * - (st.gr_line_count ? st.gr_line_count : 1); - u32 have = count * 4; + u32 bytes = slot_run ? slot_bytes : + st.line_length * + (st.gr_line_count ? + st.gr_line_count : 1); + u32 have = slot_run ? slot_bytes : count * 4; if (bytes > have) bytes = have; @@ -7557,18 +7604,23 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf, * kernel arguments in the QMD parameter bank, and the * destination VA may not be readable later. */ - if (st.have_out && st.offset_out) { + if (st.have_out && run_dst) { struct svc_grce_rec *rec = &svc_grce_dst_ring[svc_grce_dst_ring_next % SVC_GRCE_DST_MAX]; - rec->dst_va = st.offset_out; - rec->len = min_t(u32, count * 4, + rec->dst_va = run_dst; + rec->len = min_t(u32, + slot_run ? slot_bytes : count * 4, GSP_BRIDGE_INLINE_BYTES); memcpy(rec->data, buf + off + 4, rec->len); svc_grce_dst_ring_next++; } - off += 4 + count * 4; + /* + * fail4 slot rule: hop to the next slot's run header + * instead of walking the slot's raw tail as methods. + */ + off += slot_run ? (slot_end - off) : 4 + count * 4; continue; } |
