diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 10:59:09 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-23 10:59:09 -0400 |
| commit | be544f65b93095a8713256490edfc90299a173f3 (patch) | |
| tree | a87ea4d01f6dbc15362b194dbfa77872a2d180cc /kernel | |
| parent | cf80189b7e893bdc38d1e1dae122e0bbbb2d3295 (diff) | |
| download | open-iov-be544f65b93095a8713256490edfc90299a173f3.tar.gz open-iov-be544f65b93095a8713256490edfc90299a173f3.zip | |
vgsp-sema r543: hold a GR forward with a partially-resolved argument set (bounded)
The r542 matmul failure was the NOWRITE wedge: the fill resolved 969 pages
but 2 of 13 high argument bases resolved 0 pages; with
gsp_phys_gr_fill_hold=0 the fill is log-only for dropped pages and only the
aggregate all-arguments-unresolved rule holds, so the launch forwarded, the
engine fetched the QMD (qmd_rel=0x600df00d, engine fetch OK) and wrote
nothing (retirement wait 0/1032, NOWRITE-AMBIGUOUS fe_esr=0x80000000,
trap=0x80010250); the client read zeros (MATMUL bad=65536 csum=0).
Fix: the fill now records gr_arg_partial when an ARGUMENT candidate page
was dropped while other arguments resolved. svc_gr_request defers such a
launch once per push VA (SVC_GR_ARG_DEFER_MS window, svc_gr_arg_defer_ok
latch) through the existing bounded busy-defer retry, so the pins can land
before the engine reads the operands. A genuinely junk pointer word pays
the window once per push, not per retry; after the window the historical
forward stands, so the guard can only delay a launch, never hang it.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index af2d056..c575379 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -1108,6 +1108,9 @@ struct sema_svc { u64 fwd_gr_dstpend; /* r541: held for an unexecuted * device write on a data page */ u32 fwd_gr_dstpend_log; + u64 fwd_gr_argdefer; /* r543: held for a partial + * argument set (unresolved arg) */ + u32 fwd_gr_argdefer_log; u64 fwd_gr_timeout; u64 fwd_gr_fault; u64 fwd_gr_bridge; @@ -16619,6 +16622,14 @@ struct svc_fwd_req { u32 gr_dropped; /* GRFIX: pages the fill's last pass could not * resolve (0 = launch fully resolved); read * by the absolute-bound expiry log */ + bool gr_arg_partial; /* r543: an ARGUMENT pointer resolved 0 + * pages while other arguments resolved - the + * launch would run with a stale/zero operand + * (the r542 matmul NOWRITE wedge: fe_esr= + * 0x80000000, engine fetch OK, wrote 0, + * client read zeros). The request path holds + * such a launch once per push VA through the + * bounded busy-defer retry. */ u64 gr_push_va; u32 gr_push_len; u32 gr_push_n; @@ -19724,6 +19735,7 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu, svc_fwd_req.gr_n_data = 0; svc_fwd_req.gr_dropped = 0; + svc_fwd_req.gr_arg_partial = false; svc_fwd_req.gr_n_data_wins = 0; svc_gr_data_stalled = false; memset(is_arg, 0, sizeof(is_arg)); @@ -20055,6 +20067,8 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu, * page). */ svc_log_stalled_va(va); + if (is_arg[w]) + svc_fwd_req.gr_arg_partial = true; if (dropped_pages < 4) { drop_va[dropped_pages] = va; drop_kind[dropped_pages] = @@ -20493,6 +20507,30 @@ static void svc_gr_req_bridge_fallback(struct nv_vgpu_device *vgpu) static void svc_handle_map_add(void); /* + * r543: one bounded deferral per push VA for a partially-resolved argument + * set (see svc_fwd_req.gr_arg_partial). The latch keeps a genuine junk + * pointer word from adding a retry window to every launch: the first time a + * push is seen with a partial argument set it is deferred (pins land within + * ~1-2 s in the healthy case); the same push VA seen again inside the + * window proceeds through the historical forward. A re-used ring slot after + * the window gets its own deferral. + */ +#define SVC_GR_ARG_DEFER_MS 30000u +static u64 svc_gr_arg_last_va; +static unsigned long svc_gr_arg_last_j; + +static bool svc_gr_arg_defer_ok(u64 push_va) +{ + if (push_va == svc_gr_arg_last_va && + time_before(jiffies, svc_gr_arg_last_j + + msecs_to_jiffies(SVC_GR_ARG_DEFER_MS))) + return false; + svc_gr_arg_last_va = push_va; + svc_gr_arg_last_j = jiffies; + return true; +} + +/* * r541: does any of the filled launch's data pages carry an unexecuted * device write (see svc_dstpend_note)? Runs on the service thread right * after the fill, so svc_fwd_req.gr_data holds this launch's records. @@ -20631,6 +20669,33 @@ static bool svc_gr_request(struct nv_vgpu_device *vgpu, return false; } /* + * r543: a partially-resolved ARGUMENT set must not forward either - + * the engine would run with a stale/zero operand (the r542 matmul + * wedge: 2 of 13 high arg bases resolved 0 pages, the fill proceeded + * "fill hold disabled (log-only)", the engine fetched the QMD and + * wrote nothing: NOWRITE-AMBIGUOUS fe_esr=0x80000000, client read + * zeros). Defer once per push VA through the bounded busy-defer + * retry so the pins can land; the latch (svc_gr_arg_defer_ok) keeps + * a genuinely junk pointer word from paying the window on every + * launch. After the retry the historical forward stands - the guard + * delays, it cannot hang. + */ + if (svc_fwd_req.gr_arg_partial && !svc_gr_data_stalled && + svc_gr_arg_defer_ok(svc_gr_cand.push_va)) { + clear_bit_unlock(SVC_FWD_INFLIGHT, &svc_fwd_state); + mutex_unlock(&svc_fwd_lock); + svc_gr_busy_defer = true; + svc.fwd_gr_refused++; + svc.fwd_gr_argdefer++; + if (svc.fwd_gr_argdefer_log < 32) { + svc.fwd_gr_argdefer_log++; + pr_info("vgsp-work: GR forward deferred h=0x%x push=0x%llx (partial argument set: %u page(s) unresolved; bounded retry)\n", + ch->h_object, svc_gr_cand.push_va, + svc_fwd_req.gr_dropped); + } + return false; + } + /* * m150: the fill found high argument pointers that no source can * translate (the second-client zeros class). Do NOT forward a launch * whose kernel would dereference unresolved pointers: leave the |
