| Commit message (Collapse) | Author | Age |
| |
|
|
|
|
|
|
|
|
|
|
|
| |
r565 evidence: the fill dropped 4 argument bases (GRFILL-DROP), RDW showed
nrecs=2 where healthy launches run 968-969, the launch was still submitted
and the backend timed out after ~19 s (GR forward failed rc=-110); the
tail then authored the software release and the client kept spinning on a
completion for a kernel that never ran - 20 s of backend occupancy plus a
false completion, and a plausible wedge source for the following clients.
gsp_phys_gr_submit now refuses n_data < GSP_PHYS_GR_MIN_DATA_RECS (16)
with a loud line, failing fast into the same software-completion fallback
without touching the engine.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
cumulative counters
r566 evidence: the dump fired 4x with done=8929 and opdef=215/7/5 frozen
while the ring was EMPTY (every channel last_get == put - the clients were
waiting, no entry pending) and the forced flush had nothing to deliver:
is a lifetime counter (215 holds applied/expired long ago),
not proof of a current hold. A real stall has either a pending translation
(svc_pending_n) or an ACTIVE opdef slot with releases recorded
(e->active && e->n); the dump (and with it the self-heal arm) now requires
one of those. The r564-class true stalls (active slots holding releases)
still dump and still heal.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
opdef flush + per-channel state)
r564 evidence: the STALL-DUMPs fired (4x, done=12700 held=727 frozen) but
ZERO STALL-HEAL lines - the force-consume budget never engaged because the
walk breaks BEFORE the instrumented hold sites (the cheap-wait unread
window at the loop top, or a stale GR hold/nocap index). The self-heal now
acts on the state every break site consults:
- svc_opdef_force_flush(): deliver every withheld release forward-only,
record the delivered marks (so a re-decode cannot re-hold), clear the
slots - the same edge the 3 s bound would run, at the watchdog's
discretion;
- per channel (under chan_lock): unread_va/unread_until = 0 (the
cheap-wait break), gr_hold_idx/gr_hold_until/gr_nocap_idx/gr_nocap_va
reset;
- the force-consume budget stays as the belt for the hold sites.
One loud STALL-HEAL line per firing.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
progress)
Every remaining frozen-pump shape (r562: STALL-DUMP no entry consumed for
20 s, held=99 opdef=150/11/3 frozen, pool_dual=0 conflicts=1) has the same
end state: some hold condition keeps winning and the walk breaks on the
same entry forever, whichever hole was closed last (r548..r558 each closed
one). Add the single backstop that cannot be out-run: when the r539 stall
watchdog fires (20 s without consuming a GPFIFO entry while withheld work
exists), arm a budget of 4 forced consumes; the next hold decisions that
would park an entry are bypassed (opdef hold, no-capture hold, busy-defer
re-hold, data-stalled hold), the entry is consumed with its withheld
releases applied forward-only and the GR QMD completion authored by the
existing tail, and the client's wait advances.
Bounded by the dump cadence (<=4/boot) and the per-arming budget, so a
healthy boot never sees it; each bypass logs one STALL-HEAL line. This
turns 'the client stalls forever' into 'the client completes with the
best-effort data the guards would have fallen back to anyway'.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
walk)
r559 soak2 evidence (victory_saxpy, 167 s at 100% CPU, module alive and
printing stats but consuming no GPFIFO entries): the guest pin stream
flooded the injection queue (svc_handle_map_add: 1867-6101 callbacks
suppressed per burst, several bursts per 10 s) and the unbounded for(;;)
drain spent every service pass processing injections, so the ring walk
never ran - work_guard counters froze (deferred=513 applied=50 unchanged
for minutes) and the client spun.
Process at most 64 queued requests per svc_handle_map_add() call. The
drain runs again on every service pass and from svc_gr_request/
svc_run_ops, so nothing is lost; under a flood the ring walk now gets its
cycles every pass. Bounded batches are the same fairness rule the ring
walk itself already uses.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
r557 STALL-DUMP evidence (victory_matmul): "no GPFIFO entry consumed for
20s" repeated while opdef=3880/16/64 and held=155 climbed - the pump
froze on one held entry whose operand never resolved, re-holding it every
pass. The opdef hold was the only pump hold path without the absolute
per-launch-VA bound (svc_gr_hold_bound_expired, the r509 one-shot used by
every GR hold path); it could therefore extend indefinitely through
fresh slot allocations even though each individual slot window is 3 s.
Consult the same absolute bound before holding: once it fires the entry
flushes its withheld releases and is consumed, so no operand-pending entry
can freeze the pump's entry loop.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
r553/r555 boots still show clients walking the individual defer/hold
bounds for 400+ s: victory_reduce 430 s (same push VA re-deferred every
pass, r554's 64-slot latch), victory_saxpy 254 s at write time with
work_guard deferred climbing by the thousand. Each guard is bounded on
its own, but their bounds interact and re-arm across re-decode passes.
Arm an ABSOLUTE per-push-VA deadline on first sighting (64-slot table);
once 15 s have passed, svc_gr_defer_expired() returns true and every defer
site forwards best-effort: the r541 dstpend guard, the r543 arg-partial
guard and the m150 data-stalled hold. 15 s sits far above the 0.5-2 s pin
latency the deferrals exist to cover and far below every client-side
timeout (>= 60 s), so the pin-late cases keep their window and no launch
can be parked longer than the cap, whichever guard keeps winning.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
r553 soak evidence (victory_reduce, 430 s stall, 0 hangs): the same launch
push VA (0x20043be64) was deferred on every pass for 7+ minutes ("partial
argument set: 7-8 pages unresolved"). A client's UVM pool allocates ~8-10
channels and each command buffer reuses two launch push slots, so more
than 8 distinct push VAs rotate through the guard; with 8 latch slots each
new VA evicted another and the one-deferral-per-VA guarantee thrashed -
the second sighting of any VA found its record gone and deferred again,
so a partial argument set that never resolves held the launch forever.
64 slots cover a full client with margin (1 KB of static state).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
r551 soak evidence (victory_strided, same boot as a green battery): the
client's init copies keep failing -ENOENT and are retried by the pump;
every retry re-noted its destination page and re-freshened the r541
dstpend record, so svc_gr_dstpend_overlap() never lapsed and the launch
guard deferred the launch forever: "GR busy-defer timeout -> hold
8000 ms" every ~4 s for 427 s, zero GR LAUNCH submitted, client at 100%
CPU.
Stamp a page's record once per failure episode: an existing record inside
its 10 s window is not re-stamped (the window stays absolute from the first
unexecuted write); an expired record is re-stamped for a genuinely new
episode. The launch then forwards best-effort at the bound exactly as the
guard's own comment promises ("bounded by the same busy-defer + gr_hold
machinery ... it can never hang the launch").
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
651 ms)
Measured A/B on real boots (same module, same client set, only
gsp_phys_gr_settle_ms varied):
- r549 (default 300): 32 launches, min 862 / p50 1119 / p90 2363 ms;
retire wait 680-901 ms per launch ("(settled)", 1..64 of 1000+
tracked pages changed).
- r551 (100): 22 launches, min 476 / p50 651.5 / p90 1010 / max 1428 ms;
retire wait 231-247 ms. Battery 12/15, 0 hangs (unchanged profile;
the 3 fails are the streams2/streams_events/memset2d readback class).
Why the wait was the dominant cost: a read-mostly kernel writes far fewer
pages than the launch's tracked set, so the "changed >= n_all" shortcut
never fires and every launch settles through the content-stable rule,
which paid the full window plus scan overhead. The stability verdict is
still hash-gated (m180); only the minimum stable duration shrinks, and
the battery correctness profile is unchanged. 300 remains available
through the module parameter.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
re-hold cycle)
r550 evidence (victory_strided, reused CE channel 0x5c000059, init sequence
with ~40 device-aperture fills whose walk fails -ENOENT): the sweep
delivered each entry's withheld counter release every ~3 s and cleared the
slot, the pump re-decoded the still-parked entry, svc_opdef_release
recorded a FRESH slot and held it again - SWEEP-EXPIRED repeated six times
for the same entry (entries 41..43 at ~18-21 s each) before
OPDEF-EXPIRED consumed it; the client span at 100% CPU for 12+ min and the
battery timed out (r549's 3 s bound alone only shrank, did not remove, the
cycle).
Remember every delivered release by (channel, entry, va, payload) in a
bounded 256-slot / 60 s ring:
- svc_opdef_release: a re-decode of an already-delivered release claims
it (rel_seen bookkeeping stays correct) and does NOT re-record or hold;
- svc_opdef_hold: an entry with any recent delivery is consumed, never
held again;
- svc_opdef_flush / expire_sweep record what they deliver;
- the ring is per-session (svc_session_flush), because handles, ring slots
and payload sequences are reused by the next client.
Releases are monotonic completion signals and every delivery path is
forward-only, so re-applying one is a no-op - the change cannot double
anything, it only removes the re-hold.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
opfail window)
r548 evidence (matmul, reused channel handle 0x5c000059 after the previous
client exited): the new client's init sequence carries ~65 small
device-destination ops whose operands no resolver covers (memcopy/memset
rc=-2, SVC_VAS_FLOOR destinations like 0x2000c0100). Each one armed the
opdef hold, expired after exactly 10 s (OPDEF-EXPIRED idx 7..18 at ~10.5 s
spacing) and only then released the counter increment the client waits on:
the pump walked one entry per 10 s while the client spun at 100 % CPU
(12+ min, battery timeout).
The two bounds were both 10000 ms. Ops that DO resolve show 0.5-2 s pin
latency (SVC_OPDEF_HOLD_MS comment), so 3000 ms keeps the m163 guarantee
(a failed device copy still gets its retry once the pins land) and the
op-failure latch now fires on the first 3 s retry instead of a second
10 s window. Both are pure bounds - no path loses its retry.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
saxpy stall)
Live evidence (r547, 16+ min stuck victory_saxpy): both launches were
captured, deferred by the r541 (unexecuted device write) and r543
(partial argument set) guards, and left as unoffered candidates - then
every later pass re-decoded the entries as replays (LAUNCH-SKIP;
already captured=1) and the consume path dropped them with no GR LAUNCH
and no GR-COMPLETE-SW for the client, whose cudaDeviceSynchronize waited
forever (client-side strace: RM-control poll loop, libcuda condvar
500 ms retimer; host log: consume idx=105/106 every ~2 s, releases never
authored for rel=0x204827f7c).
Three coordinated changes:
- svc_gr_arg_defer_ok: per-VA latch table (8 slots) instead of a single
slot. Two interleaved launches made the single slot ping-pong (each
call saw the other VA and re-deferred both forever); each VA now gets
exactly one deferral inside the 30 s window and the next sighting
proceeds, so the guard delays without ever hanging.
- svc_decode_stream: a fresh decode pass no longer wipes a valid,
never-offered candidate (a deferred forward is not stale). The
capture path already rotates to a free candidate-ring slot.
- pump no-capture hold: fires for a REPLAY whose push VA still has an
unoffered candidate in the ring (owed forward), forcing a fresh
capture + request per bounded window; and when the window expires
with the forward still owed, svc_gr_owed_resolve authors the QMD
completion release from that candidate and marks it consumed, so an
entry is never consumed without a completion (no late double-run).
New counter gr_owed in the sema-svc drain line; hold log carries owed=.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Live root cause of the smiley/streams2/streams_events readback lottery
(r539): smiley pass 2 verified a2 + b1 and pass 4 verified a4 + b2 - each
even pass's launch read the PREVIOUS even pass's b page. The b H2D's
release completed the client's synchronous cudaMemcpy while the copy op
itself was still held (b's svc_copy executed at 294026.818; launch 2's
engine read at ~294026.3), so the client legitimately submitted the launch
against a shadow page the H2D had not written yet. Passes 1/3 looked
'correct' only because passes 2 and 3 share the same b formula.
Fix, as recommended in CONT.100/94: a device-dst copy/fill that fails to
execute this pass (rc=-ENOENT) records its destination VA page in
svc_dstpend[] with a 10 s stamp. svc_gr_request, right after the fill and
before any submit, checks the launch's filled data pages against the
table (svc_gr_dstpend_overlap); a hit returns the busy-defer verdict, so
the pump holds the entry in its bounded retry window and re-captures once
the copy has run - the record clears on the copy's success. The 10 s
window restores the historical forward when the copy never lands, so the
guard can only delay a launch, never hang it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The r539 boot showed the 5-minute device-init stall class live: a GRCE
channel push (eng=0) carrying an H2D copy is decoded before the pin stream
reaches its operands, so allow_ops=0 and the copy is denied; the r308 path
sets op_tr_pending and holds the entry. That path is capped at 4 tries per
slot ('so a slot whose trust never arrives cannot wedge the channel'), but
once the cap is hit op_tr_pending stays 0 and svc_decode_stream's tail
marks the slot COMPLETE - so every later pass classifies the entry as a
replay and suppresses the copy forever. The pin arrives seconds later; the
copy still never runs and the client spins at DEVICE until UVM's own
retry. Evidence (r539, /tmp/opencode/r539-live.log): held idx 89/91..94 on
h=0x5c000059 with 'denied ... replay=1 trusted=1' and 'sema-pend: hold
... idx=89' for minutes while the client printed DEVICE.
Fix: new svc.op_owed flag. When the pend cap blocks the retry, the pass is
marked owed so slot_ops_complete stays 0; the next fresh pass runs the
copy as soon as the translation/injection exists. No hold is armed for an
owed pass, so an operand that never translates still cannot wedge the
pump (the denied path's liveness guarantee is preserved - only the
freshness is).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
watchdog
The init-stall boots (r530-r538) share one shape: the pump loops but the
entry loop stops consuming, and a client spins in uvm channel_pool_add ->
uvm_push_end_and_wait while its pool tracker word is frozen. The r538 live
boot showed the cause live: va=0x121000000 flapped between the injected pin
(the guest kernel's tracker->page->rm_mem chain) and the host GMMU walk on
every resolve (pool-boot conflict ping-pong, ~50/s), and the release write
follows whichever source answered that pass - a release written to the
losing page strands the client that polls the other one.
Fix: svc_pool_boot_store keeps BOTH most-recent distinct pages (primary +
secondary, each with its own proof stamp). svc_pool_boot_fanout applies
every successful pool release to the secondary as well (forward-only,
read-back proven, 10 s freshness so a freed/reused page is never written).
Wired into all three svc_sem_write success paths and svc_fake_release's
recovery write. The r536 walk-over-pin preference stays as the primary
choice; the pin is now recorded as the secondary there.
Also: STALL-DUMP - when the entry loop consumes no entry for 20 s while
withheld work exists (pending releases or opdef slots), dump the pending
list, opdef slots, pool candidates and counters once (bounded 4/boot), so
the next stall is named in one place instead of N bounded logs.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The VAS candidate verification needs the client's ring to be found by the
RAM content scan; on a boot where that never anchors the ring the
candidate stays parked forever and every launch operand walk fails rc=-2
(observed: pd_found=0, vas[0] holding an internal pdb, walks stuck at
9555 successes with 114 K attempts while the client spun for minutes).
After 15 s parked, register the candidate unverified with a loud log: it
came from the client's own RM publish and the newest-first walk order
keeps an older stale directory from winning, so the bounded wait's
registration is the lesser evil.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(moved-but-readable pool)
The pool resolver trusted an injected pin after a read-back proof. That
proof does not catch a pool page that MOVED: the old page is still
readable, so the release write lands on the old page while the client
polls the new one. Observed: 'pending release starved va=0x12100000x
tries=64' for ~45 s with the stale pin (pa=0x120b30000) readable, until
the fresh pin (pa=0x130e9d000) arrived; the client's tracker never woke
and its init hung (multikernel battery timeout, copies stuck rc=-2).
The client's own page tables are the GPU/UVM ground truth for where the
tracker reads, so when a structural walk resolves a different page than
the pin (and it is not a degenerate identity), the walk wins - both
sources are read-back proven at the exact offset.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
starving the pump
The full-RAM discovery scan read one 4 KB page per vfio_dma_rw call:
1.5 M guest reads over the 6 GB range, ~10-11 s per rebuild, and the
rebuild runs every 10 s - so the pump got roughly one pass per rebuild.
A client whose resolutions were dropped by a session flush then waited
minutes for the scan to re-find its pages (the observed post-flush
stall: data-VA copies returning -ENOENT with the pump counters frozen).
Reading 64 KB chunks amortizes the iommu walk + pin over 16 pages; the
per-page detection logic is unchanged.
|
| |
|
|
|
|
| |
(re-compact, not wipe)"
This reverts commit 1a49c7eb69c03f58bc51939828de222a2ac42fea.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
wipe)
The flush fires when the channel table momentarily empties - a live
client's UVM channel cycling triggers it - and wiping the map left the
client's already-resolved data VAs unresolvable until a rebuild scan
re-found them, which it may not. Evidence: a mid-battery boot where
multikernel's operands went NO ENTRY 40+ s after a flush (the rebuild
restored 14-31 K entries without them); the pump stalled for minutes and
the next clients read back whole-page garbage. The map is a cache with a
merge-on-rebuild contract, so re-compact it (dedup + sort) and keep it as
the merge base; reused-VA correctness stays with the ledger landing, the
pin-wins rule and the fresh scan.
Also: push_battery.sh now pushes inplace_scale (the battery list had it,
the push list did not).
|
| |
|
|
| |
advance even when the r391f once-only gate suppresses the write. A re-decode pass that skipped the FIRST run of a split upload left the cursor at the first run's destination, so the SECOND run's data landed at offset 0 (the deterministic tgemm X[0..1]<-X[2..3] 8-byte overwrite, present in every pass); the gate suppresses the write, not the method stream's positional semantics
|
| |
|
|
| |
runtime root alloc answers NV_ERR_INVALID_CLIENT (0x23) because the server's internal client is adopted, so allocate the class-0x2081 child directly under the internal subdevice with a candidate handle list
|
| |
|
|
| |
the live session (root -> device 0xcaf00000 -> subdevice 0xcaf00004 -> class-0x2081 child 0xcaf00099) and send the query as that client, so the server dispatches from a genuine BINAPI object
|
| |
|
|
| |
32-byte request header (hObject at +8, status at +16) - the backend alloc itself succeeded (rpc_result=0) in r522
|
| |
|
|
| |
the SUBDEVICE (0xbeef0004 is the class-0x2080 child), so mirror that on the backend - the device parent answered NV_ERR_INVALID_OBJECT_PARENT (0x36)
|
| |
|
|
| |
live session (GSP_RM_ALLOC as the internal client/device parent) and send the query to it - the subdevice attempt answered NV_ERR_NOT_SUPPORTED because the server dispatches by the object's class
|
| |
|
|
| |
forwarding only 0x20810107 keeps the P3 whitelist off so the boot is perturbed by exactly the one control under study
|
| |
|
|
| |
reserved-interface query to the live GSP session (internal subdevice translation) and log the server's own status/bytes as evidence; scoped to the observed 2-byte shape, fail-open to the emulated generic reply
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
MakeCurrent wall
The guest driver dups memory/VASpace objects into the GL client at
EGL MakeCurrent time; the generic-SUCCESS default replied with an EMPTY
payload and the driver, expecting rpc_dup_object_v03_00
(NVOS55_PARAMETERS {hClient, hParent, hObject, hClientSrc, hObjectSrc,
flags, status}) echoed back, failed the call and tore the whole EGL
session down. r510 guest witness: 'RPC UNKNOWN(21) seq=0 len=60 ->
generic SUCCESS' immediately followed by the session's FREE cascade and
eglMakeCurrent -> EGL_BAD_ALLOC (0x3003); EGL device enumeration and
eglInitialize were already green (n=3 devices, NVIDIA 1.5). The handler
echoes the params with status=NV_OK (the emulation keeps no per-object
state for these classes).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
large mixed-space map no longer burns them
r508/r509 witness: 'page directory discovery: not found (base=0x0 ap=ram
cands=39621 best=0/8)' during the very first client - eight RAM walks
spent on a stride subsample of the boot-scoped map, which holds pairs from
several VA spaces and (per the code's own comment) no single directory
reproduces. By the time the push-buffer pairs - the strongest samples -
formed, the attempts budget was gone; every later client's high argument
pointers stayed unresolvable and the boot ended in the held-launch class.
Only a small map (one session's own pairs) still falls back; a larger one
waits for the pairs and keeps the attempts.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
the r351 retry-forward consumes it
svc_gr_hold_bound_expired() re-armed the deadline on the very call that
detected expiry and then compared jiffies against the NEW deadline - the
function could never return true. A data-stalled launch whose arguments
never resolve therefore held its entry forever (r508 witness: matmul plus
ten sibling channels in 'GR hold ... data args unresolved' with zero
GR-STALL-hold-bound lines for 10+ minutes; the designed one retry-forward
plus consume never ran). The expiry is now one-shot: push the deadline,
latch gr_hold_bound_hit (snapshot-persisted) for the second call site of
the same pass, return true; the r351 retry-forward block consumes the
latch and forces its single best-effort forward, and the NEXT expiry cycle
(gr_hold_exp_logged now set) falls through to the historical consume with
the software completion - a never-resolving launch now costs ~6 s and the
client sees a stale-data FAIL instead of a hang.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
stream order in the pump itself
The streams order their H2D copies before the kernel that consumes them,
but the channels register in handle order (the RM's GR channel early, the
copy-CE channels later) and the pump walked them in that order; a pass that
decoded the GR launch before the CE channel's entries ran let the forward
workqueue execute the launch's copy-in against pre-copy data (r480-sep:
copy-in 115 ms before its stream's H2D soft copies; r481 proved no host
semaphore links the two). The CE copies execute on the same service
thread, so consuming the CE entries first fixes the inversion without any
cross-channel hold. Stable partition of the pass snapshot; relative order
within each class is preserved.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
holding (r507 matmul lost a pin-late 1 MB UVA copy and verified FAIL)
r506w's attempt-count latch tripped after 8 fast passes (~100 ms) while
the legitimate pin-late retry needs 0.5-2 s (r507 witness: memcopy
dst=0x71365ee02200 src=0x71365e500000 bytes=1048576 rc=-2 skipped; matmul
completed with STATUS FAIL instead of hang). The first failure of a VA now
arms a full 10000 ms window during which the op holds its entry exactly as
before; only after a full bound with no success does the op stop forcing
the hold. A success clears the record (fresh window on a later failure).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
release routing
Two independent defects turned one unresolvable virtual op into a
client-wide hang (r505 multikernel, r506 matmul: 'client at DEVICE
forever' while the pump ground its stream at ~10 s per push):
- an op that keeps failing -ENOENT re-runs on every decode pass and
re-set svc.op_tr_pending each time, so its push held for the full
SVC_OPDEF_HOLD_MS opdef bound every pass (r506 witness: the RM's
channel-progress zeroing at 0x2000c0xxx, 1913 failed attempts, 65 ring
entries in ~90 s). New per-VA failure latch: after 8 failures the op
still attempts its write but stops forcing the hold; the entry consumes
and its withheld release applies - exactly the outcome the expired
bound already sanctioned, minus the 10 s tax.
- svc_rel_apply_launch routed EVERY release through the exact-slot
counter fallback (release_pa ?: counter_pa), which writes (and
forward-only-skips against) the channel's registered completion slot -
a different word. The tracker releases to 0x20480fef0 were skipped
against the polluted PUT counter (cur=96) and lost: rel-apply
h=0x5c000059 pa=0x10809def0 pay=1 cur=96 -> skip. The fallback is now
restricted to counter VAs; generic releases are forward-only by value
(payload > fresh cur) so a decode blinded by a stale landing can no
longer drop them.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Two fixes for the r505 multikernel livelock (opdef held=18359, expired=61,
client at DEVICE forever while the pump looped on ring slot 1):
- after the bounded opdef hold expires and svc_opdef_flush delivers the
withheld releases, the slot's ops are permanently skipped - but the
decode-time bookkeeping had stored slot_ops_complete=0 (op_tr_pending was
set when it ran), so every pin-batch rewind replay of the slot re-decoded
it, re-set op_tr_pending and re-held the entry forever. Mark the slot
complete on flush so a replay suppresses the ops (entry_replay) and the
entry consumes normally.
- the per-slot op arrays are SVC_GPFIFO_MAX_BITS (1024) but the X/GL
channel's ring is 8192 slots: bound every slot-index write/read
(entry_ident is zeroed past the array size, so the bookkeeping skips).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
(+3 fixes)
The r496g blast registration of every COPY_SERVER_PDES directory let a
stale kernel directory answer another client's VA in the walker's
first-success order (the r459 stale-directory class) - measured as a CUDA
client hanging after DEVICE. Candidates are now parked and registered only
when a walk of the client's own content-validated ring VA through them
reproduces that ring's PA; the r496f vidmem sweep remains as a fallback.
Also in this batch:
- svc_chan_userd's VRAM shape scan now prefers a block with work PENDING
(get < put) and then the one nearest the registered memdesc offset: on a
channel re-registration the stale previous USERD still validates (it
holds the same put/entry values) and the old first-match adoption made
the pump write GP_GET into the dead block (r504 second DMA init).
- The USERD/FB scan and the CE caps byte-1 BL bits (r496i) are unchanged;
TU104_CE_CAPS1 = 0x03 needs the CUDA battery re-verification.
|
| |
|
|
|
|
|
|
|
| |
nvCEChooseEngine skips every CE without CE_SUPPORTS_NONPIPELINED_BL
(caps byte 1, 0x01) and, in the preferred pass, PIPELINED_BL (0x02). Our
emulated CE caps left byte 1 zero, so every CE failed the filter and the X
driver aborted with 'Failed to find a suitable copy object' - the wall
after the DMA pushbuffer test started passing (r503). Turing CEs are fully
capable (bug 200288104 case (a)): byte1 = 0x03.
|
| |
|
|
|
|
|
|
|
|
|
| |
resolves the rest
The registered COPY_SERVER_PDES directory walks the ring VA correctly
(trace: L0 -> L1 -> L2 idx 9 -> PD0), but the linear window pin installed
around the ring shadows it in svc_lookup_trusted (pin_lookup_any returns
the win-flagged entry first), so the pushbuffer/tracker reads kept using
the wrong noncontiguous guess. Pin only the content-validated ring page;
every other VA of the client now resolves through the walk.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
NV90F1_CTRL_CMD_VASPACE_COPY_SERVER_RESERVED_PDES (0x90f10106) is the
kernel RM publishing its internal VAS page-table chain - level[0..] with
phys addresses, sizes and page shifts (the handler already parsed and
logged it, then discarded it). Register level[0] as the VAS root with the
progress service so the walker translates every VA of that client, which is
exactly what the X/GL channel needs: its pushbuffer pages and progress
semaphore have no other translation source (fn-54 is external-VAS/UVM
only, the rm_mem content scan finds nothing for these VAs, and the
sysmem/linear window guesses are wrong for the noncontiguous surface).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The X/GL channel's pushbuffer pages and progress semaphore live in a
kernel-RM internal VAS whose page directory is never published (fn 54 is
UVM/external-VAS only), so no translation source can resolve them: the
tracker push reads zeros/garbage and the driver's DMA sanity poll (which
waits on the progress-tracker semaphore the GPU writes when it consumes the
tracker push) never completes.
With the ring content-validated, try each 4 KB page of the vidmem shadow as
a walk root and register the first whose walk reproduces the ring
VA -> ring PA translation. The walker then resolves every other VA of the
same client - pushbuffer pages, the tracker push, the progress semaphore.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
capture holds for their entries
The driver's __nvPushTestPushBuffer writes one zero dword (NVA06F_DMA_NOP)
and waits for GP_GET to follow GP_PUT. The method-stream plausibility gate
rejects an all-zero buffer (it parses as zero methods), so the entry fell
into the unreadable/rescue path and the GR no-capture hold - the DMA sanity
test could never pass. For channels whose ring was found by the RAM content
scan (kernel-RM sysmem 3D channels), model them as consume-and-apply-
releases: accept an all-zero NOP push, and skip the no-capture hold (these
pushes are not compute launches; holding them 6 s per entry cannot help).
|
| |
|
|
|
|
|
|
|
| |
ring
The ring-ownership check rejected every entry VA >= ring_va, but the driver
writes TWO GPFIFO entries per kickoff - the main pushbuffer BELOW the ring
and the progress tracker ABOVE it (nvidia-push-priv.h). Accept VAs anywhere
in the 2 MB allocation window.
|
| |
|
|
|
|
|
| |
The pump's !userd_ok path continues past the end-of-pass write-back, so the
GR RAM ring scan restarted from slice 0 every pass and never reached the
ring page beyond the first 512 MB. Persist gr_ram_cursor/gr_ram_passes (and
the one-shot log flag) directly in the scan.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
USERD shape scan
With the GR classification fixed the pump reaches the X driver's 3D channel
for the first time, but both of its structures are outside every existing
translation source: the CPU RM maps the pushbuffer's NV01_MEMORY_SYSTEM
surface locally (no SET_PAGE_DIRECTORY, no rm_mem record carrying the ring
VA - the targeted resolve scans all of guest RAM and finds nothing), and the
driver's USERD GP_PUT write lands in the emulated VRAM at a BAR1-window
offset (observed: fb 0x80000) that is neither the registered memdesc base
(0x10000, pool-relative) nor ring-derived.
Two content scans close the gap, both validated so a wrong hit costs a
failed probe, not a bad pin:
- svc_gr_ram_ring_scan: the driver's kickoff writes GPFIFO entries whose
pushbuffer VAs sit just BELOW the ring VA in the same allocation (main
pushbuffer first, GPFIFO after - nvidia-push-priv.h). A page whose first
two 8-byte entries both name such VAs with sane lengths is the ring; the
ring page is pinned validated and the 2 MB allocation window as guesses
(the ring entry and pushbuffer reads resolve through it). Sliced 512 MB
per pass, cursor-resumed, 16 slices max.
- svc_userd_fb_scan (svc_chan_userd GR fallback): scan the VRAM for the
USERD shape (GP_PUT at +0x8c in [1..entries], GP_GET at +0x88 <= put) and
validate each hit against the ring: every entry the put claims must
decode to a pushbuffer VA in the ring's allocation window. A foreign
channel's USERD cannot pass that test. 8 bounded retries (the kickoff
lands a few passes after registration).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
GR channel
With the real-GSP KGR snapshot in place the X driver's 3D-engine selection
succeeds; the next wall was 'Failed to initialize DMA' / 'Failed to allocate
push buffer' - the X driver's pushbuffer NOP test never saw its GPFIFO entry
consumed. Root: the wire's NV_CHANNEL_ALLOC_PARAMS engineType carries
NV2080_ENGINE_TYPE_* (NULL=0, GR0/GRAPHICS=1, COPY0=9); CUDA's kernel-RM GR
channels arrive with NULL=0 and the progress service's convention is
'engine_type == 0 means GR', so the X/GL 3D channel's real GR0 value 1 was
misclassified as a CE - the CE path then demanded a ring translation the
channel does not have (rrc=-2 'norrng'), never probed the USERD, and the pump
never executed a single entry (submissions=0 at the 10 s timeout).
Normalize GR0..GR7 (1..8) to 0 at channel registration; every other engine
id is >= COPY0 (9) so no CE can be captured. Also fixes the KGR snapshot
max-size constant: KGR_GET_INFO is 3712 bytes (8 engines x 58 x 8), which
the 1664-byte cap silently dropped - the one snapshot the engine selection
actually needs.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The X driver's nvSelect3DClass -> nv3dAllocDevice maps GR_GET_INFO index
SM_VERSION (0x0c) through an SM-version -> SPA-version table; the emulated
KGR_GET_INFO fill never set index 0x0c, so SM_VERSION read back as
SM_VERSION_NONE (0) and every Xorg/EGL session died at 'Failed to select a
3D engine' (the class list and the engine list were never the problem: the
X log carries neither 'Failed to determine graphics capabilities' nor
'Failed to determine engines list').
The physical backend already asks the LIVE GSP the real client's whole KGR
query set at mode-35 boot (gsp_phys_rmcall_user_lane_kgr_queries) and threw
the replies away. Retain them (generation-keyed, invalidated with the
backend static cache) and serve the identical bytes in the guest-side
GSP_RM_CONTROL dispatch for the same commands, so the guest's GL/3D stack
reads the device's true GR static values (SM_VERSION 0x75, warps, caps,
topology, ctx-buffer tables) instead of fabricated approximations. Falls
through to the emulated handlers unchanged when no capture exists (backend
not READY, other boot mode, cmd not captured) and never answers with more
bytes than the guest requested.
|
| |
|
|
| |
multi-frame request): stop replying to it. The guess reply injected an extra fn-71 record the driver drained as an unexpected event (0x47) and corrupted our own large-reply continuation framing
|
| |
|
|
| |
driver's pRpc->maxRpcSize (65080; pinned by the guest's own remainingSize 0x940 arithmetic for the 67448-byte PERF_VPSTATES_INFO reply) are now sent with the GSP continuation-record protocol - first frame length = maxRpcSize, then NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD frames of up to maxRpcSize-32 bytes each, exactly like the host GSP's _rpcWriteContinuationEntries. Replaces the r487 clamp (which produced a record the guest refused, and a size the guest then waited on fn-71 continuations for). Root: the GL VASpace construction and 3D engine selection die on this control's reply
|