<feed xmlns='http://www.w3.org/2005/Atom'>
<title>open-iov.git/kernel/gsp_phys_gpu.h, branch stallfree</title>
<subtitle>Open-IOV vGPU-IO: host-side GSP emulation for unmodified NVIDIA guest drivers
</subtitle>
<id>https://git.vgpu.io/open-iov.git/atom?h=stallfree</id>
<link rel='self' href='https://git.vgpu.io/open-iov.git/atom?h=stallfree'/>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/'/>
<updated>2026-10-18T16:10:03+00:00</updated>
<entry>
<title>vgsp: bounded GR launch completion (GR-STALL), r220 hold storm fix, churn caps</title>
<updated>2026-10-18T16:10:03+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-18T16:06:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=2658fedd556f872f11dd3aeefa88ff6eb76c5342'/>
<id>urn:sha1:2658fedd556f872f11dd3aeefa88ff6eb76c5342</id>
<content type='text'>
Every GR launch now either completes or fails fast with a distinguishable
dmesg line; no host wait in the launch/consume path can run forever.

- gsp_phys_gr_wait_max_ms (new param, default 60000, clamp [10000,600000],
  0 = built-in per-ladder bounds only): absolute per-launch submit budget.
  Checked in the GR poll loop (after the release acks) and in the
  retirement-retry loop; on expiry the submit fails out ('vgsp-gr:
  GR-STALL-wait-max ... action=fail') or the retry loop stops
  ('GR-STALL-retry ... action=proceed'), so the chain of individually
  bounded ladder phases can no longer hold the single-inflight work item
  (and the client's launch wait) for the ladder sum.
- gsp_sema_service: pass-top svc_fwd_outcome_check() completes a forwarded
  GR request that no hold owns. A GR push with no push-level release
  records engages no release hold, so a backend failure (ladder timeout,
  abort) left the QMD completion word unwritten and the client waited to
  its own timeout (r219/r222, qmd_rel frozen at the previous value). The
  check authors the word in software (full resolver, forward-only,
  latched once) and logs 'GR-STALL-backend ... action=proceed'. It also
  covers a *successful* submit whose release0 could not target the guest
  page (engine completion landed on the module semaphore only) - the
  work item records gr_rel_unobserved for that.
- Consume tail: a GR capture consumed without ever being forwarded (a
  data-stall / busy-defer / no-capture hold fell through) now authors its
  QMD completion release, latched per capture, and logs 'GR-STALL-hold'.
- r220 hold-storm fix (196 s re-hold): the m150/m156 data-stall hold
  window is keyed to the GPFIFO slot index, and a pin-batch rewind
  replays the same launch at different slots, so the window re-armed on
  every pass; the absolute per-launch backstop could never fire because
  its record fields were excluded from the pump snapshot write-back list
  (the GRFIX NOTE record leak) and the fill gate defaulted off. The four
  bound fields are now written back and svc_gr_hold_bound_expired is
  effective on the default path (cap gsp_phys_gr_hold_max_ms, default
  3000 ms, keyed to the launch push VA via svc_gr_launch_va so nothing
  re-arms it across rewinds); the busy-defer hold site consults the same
  bound. On expiry the entry is consumed with the software completion and
  logs 'GR-STALL-hold-bound'.
- Hold expiry/failure edges log 'GR-STALL-fwd-hold' / 'GR-STALL-fwd-fail'
  with waited_ms for held forwarded launches.
- Anti-degradation under pin churn/leftover clients: svc_rescue_scan_range
  (up to 6 GB of guest-RAM reads on the service thread) is capped at 3 s
  per range with RESCUE-SCAN-CAP logging; the ledger eviction burst
  triggers a logged wholesale cache reset (LEDGER-RESET cap-and-degrade,
  256 evictions); pending-ring overflow is counted and surfaced
  (PENDING-OVF, pend_ovf in the drain line). New diag tokens:
  gr_swrel/pend_ovf, ledger resets, rescue scan_capped, work_gr
  stall_wait_max/stall_retry/wait_max_ms.

Green behavior: normal launches complete in ~0.2-11 s and never approach
the budget; the hold bound only fires where the old path could stall
forever. make kernel green; only pre-existing warnings.

(cherry picked from commit dc3650105f163631bb826ae3685a7d6e9025bfe8)
</content>
</entry>
<entry>
<title>vgsp: m91 - first-fault capture + QMD instruction-cache invalidate for the SM I-fetch lottery</title>
<updated>2026-10-18T16:10:03+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-18T16:09:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=7fc3c3ca9f0c2e25c5a932e3fa955dcb0a261ec6'/>
<id>urn:sha1:7fc3c3ca9f0c2e25c5a932e3fa955dcb0a261ec6</id>
<content type='text'>
m91-class recap: the first attempt of a mid-sequence forwarded GR launch
raises SM warp exceptions ("Illegal Instruction Encoding", "Out Of Range
Register") on garbage instruction bytes while a retry of the IDENTICAL QMD
and identical shadow content succeeds (r219: fault at +2.5 s, fast re-arm
recovered 3 ms later; r223 same pattern). The host retry path only replays
the mode-35 lane-enable tail + channel/TSG schedules + doorbell and
re-publishes the same method block on a fresh ring entry: no shadow re-copy,
no QMD re-read, no cache/TLB invalidate exists anywhere in the ladder. Plain
re-submission of byte-identical content flipping the outcome names stale
engine-side fetch state at first dispatch, not a content or programming
error: the window-0 shadow pool alternates two 8-page banks by submit
epoch, so a program VA's bytes change every two launches, and every
captured guest QMD carries the QMD v2.3 cache-control word (word 5) with
INVALIDATE_INSTRUCTION_CACHE (bit 30) clear - the client driver arms that
bit only under its forced-invalidate mode.

Two changes:

1. FAULT-CAP (diagnostic, inert until a fault): when a forwarded launch's
   fault epoch advanced across its window, emit one "vgsp-m91: FAULT-CAP"
   line per launch (capped at 20 per module-load cycle, then one
   suppression notice) with: fault-epoch delta, QMD address + first 64 B,
   live program pair (w48/w49) + resolved engine-visible VA/PA, the first
   64 B at that code address, retry decision (fast re-arm /
   resched/fresh-entry / none) + outcome (ok vs timeout), and the newest
   relay-decoded 0x1006 note (exceptType/chid/errString). A fault-free
   launch costs one epoch read and one compare (greens unaffected
   statically: no prints, no content reads, no engine access).

2. QMD icache invalidate (fix, param-gated default-on
   gsp_phys_gr_icache_inv=1): set QMD v2.3 word 5 bit 30 in the forwarded
   QMD (forcing an instruction refetch at dispatch) only when the QMD
   carries the client driver's standard cache-control signature (word 5
   bits 26..29 set) so an unknown QMD revision is never touched; 0 restores
   the exact pre-change QMD for a one-flip A/B. The bit cannot alter
   instruction bytes or data - it only invalidates cached fetch state (the
   same field the client driver sets under forced invalidate) - so green
   launches keep their semantics; the only cost is a per-launch refetch.

Expected next-cycle evidence: zero FAULT-CAP lines with the multi-page
client set green confirms the stale-fetch mechanism; any FAULT-CAP content
policies the remaining candidates (shadow-VA reuse distance, cross-cycle
context state left by killed clients). Doc: 03-architecture/13-vexecution-
plane.md m91-class section.

(cherry picked from commit 682a5559b1dbbd482d8fe6bdabbc46220ce0d5de)
</content>
</entry>
<entry>
<title>vgsp: m179 GR no-write robustness - dedicated re-execution budget + specific zero-write test + loud classified accept</title>
<updated>2026-10-18T04:26:02+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-18T04:04:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=1595efde3d9a8fc08dc892fd88b48dbb84715095'/>
<id>urn:sha1:1595efde3d9a8fc08dc892fd88b48dbb84715095</id>
<content type='text'>
The r200-r202 memcpy_roundtrip/multikernel all-wrong class: a forwarded GR
launch retires with zero tracked engine writes (NOWRITE, qmd_rel satisfied),
the m153 outcome-retry loop either never ran (it shared the timeout ladder's
attempt counter, which the fast re-arm / fresh entries had already consumed)
or exhausted, and the accept path silently restored the release words,
handing the client an all-wrong output with a fabricated completion.

Changes (kernel/gsp_phys_booter.c, gsp_phys_gpu.c, gsp_phys_gpu.h):
1. gsp_phys_gr_nowrite_retries (default 3, clamped [0,4]): the no-write
   re-execution loop now has a DEDICATED budget, independent of the timeout
   ladder's attempts. Each retry keeps the existing backoff mechanics (zero
   release words, fresh qmdwin/win0 bank, refill bounce, rebuild PB,
   re-publish + resched, fresh-ack poll, fetch witness, retire wait). Worst
   case stays within the 8-entry GPFIFO ring (initial + fast re-arm + 2 fresh
   entries + 3 retries = 7 publishes).
2. Specific zero-write test: gsp_phys_gr_output_retire_wait() now reports
   n_tracked (the number of data entries that resolve to a bounce page); the
   no-write retry/accept path only triggers when n_tracked &gt; 0, so a launch
   whose data entries resolve nothing can no longer false-positive as a lost
   launch.
3. The accept (last resort after the budget) is now LOUD (pr_warn) and
   classified by the QMD fetch sentinel: NOWRITE-CONFIRMED = deposit never
   reached the engine (sweep/hold-faked-ack class); NOWRITE-AMBIGUOUS =
   engine consumed the deposit, zero tracked writes may be a legitimately
   read-only kernel. It also runs when the retry master gate is off, so a
   zero-write outcome is never silent.
4. Ordering: explicit wmb() after the retry's fresh qmdwin deposit (the
   first-attempt path and the publish tail already carry the barriers;
   dma_wmb before GP_PUT advance + wmb before the doorbell in
   gsp_phys_rmcall_publish_locked) - deposit-&gt;kick order is now explicit on
   both paths.
