diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-26 14:51:09 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-26 14:51:09 -0400 |
| commit | a674c21cd101127481ee0fe46710b03216ce7505 (patch) | |
| tree | 53df93e26487722d6efde9a90b9fd14da4cee914 /kernel | |
| parent | 928c0730f482b95cb5f27ff43f7500e191f012f4 (diff) | |
| download | open-iov-a674c21cd101127481ee0fe46710b03216ce7505.tar.gz open-iov-a674c21cd101127481ee0fe46710b03216ce7505.zip | |
vgsp-sema: SESSION 134c rank-aware CE first-submission capture - the rank-blind first-hit latched rank 0's block for rank 1
The SESSION 134 first-submission capture scanned the shadow from offset 0
and took the first ring-shaped page for EVERY CE channel. On the r779 boot
that latched rank 0's block (fb 0x80000, userd 0x90000) for rank 1 as well
(both rows scan_hits=1 latch=1 off=0x80000), so caf0001d's first release was
decoded from rank 0's ring/page (sem word +0 instead of +4) and
stale-dropped (cur=1 already from rank 0's applied release). The client's
rank-1 tracker wait never completed: victory_mail spun at 100% CPU with
pub_calls=0 on three consecutive boots (r777/r778/r779), while the r746-era
module (25523f84) passed the same run on a fresh boot (VADDs OK, STATUS OK).
Fix: try the rank's convention offset (0x80000 + 0x20000 * rank) first,
scan the rest bounded as before, and never accept an offset another CE rank
already latched this session (svc_ce_firstsub_off[], reset per session). A
rank whose block is not in the shadow at the instant stays unlatched for
the regular per-pass CE latch instead of stealing a foreign block.
Verified on r781 (fresh boot, same params xlate=1/util_scan=0/vas_cand_ms
=5000/ce_grace=20000): caf00012 rank0 -> fb 0x80000 upa 0x90000;
caf00001d rank1 -> fb 0xa0000 upa 0xb0000 (correct block, sem +4 applied:
pool-wr va=0x121000004 cur=0 -> val=1 ok); ranks 2-5 -> 0xc0000/0xe0000/
0x100000/0x120000 each +0x10000; r780 (r746 module) control run: same
client PASSED (VADD n=32768 bad=0 checksum=12204516.000000, STATUS OK);
r781 client progressed with pub_calls=185132+ (no spin stall). Also the
Vulkan client's CE channel latched via the classic autopin on r781
(beef0101 -> fb 0x80000, live entry0) - first time in the SESSION 131-134
window - confirming the latch machinery works once the wrong-block
mis-latch no longer poisons the channel.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_sema_service.c | 172 |
1 files changed, 124 insertions, 48 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 4b315f6..1b94505 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -9088,6 +9088,20 @@ static u32 svc_userd_dbg_ch[32]; static u32 svc_ce_firstsub_n[32]; static unsigned long svc_ce_hold_since[32]; /* + * SESSION 134c: the FB offset each CE rank's first-submission capture latched + * (0 = none). The shadow scan is rank-blind on its own - it takes the first + * ring-shaped page in the shadow - and on r779 that latched rank 0's block + * (fb 0x80000, userd 0x90000) for rank 1 as well (both channels reported + * scan_hits=1 latch=1 off=0x80000). The rank-1 channel's first release was + * then decoded from rank 0's ring/page and stale-dropped (cur=1 already from + * rank 0's applied release), so the client's rank-1 tracker wait never + * completed and the client spun forever (victory_mail stall, three boots). + * The capture now prefers the rank's convention offset and refuses any + * offset another CE rank already latched. Session state; reset by + * svc_session_flush. + */ +static u64 svc_ce_firstsub_off[32]; +/* * ISSUE-0002 (r47): deferred FB sweep for a CE channel whose layout USERD * probe fails at discovery. Session/reset-scoped, scheduled on the first * failure (+3 s) and re-run once more (+30 s, after the client's follow-up @@ -13101,6 +13115,7 @@ static void svc_session_flush(void) memset(svc_userd_dbg_ch, 0, sizeof(svc_userd_dbg_ch)); memset(svc_ce_firstsub_n, 0, sizeof(svc_ce_firstsub_n)); memset(svc_ce_hold_since, 0, sizeof(svc_ce_hold_since)); + memset(svc_ce_firstsub_off, 0, sizeof(svc_ce_firstsub_off)); svc_userd_sweep_log = 0; memset(svc_userd_sweep_at, 0, sizeof(svc_userd_sweep_at)); memset(svc_userd_sweep_n, 0, sizeof(svc_userd_sweep_n)); @@ -14726,6 +14741,71 @@ static u64 svc_ce_hold_ms; module_param_named(sema_ce_hold_ms, svc_ce_hold_ms, ullong, 0644); MODULE_PARM_DESC(sema_ce_hold_ms, "Hold an unlatched CE channel's completion open for up to N ms so the ring stays live for the latch (0 = off)"); +/* + * SESSION 134c rank-aware first-submission capture (see the capture below). + * The CE block convention: ring at 0x80000 + 0x20000 * rank, USERD at + * ring + 0x10000 (observed for every CE channel across boots; the same + * convention svc_chan_userd applies in its regular per-pass latch). + */ +#define SVC_CE_RING_FB_BASE 0x80000ULL +#define SVC_CE_RING_FB_STRIDE 0x20000ULL + +/* + * One candidate offset for the CE first-submission capture: validate the + * ring shape (`scan_hits` counts shape hits) and, on a shape hit, run the + * standard USERD gate at +0x10000/+0x2000/+0x1000/+0x0; a candidate whose + * USERD reads coherent (or idle 0/0) is PINNED and LATCHED exactly like + * svc_ring_autopin's CE path. Returns true when latched. + */ +static bool svc_ce_firstsub_try_off(struct nv_vgpu_device *vgpu, + struct svc_channel *ch, u8 *sbase, + u64 lim, u64 off, u32 *scan_hits, + u64 *latch_off, u64 *latch_upa, + u32 *latch_put, u32 *latch_get) +{ + static const u64 udeltas[] = { 0x10000, 0x2000, 0x1000, 0x0 }; + u32 h0, h1, hlen; + u64 hva; + unsigned int ui; + + memcpy(&h0, sbase + off, 4); + memcpy(&h1, sbase + off + 4, 4); + hva = ((u64)(h1 & 0xff) << 32) | (u64)(h0 & 0xfffffffc); + hlen = ((h1 >> 10) & 0x1fffff) << 2; + if ((hva & 0xfffff) || hva < 0x120000000ULL || + hva >= 0x121000000ULL || hlen < 4 || hlen > 0x10000) + return false; + (*scan_hits)++; + for (ui = 0; ui < ARRAY_SIZE(udeltas); ui++) { + u64 upa = off + udeltas[ui]; + u32 p3 = 0, g3 = 0; + int prc; + + if (upa + 4 > lim) + continue; + prc = svc_userd_probe(vgpu, upa, + SVC_APERTURE_FB, + ch->gpfifo_entries, + &p3, &g3); + if (prc && prc != -EAGAIN) + continue; + /* latch exactly like the CE autopin */ + svc_pin_store(ch->gpfifo_va, off, SVC_APERTURE_FB); + svc_lat_store(ch->gpfifo_va, off, SVC_APERTURE_FB); + ch->userd_pa = upa; + ch->userd_as = SVC_APERTURE_FB; + ch->userd_ok = true; + set_bit(ch->ce_index, &svc_ring_done); + svc_ring_n++; + *latch_off = off; + *latch_upa = upa; + *latch_put = p3; + *latch_get = g3; + return true; + } + return false; +} + static void svc_ce_firstsub_capture(struct nv_vgpu_device *vgpu, struct svc_channel *ch) { @@ -14770,59 +14850,57 @@ static void svc_ce_firstsub_capture(struct nv_vgpu_device *vgpu, } /* 3. shadow scan for a CE-window ring page. */ { + /* + * SESSION 134c rank-aware order: try the rank's + * convention offset first, then the bounded scan, + * and never accept an offset another CE rank already + * latched. The rank-blind first-hit latched rank 0's + * block for rank 1 on r779 (both rows read + * off=0x80000 upa=0x90000), so the rank-1 channel's + * first release decoded from rank 0's ring/page and + * was stale-dropped (cur=1 already) - the client's + * rank-1 tracker wait never completed and it spun + * forever. A rank whose block is not in the shadow + * at this instant now simply stays unlatched for the + * regular per-pass CE latch instead of stealing a + * foreign block. + */ + u64 exp = SVC_CE_RING_FB_BASE + + SVC_CE_RING_FB_STRIDE * ch->ce_index; u64 off; - for (off = 0; off + 0x90 <= lim; off += 0x100) { - static const u64 udeltas[] = { 0x10000, 0x2000, - 0x1000, 0x0 }; - u32 h0, h1; - u64 hva; - u32 hlen; - unsigned int ui; + latched = svc_ce_firstsub_try_off(vgpu, ch, sbase, + lim, exp, &scan_hits, + &latch_off, &latch_upa, + &latch_put, &latch_get); + for (off = 0; !latched && off + 0x90 <= lim; + off += 0x100) { + unsigned int ri; + bool foreign = false; - memcpy(&h0, sbase + off, 4); - memcpy(&h1, sbase + off + 4, 4); - hva = ((u64)(h1 & 0xff) << 32) | - (u64)(h0 & 0xfffffffc); - hlen = ((h1 >> 10) & 0x1fffff) << 2; - if ((hva & 0xfffff) || hva < 0x120000000ULL || - hva >= 0x121000000ULL || hlen < 4 || - hlen > 0x10000) + if (off == exp) continue; - scan_hits++; - for (ui = 0; ui < ARRAY_SIZE(udeltas); ui++) { - u64 upa = off + udeltas[ui]; - u32 p3 = 0, g3 = 0; - int prc; - - if (upa + 4 > lim) + for (ri = 0; ri < 32; ri++) { + if (ri == ch->ce_index || + !svc_ce_firstsub_off[ri]) continue; - prc = svc_userd_probe(vgpu, upa, - SVC_APERTURE_FB, - ch->gpfifo_entries, - &p3, &g3); - if (prc && prc != -EAGAIN) - continue; - /* latch exactly like the CE autopin */ - svc_pin_store(ch->gpfifo_va, off, - SVC_APERTURE_FB); - svc_lat_store(ch->gpfifo_va, off, - SVC_APERTURE_FB); - ch->userd_pa = upa; - ch->userd_as = SVC_APERTURE_FB; - ch->userd_ok = true; - set_bit(ch->ce_index, &svc_ring_done); - svc_ring_n++; - latched = 1; - latch_off = off; - latch_upa = upa; - latch_put = p3; - latch_get = g3; - break; + if (svc_ce_firstsub_off[ri] == off) { + foreign = true; + break; + } } - if (latched) - break; + if (foreign) + continue; + latched = svc_ce_firstsub_try_off(vgpu, ch, + sbase, lim, + off, &scan_hits, + &latch_off, + &latch_upa, + &latch_put, + &latch_get); } + if (latched) + svc_ce_firstsub_off[ch->ce_index] = latch_off; } } @@ -14970,8 +15048,6 @@ static void svc_notify_complete(struct nv_vgpu_device *vgpu, * against the ring's first GPFIFO entry, so a layout change costs a failed * pin, not a wrong one. */ -#define SVC_CE_RING_FB_BASE 0x80000ULL -#define SVC_CE_RING_FB_STRIDE 0x20000ULL static unsigned long svc_ring_done; /* CE ranks whose ring is pinned */ static bool svc_fbs_scan_done; /* one-shot FB entry scan diagnostic */ |
