diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-17 10:17:20 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-17 10:17:20 -0400 |
| commit | cb576f032852de09e63deeba2ac3babe3d3f1385 (patch) | |
| tree | 48133972ea112329f8484d86dd1198fda5a667a2 /kernel/gsp_sema_service.c | |
| parent | 0bb52e0e3cdc86b31dce2daa23eafd099461604a (diff) | |
| download | open-iov-cb576f032852de09e63deeba2ac3babe3d3f1385.tar.gz open-iov-cb576f032852de09e63deeba2ac3babe3d3f1385.zip | |
vgsp: m172 stall+data fixes - distinct pending releases never dropped (exact-dup dedup only; the >= dedup let bursts hold only the last payload and the guest word stopped short: evtest3 sync/streams stall class, starved=0), failed absolute releases re-queued (svc_rel_apply_launch fall-through), ledger consult on fill resolve-miss (C1: r174 cand[] probe=none operand now served from the H2D landing page), aperture-aware ledger compare (fill+D2H), ledger 2048 entries (C4: 4MiB operands no longer evicted), >=64KiB virtual fills recorded (C2: memset2d), engine write-back pages recorded (C3: atomics readback), store visibility log + pending rescue counter
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 140 |
1 files changed, 120 insertions, 20 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 95134bd..4ab450e 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -4075,6 +4075,8 @@ static bool svc_dst_watched(u64 dst) * `addr`, in vidmem or guest RAM depending on the aperture DST_TYPE * selected. Returns 0 on success. */ +static void svc_ledger_store(u64 va, u64 pa, u32 ap); /* R2 ledger, defined below */ + static int svc_fill(struct nv_vgpu_device *vgpu, u64 addr, u64 value, u32 elem, u32 count, u32 phys, u32 aperture) { @@ -4083,6 +4085,7 @@ static int svc_fill(struct nv_vgpu_device *vgpu, u64 addr, u64 value, u32 elem, size_t total = (size_t)elem * count; size_t o; bool shadow = false; + u64 va0 = addr; /* original destination VA (fills, C2) */ if (elem != 1 && elem != 2 && elem != 4 && elem != 8) return -EINVAL; @@ -4136,6 +4139,20 @@ static int svc_fill(struct nv_vgpu_device *vgpu, u64 addr, u64 value, u32 elem, memcpy(base + addr + o, pat, 8); if (o < total) memcpy(base + addr + o, pat, total - o); + /* + * C2 (data class): a large virtual fill is a write/read pair + * with the memset's readers like any H2D copy - record its + * landing pages so the fill/D2H side reads exactly what was + * filled (memset2d was fully bypassed before this). + */ + if (!phys && !shadow && va0 >= SVC_VAS_FLOOR && + total >= (64u << 10)) { + u64 po; + + for (po = 0; po < total; po += SEMA_PAGE_SIZE) + svc_ledger_store(va0 + po, addr + po, + SVC_APERTURE_FB); + } return 0; } @@ -4536,11 +4553,18 @@ struct svc_ledger_ent { u64 pa_page; u32 ap; }; -#define SVC_LEDGER_MAX 256 +/* + * C4 (stall/data class): a 4 MiB H2D is 1024 pages; the old 256 kept only + * the tail (early pages evicted before the launch fill ran). 2048 covers a + * single 4-8 MiB operand without eviction. Lookup is linear and bounded. + */ +#define SVC_LEDGER_MAX 2048 static struct svc_ledger_ent svc_ledger[SVC_LEDGER_MAX]; static u32 svc_ledger_n; static u32 svc_ledger_next; static u64 svc_ledger_diverges; +static u64 svc_ledger_stores; +static u32 svc_ledger_store_log; static void svc_ledger_store(u64 va, u64 pa, u32 ap) { @@ -4562,6 +4586,12 @@ static void svc_ledger_store(u64 va, u64 pa, u32 ap) svc_ledger[i].va_page = page; svc_ledger[i].pa_page = pa_page; svc_ledger[i].ap = ap; + svc_ledger_stores++; + if (svc_ledger_store_log < 64) { + svc_ledger_store_log++; + pr_info("sema-ledger: store va=0x%llx pa=0x%llx ap=%u n=%u\n", + page, pa_page, ap, svc_ledger_n); + } } static int svc_ledger_lookup(u64 va, u64 *pa, u32 *ap) @@ -4910,8 +4940,10 @@ static int svc_copy(struct nv_vgpu_device *vgpu, u64 dst, u64 src, size_t total, */ if (src_orig >= SVC_VAS_FLOOR && !svc_ledger_lookup(src_orig + o, &lpa, &lap) && - (lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) != - (pa & ~(u64)(SEMA_PAGE_SIZE - 1))) { + ((lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) != + (pa & ~(u64)(SEMA_PAGE_SIZE - 1)) || + (lap == SVC_APERTURE_FB) != + (aper == CE_APERTURE_VID))) { svc_ledger_diverges++; if (svc_ledger_diverges <= 32) pr_info("sema-ledger: DIVERGE read va=0x%llx wrote=0x%llx read=0x%llx\n", @@ -6111,6 +6143,16 @@ static bool svc_rel_apply_launch(struct nv_vgpu_device *vgpu, svc_counter_learn(vgpu, ch->h_object, sem_va); svc_counter_release_apply(vgpu, ch->h_object, sem_va, payload, inc && inc_apply); + /* + * Stall-class fix (R2): when the decode said this absolute release is + * genuinely pending and every write attempt above failed without + * queueing, the release must not vanish - retry it through the pending + * pass. Increments stay excluded (their one-shot claim makes + * re-queueing unsafe until a diag run proves otherwise). + */ + if (pending && !inc && !(ch->engine_type == 0 && + svc_counter_va(sem_va))) + svc_pending_add(sem_va, payload, 0); return false; } @@ -7545,16 +7587,42 @@ static struct svc_pending_release svc_pending[SVC_PENDING_MAX]; static u32 svc_pending_n; static u32 svc_pending_next; +static u64 svc_pending_rescued; /* stall-class: entries the old >= dedup would have dropped */ +static u32 svc_pending_rescued_log; + static void svc_pending_add(u64 va, u32 payload, u32 op) { u32 i; if (!payload) return; - for (i = 0; i < svc_pending_n; i++) - if (svc_pending[i].va == va && - svc_pending[i].payload >= payload) + for (i = 0; i < svc_pending_n; i++) { + if (svc_pending[i].va != va) + continue; + /* + * Stall-class fix (R1): only an EXACT duplicate may be + * dropped. The old rule dropped every release behind an + * already-queued higher payload; in a burst the queue could + * end up holding only the last value (observed: payloads 7..34 + * decoded, queue held {7,34}, the guest word stopped short of + * the waiter's value and the client spun forever with + * starved=0). Distinct releases must always queue - the apply + * pass already stale-drops values the word has passed. + */ + if (svc_pending[i].payload == payload && + svc_pending[i].op == op) return; + if (svc_pending[i].payload >= payload) { + svc_pending_rescued++; + if (svc_pending_rescued_log < 32) { + svc_pending_rescued_log++; + pr_info("sema-svc: pending rescue va=0x%llx pay=%u op=%u (queued; ahead entry pay=%u op=%u)\n", + va, payload, op, + svc_pending[i].payload, + svc_pending[i].op); + } + } + } if (svc_pending_n < SVC_PENDING_MAX) { i = svc_pending_n++; } else { @@ -12637,6 +12705,16 @@ static void svc_fwd_gr_work(void) data[gs.n_data].va = dg->va; data[gs.n_data].hpa = dhpa; data[gs.n_data].reloc_va = dg->reloc_va; + /* + * C3 (data class): after the run the backend copies this + * page's results back to dg->pa (gsp_phys_booter.c copy-out). + * Record that page as the truth for this VA so the guest's + * D2H read of an engine-authored output follows the page the + * results actually landed on, whatever a later resolver says + * (atomics: engine ran, readback read a different page). + */ + if (dg->va >= SVC_VAS_FLOOR) + svc_ledger_store(dg->va, dg->pa, dkind); gs.n_data++; } gs.data = data; @@ -13393,18 +13471,37 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu) ap = (u32)iap; } else if (svc_resolve_va(vgpu, va, &pa, &ap)) { /* - * m170 (R4a): remember that the very - * first page of this span failed to - * resolve - the fail-closed trigger - * below distinguishes it from the - * benign "0 new pages" of a span - * whose pages an earlier candidate - * already mapped. + * C1 (stall/data class): the page may + * still be readable - the ledger holds + * the landing page of the H2D that + * wrote it even when every resolver + * misses (r174 cand[] probe=none, 0 + * pages, bad=65536). Use it before + * declaring the page dead; only a page + * with no ledger entry can truncate + * the span. */ - if (p == 0 && - svc_fwd_req.gr_n_data == before) - first_unresolved = true; - break; + u64 lpa = 0; + u32 lap = 0; + + if (!svc_ledger_lookup(va, &lpa, &lap)) { + pa = lpa; + ap = lap; + } else { + /* + * m170 (R4a): the very first + * page of this span failed to + * resolve - the fail-closed + * trigger below distinguishes + * it from the benign "0 new + * pages" of a span whose + * pages were already mapped. + */ + if (p == 0 && + svc_fwd_req.gr_n_data == before) + first_unresolved = true; + break; + } } } /* @@ -13412,15 +13509,18 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu) * landing page for this operand VA when it disagrees * with the resolution - the kernel then reads exactly * the page a large H2D wrote (r174: write landed on - * pa X while the fill read a stale page Y). + * pa X while the fill read a stale page Y). Compare + * aperture-aware (a SYS page and an FB page with the + * same numeric address are not the same page). */ if (va >= SVC_VAS_FLOOR) { u64 lpa = 0; u32 lap = 0; if (!svc_ledger_lookup(va, &lpa, &lap) && - (lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) != - (pa & ~(u64)(SEMA_PAGE_SIZE - 1))) { + ((lpa & ~(u64)(SEMA_PAGE_SIZE - 1)) != + (pa & ~(u64)(SEMA_PAGE_SIZE - 1)) || + (u32)lap != (u32)ap)) { svc_ledger_diverges++; if (svc_ledger_diverges <= 32) pr_info("sema-ledger: DIVERGE fill va=0x%llx wrote=0x%llx read=0x%llx\n", |