5. Frame bound: the ~370-byte struct gsp_phys_fault_info moved to static
   scratch (the function's documented single-inflight contract, same as
   methods[]/qmd[]) with a per-submission memset; this clears the
   pre-existing &gt;1024-byte frame warning in the submit function instead of
   growing it.

Fast re-arm (gsp_phys_gr_retry_fast) and the timeout ladder are untouched.
Build: make kernel -j - green, vgsp.ko; no warnings in touched code.
</content>
</entry>
<entry>
<title>vgsp: m178 GR launch reliability + diagnostics; tools: pin latching robustness</title>
<updated>2026-10-17T23:18:50+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-17T23:18:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=33de4c9bc524ac27582fde5911ad32d89d0a7de9'/>
<id>urn:sha1:33de4c9bc524ac27582fde5911ad32d89d0a7de9</id>
<content type='text'>
Kernel: authorship instrumentation + swrel gate for in-flight GR release VAs;
first-poll shortening + fast extended re-arm (params gr_retry_fast=1,
gr_first_poll_ms=2500); per-attempt win0 bank recompute + shadow recopy in the
outcome-retry loop; poll-break/deposit-readback diagnostics; C1-C10 sema
diagnostics (crel-entry, relx, opdef-clear, walk, pub-adv, hold-fallback,
busy-defer, CAND-OVERWRITE, inline recs); busy-defer hold instead of
software-release consume; counter fast path; QMD word 48/49 skip.
Tools: heartbeat thread, scanner-alive probe on reinstall, full periodic
re-assert, #nopid handling, per-client reset fix (debounce), dead-pid drop,
supervisor grace+threshold.
</content>
</entry>
<entry>
<title>Merge branch 'dual'</title>
<updated>2026-10-16T17:33:02+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-16T17:33:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=06b9333cf64f613be5dfb3ea1ee40e087a182061'/>
<id>urn:sha1:06b9333cf64f613be5dfb3ea1ee40e087a182061</id>
<content type='text'>
</content>
</entry>
<entry>
<title>vgsp-dual: stage B+C minimal per-mdev separation (G1-G3, G5, G6, G7, G8a)</title>
<updated>2026-10-15T21:53:52+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-15T21:53:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=81c11ca09adf85bd314f7406a8e0d7d637726a80'/>
<id>urn:sha1:81c11ca09adf85bd314f7406a8e0d7d637726a80</id>
<content type='text'>
Goal 1.0: two mdevs + two QEMU guests running CUDA simultaneously.
Single-mdev behaviour is kept identical: the legacy guest-RAM record
still serves the first/only open mdev, the channel table degenerates to
the historical key, and the session flush fires at the same
last-channel-closed transition.

- G6: guest-RAM backing {file, path, ranges} per mdev (legacy record +
  up to 4 vgpu-bound records); debugfs gsp-phys-guest-ram accepts an
  mdev UUID as an extra first token and keeps the 4-token form; records
  released on mdev cleanup and physical release.
- G7: gsp_phys_gpa_to_hpa_vgpu(vgpu, gpa, *hpa); NULL keeps the
  historical first-open resolution. Forwarding operands pass the
  request's vgpu; the single-guest boot-ladder pin passes NULL.
- G1: the sema-service thread services every open mdev each pass.
- G2: channel table keyed by (vgpu, h_object); per-guest ranks;
  counter/scrub/opdef/pump snapshot+writeback matches per vgpu;
  scrubber records per guest.
- G3: per-guest session records drive the flush; the shared learned
  tables (staged G4) are only flushed when no guest has live channels.
- G5: hold/abort keyed by (vgpu, handle); dead-owner guards on the
  hold resolution paths; single-inflight serialization kept.
- G8a: guest-GPA pin refused while more than one mdev is open.

Build: make -j8 clean success (vgsp.ko). No module load. See
DUAL-REPORT.md for the per-item status and live-validation plan.
</content>
</entry>
<entry>
<title>vgsp-gr: B-2 planted 64 MiB data-bounce region for large GR operands</title>
<updated>2026-10-15T21:51:17+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-15T21:51:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=54dc6c8cb980aecef1885d5622ca5fd869d7243f'/>
<id>urn:sha1:54dc6c8cb980aecef1885d5622ca5fd869d7243f</id>
<content type='text'>
Replace the 205-page / 68-pages-per-pointer GR operand window with a
boot-planted 16384-page (64 MiB) region at VA 0x0a000000 (PD0 80..111):
one dual PD0 entry per 2 MB window backed by one fresh 4 KB PT page,
every leaf PTE written at stage 3 before any engine fetch (the GMMU has
no PTE invalidate, so no leaf is rewritten at runtime). The 208-page
window, mail slot 206 and marker 207 stay as-is (mail injection and
copy diagnostics unchanged) but carry no operand data when the grown
region is on.

Sema service: reloc base and page cap derive from the shared header
constants; per-pointer span becomes a 4096-page runaway guard; a total
cap hit is fail-closed (launch stalled for the bounded hold, loud
CAP-HIT log, no silent truncation); the launch's own param/bank pages
are skipped as data candidates (budget hygiene). Copy-in, copy-out,
retirement wait and the window diagnostic index the active region
through one helper/chunk selector; checksum and dedup scratch move off
the kernel stack.

gsp_phys_gr_data_region=0 (insmod, boot-fixed) flips the whole path
back to the legacy 205-page window for A/B trialing.
</content>
</entry>
<entry>
<title>vgsp-gr: m152 scratch-PT alias cache + extended pool; m153 outcome-verifying launch retry</title>
<updated>2026-10-15T14:20:13+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-15T14:20:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=48a8089ed3c4892c2577db2da815e6731b882045'/>
<id>urn:sha1:48a8089ed3c4892c2577db2da815e6731b882045</id>
<content type='text'>
m152: the Tier-2 shadow alias pool consumed one never-reused 128 B fetch
line per mapping per launch (512 lines/boot), so a normal launch mix
exhausted it permanently: every later launch that needed a new mapping
was refused (the deterministic r152 'launch refused: no Tier-1 mapping'
loop). Two fixes: (a) an HPA-keyed alias cache in map_shadow_locked that
returns the existing never-rewritten VA for a page already mapped, so
repeat launches of the same buffers/sem pages consume nothing; a hit
reports line_out = ~0 so contiguity bookkeeping never extends an old
line; (b) a 48-window extension pool at VA 0x04000000 (PD0 indices
32..79, one 48-page PT chunk) raising capacity to 2048 lines/boot.

m153: the intermittent per-boot mis-execution classes (engine wrote
nothing; or wrote into a lower operand window while the output operand
stayed untouched - both complete with qmd_rel/ch_rel satisfied, live
evidence in r152 smiley: passes wrote b into the a window / nothing /
correct-after-10s-retry) are now detected by the m151 retirement wait
and retried: refill the bounce window from the guest inputs, re-publish
the same method block on a fresh ring entry, re-issue schedule, re-poll,
re-wait - bounded by the timeout path's attempt budget. Gate param
gsp_phys_rmcall_gr_nowrite_retry (default 1).
</content>
</entry>
<entry>
<title>vgsp: m113 - re-register the VAS page directory after planting data (re-commit probe)</title>
<updated>2026-10-07T19:33:31+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-07T19:33:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=d9c2545fac3c37c57e56b892ed3d0e054d8f6816'/>
<id>urn:sha1:d9c2545fac3c37c57e56b892ed3d0e054d8f6816</id>
<content type='text'>
All late engine-tree writes are invisible to the SM walker (only the
commit-time snapshot resolves); the mail injection at a main-window fresh
slot also fails (m112). Probe whether UNSET+SET_PAGE_DIRECTORY on the
ladder VAS after planting forces the server walker to re-snapshot the tree;
gated by gr_recommit.
</content>
</entry>
<entry>
<title>vgsp: m106 - pre-install the data PT window pool in stage 3 (pre-commit)</title>
<updated>2026-10-07T19:05:08+00:00</updated>
<author>
<name>Arthur Hanson Rasmusson</name>
<email>arthur@vgpu.io</email>
</author>
<published>2026-10-07T19:05:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.vgpu.io/open-iov.git/commit/?id=d2848c109761e3ccde81a742f4569730254031f8'/>
<id>urn:sha1:d2848c109761e3ccde81a742f4569730254031f8</id>
<content type='text'>
Post-commit UPDATE_PDE_2 installs are accepted (status 0x0) but ineffective
(m94's scratch windows, m101-m105's reloc windows: the SM never resolves
them), while the stage-3 ctx-window installs are honoured. Add a fixed
32-window pool at GSP_PHYS_RMCALL_VA_GR_DATA_BASE (0x100000000 + k&lt;&lt;21,
inside the server-managed region), each backed by a module PT page
installed through UPDATE_PDE_2 during stage 3; the engine data map then
only writes leaf PTEs into those fresh PT pages at launch (the P6b-proven
'direct leaf write into a walker-installed fresh table' pattern). The mail
injection uses the reserved last window (k=31); service data windows cap
at 31 and use the same fixed layout.
</content>
</entry>
</feed>
