summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
Commit message (Collapse)AuthorAge
...
* sema-svc: apply releases before push memsets; poller: bypass read cacheArthur Hanson Rasmusson13 days
|
* sema-svc: disable swept-page release writes (guest memory corruption); wake ↵Arthur Hanson Rasmusson13 days
| | | | on doorbell + tight pump loop while entries execute
* guest-diag: stream uvmt sems over vsock (no guest-agent race); dump channel ↵Arthur Hanson Rasmusson13 days
| | | | last release VA; larger push log budget
* sema-svc: never apply swept-page releases with no live channel (guest boot ↵Arthur Hanson Rasmusson13 days
| | | | corruption); tooling guards
* sema-svc: apply decoded releases to registered counter slots; single-QMP ↵Arthur Hanson Rasmusson13 days
| | | | semfix+uvmt watcher
* kernel: grace window for untranslatable GR entries; tools: coalesce window ↵Arthur Hanson Rasmusson13 days
| | | | | | | | | | | | | | | | | pin output The first GR window pin landed ~2 s after the pump consumed the freshly created channels' GPFIFO entries on the first failed read, so the pushes (and the tracking-semaphore releases they carry) were lost. GR entries with an unresolvable push page now stay pending for sema_gr_grace_ms (default 8 s) before the stale-entry consume; a pin landing in that window makes the entry readable and it executes normally. The completion counter is still published from put at the end of every pass, so the client's counter wait is not delayed. guest_pmap_win.py coalesces contiguous VA+PA pages into run lines, so a 15k-page window transfers as ~200 lines instead of ~15k and the pin batch lands within a second of the pages appearing.
* tools: pin GR push-buffer window from guest pagemap per boot; widen ↵Arthur Hanson Rasmusson13 days
| | | | | | | | | | | | | | | | | injected-pin table The GR channel GPFIFO entries point at pushes in the client GPU VA window (observed 0x200400000 + stride, one allocation per channel) and the pump cannot read them: pushes_nomap grows and the tracking-semaphore releases they carry never land. The pushes are sysmem pages mapped into the client process, so /proc/<pid>/pagemap in the guest gives the GPA. New guest helper guest_pmap_win.py batch-reads the pagemap of a VA range (512 entries per pread). New host tool pin_gr_window.py rescans the window on an interval, follows cdt pid changes, and injects VA->PA runs through sema_map_add (same mechanism as the counters and the CE pushbuffer pins). The injected-pin table grows 8k -> 32k slots so the CE pushbuffer (4096) plus the GR window pages fit without drops.
* kernel: batch the map-add channel rewind; trust injected streams for opsArthur Hanson Rasmusson13 days
| | | | | | | | | | | | | | | | | Two fixes for the CE data path. (1) svc_handle_map_add rewound every channel by 8 ring entries on every injected mapping; a 16 MB push-buffer pin is thousands of page injections, so the pump's last_get was pinned in place and it re-read the same entries for the whole batch (3645 submissions, zero ops). The rewind now runs once per drained batch. (2) The push-start heuristic (op=INC_METHOD at address 0) rejects UVM's real CE memop pushes, which start with an IMM method at address 8 (observed 0x60020002, PTE data words) or a release method at 0x700 (0x200381c0); a buffer read through a host-injected (ipin) translation is now decoded fully trusted, ops included. Result on the next boot: memset=2718/0/0 ringops=1794 (first sustained CE work), false 12k->1.9k. semfix_watch: bulk-pin contiguous runs via sema_map_add len, read rm_mem size, 16 MB (4096 page) cap, non-blocking QMP read (the fixed 30 ms sleep made 4096 gva2gpa calls take two minutes), and KEEP_TRACE=1 to preserve the guest trace for post-mortems.
* kernel: decode release pushes read through injected pins instead of rescuing ↵Arthur Hanson Rasmusson13 days
| | | | | | | | | | | | | them Real CE release pushes start with INC_METHOD addr 0x700 (0x200381c0, count 3, subch 4), and svc_method_stream_plausible requires method address 0, so every readable release push was treated as a false pairing, rescued (fails) and skipped - the client's tracking-semaphore release never applied and cuCtxCreate waited forever (slot payload 74 vs queued 75). A buffer read through a host-injected (ipin) translation is now decoded release-only (allow_ops=false) when it fails the push-start heuristic; self-discovered translations keep the strict rescue path.
* kernel: authoritative host-injected VA->PA pins (ipin table) + wider pin tableArthur Hanson Rasmusson13 days
| | | | | | | | | | | | | | The CE push-buffer page 0x120000000 resolved to a zero-filled page even after sema_map_add injected the correct translation: the shared pin table silently dropped inserts once a hash cluster exceeded the 32-probe window (the page hashes to slot 0, a hot cluster), and lookups fell through to the content-scanned map and answered with a stale page - so every CE push read as implausible and memset stayed 0. Injected translations now live in a separate authoritative table checked before every other source and are never written by self-discovery; the general pin table is 4x larger with a 4x probe window and counts drops (pin_drop/ipin_drop) in the stats line. guest_kprobes.sh disables the kprobe group before removal (EBUSY) and matches p:kprobes/<name>; the guest wait sampler can run counters-only with GDB=0.
* sema-svc: fake_rel applies releases immediately (skip multi-second CE rescue ↵Arthur Hanson Rasmusson13 days
| | | | scans)
* sema-svc: learn the tracking-sem VA from readable pushes for the release ↵Arthur Hanson Rasmusson13 days
| | | | fallback
* sema-svc: optional CE release fallback for unreadable pushes (sema_fake_rel)Arthur Hanson Rasmusson13 days
|
* sema-svc: async VA->PA injection queue; guest-diag: fast counter+pin ↵Arthur Hanson Rasmusson13 days
| | | | injector, wait sampler
* sema: fix host stack-overflow hang; robust VA resolution; dispatcher lock fixArthur Hanson Rasmusson13 days
| | | | | | | | | | | | | | | | | | | | | | | - svc_handle_chan_dump()/svc_decode_stream(): static snapshot buffers. The 128-channel local array made an ~18 KB frame, which overflows the 16 KB kernel stack in the function prologue and panicked the host 2-3 s after a VM attached the vGPU (proven from EFI pstore: guard page hit at svc_handle_chan_dump+0x20, sub rsp,0x4850). - svc_pump_channels(): write-back now also persists expected_sem_payload, rescue_last and rescue_fail. The pump works on a snapshot copy, so without this the stale-entry skip and the rescue rate limit could never fire and the payload expectation was reinitialized every pass. - svc_targeted_resolve(): sliced scan (128 MB per call, one VA at a time, failed-VA cache) instead of a full-RAM scan per miss; no longer appends to the sorted map out of order. - svc_rebuild(): merges new scan results into the previous map (fresh translation wins in place, new VAs appended) instead of replacing it wholesale, so live translations survive a scan-yield collapse. - Warning fixes: misleading indentation, unused variable, jiffies typecheck. Frame audit: largest frame now 872 B. - Includes the previous session's uncommitted work: sema_counter / shadow_scan / shadow_dump debug params, exit stage markers, pdev ref fix, and the dynamic dispatcher request_firmware-out-of-spinlock fix.
* sema: consume stale GPFIFO entries after repeated rescue failuresArthur Hanson Rasmusson14 days
| | | | | | | | Entries whose push buffer was overwritten (the rescue cannot validate any candidate page) were retried forever, rescanning RAM every 5 s and leaving the ring stuck behind them. After three real rescue failures (rate-limited attempts do not count) the entry is consumed with a 'skipping stale entry' log and the pump moves on. New skip= stat.
* sema: rescue entries anywhere in a pushbuffer slotArthur Hanson Rasmusson2026-09-28
| | | | | | | | Mid-slot entry VAs were rejected by the alignment guard, leaving their false translations permanent. Candidate 2 (the group's page minus the push length) is the PA of the entry VA's page regardless of alignment; pin only the pages the push occupies for mid-slot entries and the whole 1 MB slot for slot-aligned ones. Validation by read-back is unchanged.
* sema: rescue by exact release group at any offset, with validated pin alignmentArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | | Kernel: the slot-aligned failing entries carry pushes whose release group is not at the page's fixed +0x10 offset, so the shape matcher found nothing. Scan every 4-byte offset for the exact group (hdr 0x20038090, hi==1, lo&0xfff==slot, follower LAUNCH_DMA sem-release; payload may lag the tracked expectation) with the header compared first. Each match yields two candidate pin bases - the group's page and the page implied by treating the group as the end of this entry's push - and each candidate is validated by pinning and reading the entry VA back before it is accepted. Live: 13 rescues pinned the MEMOPS slots; the 12700-byte push then decoded to 29 op-runs with a real release, and memset=338 fills (page-table clears) executed ~13 s before the client's rc=999.
* sema: strong rescue signature; rescue on false translations; slot pinArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | The content rescue matched only the release group bytes and had matched GSP firmware pages. It now requires the full known push shape around the release (two SET_OBJECT class binds, the 3-word SET_SEMAPHORE_A run with this channel's next payload, and the LAUNCH_DMA semaphore-release follower), and it is also invoked when a trusted read resolves but the buffer does not parse as a push (false content-scanned pair; observed firmware/kernel-data pages), not only when the VA is unmapped. The rescue pins the whole 1 MB push-buffer slot, which is what the UVM MEMOPS channels' pushbuffer pool (0x1200_0000 + n*1MB) needs. New false= stat.
* sema: include the push VA in the per-push summaryArthur Hanson Rasmusson2026-09-28
| | | | | | The long bogus pushes (RISC-V tails) could not be tied back to the ring entry they came from; log the GPFIFO entry VA with each push so the false translations are identifiable and can be compared against probes.
* sema: refuse work from buffers that do not start like a pushArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | The discovered VA->PA map is content-scanned and can hand a ring entry's push VA a false translation; observed: GSP firmware pages read as a 12700-byte method stream whose fills would have been executed into vidmem. Work now requires the buffer to start with a plausible first method (INC_METHOD, address 0, sane count that fits the length); releases still apply from such buffers so a shifted stream is not lost. New 'denied' counter in the sweep stats.
* sema: per-push release/ops summary; never run work from rescued pagesArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | Log one line per ring-decoded push (channel, engine, length, op-run count, decoded release VA/payload, last 24 bytes) to make the push->tracker path observable; it showed that the content rescue had been pinning unrelated RAM pages: pushes of length 4196/8500/12700 whose tails are RISC-V code (ecall/jal) - GSP firmware or other code pages whose bytes matched the expected release pattern. Those pages decode as plausible but bogus method streams, so work executed from them can write garbage into vidmem. Rescued pages now apply the release only (allow_ops=false); work requires a page read through a trusted translation.
* sema: add walk_probe - trace the page-table walk for a VAArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | New module parameter walk_probe <va> runs the recorded-va-space walks and the discovered-directory walk directly (pin/lat/pair map bypassed) with per-level tracing, and prints the result of each. This separates 'the page tables are not walkable' from 'the VA->PA pair map already answers' when a translation is missing. Baseline on a live boot: root PDB entries are zero (L0 e=0 idx=0) so the writes UVM issues into the level pages have no parent entry yet.
* sema: run work at the LAUNCH_DMA release path too; log LAUNCH_DMA inventoryArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | | | The CE pushes UVM's MEMOPS channels submit release through SET_SEMAPHORE_A plus a LAUNCH_DMA with SEMAPHORE_TYPE=RELEASE_ONE_WORD. That path still gated the push's collected fills/copies on the semaphore being readable and behind the payload - the same bootstrap deadlock as the REPORT_SEM path fixed before: the page-table writes that make the semaphores translatable were dropped. Run the work unconditionally there as well (trusted-ring pushes only). Also log a one-line LAUNCH_DMA inventory (channel, engine, dma word, modes, offsets, line length, collected op count) for the first pushes read through rings, which is how the UVM page-table write sequence (fill 512x8 zero + 16-byte PTE copies + release) was identified.
* sema: always run a decoded push's work when the push is reachedArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | The pump gated collected fills/copies on the tracking semaphore being translatable and behind the release payload. On real hardware the work always executes and the release only orders observers, so the gate dropped work exactly when it was needed to bootstrap translations (UVM's CE memsets writing page tables into vidmem, whose tracking semaphores live in the address space those writes create) and skipped pushes as stale as soon as a tracking semaphore advanced past them. Execute the work at the release method for every push read through a trusted ring; swept-RAM decoding still never runs work. Count op runs in the sweep stats (ringops).
* sema: clamp the pin-rewind at ring start - never wrap below zeroArthur Hanson Rasmusson2026-09-28
| | | | | | | The rewind used entries - (N - get) for get < N, which for an empty ring (get=0, put=0) jumped last_get to entries-8, so the pump read ring slots the producer had never reached and could execute stale/garbage entries. Replay only recently consumed slots, clamped at 0.
* sema: re-run recent ring entries when a translation is replacedArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | | | | | A pin injected after the pump consumed pushes that release through that VA resolved against the old (or bogus) translation, so the releases were compared as stale against the old page's values and dropped - a new client that maps fresh pages at the same VAs then waits forever. Rewind every channel's last_get by 8 ring entries on injection so the pump re-reads those pushes under the new translation; the release and fill application paths are forward-progress guarded and idempotent, so re-execution is safe. The handler runs in the service thread, which also runs the pump, so no pass can be in flight during the rewind. Diagnosed from cdt4: its tracker releases were consumed while the pin still pointed at the previous cdt's page (value 1), so payload <= cur and every release was dropped as stale; re-pinning afterwards could not resurrect them because the ring entries had already been consumed.
* sema: never execute work decoded from swept RAM; pin only tracker semsArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | | | | | | | The content sweep reads arbitrary guest RAM and ran the full push decoder on every page, so fabricated method streams in unrelated data executed fills/copies: one boot scanned 65M pages, 'decoded' 124k pushes and ran dozens of memsets from false positives - writes into live guest memory (a guest kernel crashed in nvidia_uvm right after such a boot). - Swept pages now only permit the bounded semaphore-release writes; fills and copies execute only for pushes the pump read through a trusted ring translation. - Pushes read for a compute (GR) channel apply releases only: their method space is not the copy engine's, so aliased encodings must never become memory writes. - sempages.py derives the pages to pin from the client's tracker objects (sem object + sem memory) instead of matching bare sem-object shapes, which pinned 140 pages where the client has ~53 sems; shape scan remains as a fallback when no tracker resolves.
* sema: GR ring autopin must not trust an early base or a pre-existing pinArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | | | | | | | | | | Two failure modes kept every GR channel dark despite the ring layout being known: - The CE region size was latched on the first autopin attempt, which can run before all CE channels are registered; a too-small base then points every GR candidate at a chunk whose entry 0 is zeros, and it stays wrong for the life of the boot. Recompute the base from the live CE ranks on every pass. - An existing pin for a ring VA (e.g. from a convention guess) made the autopin mark the rank done without validating the ring - a wrong USERD is then never corrected. Validate the candidate chunk (entry 0 decode + USERD put/get) first and only fall back to trusting an existing pin when the chunk does not validate; on success overwrite the pin. Also log one diagnostic line per GR rank when the chunk does not validate yet, so a silent autopin failure is visible in dmesg. Live: fresh boot, no manual ring pins - 20/20 GR channels auto-pinned (correct USERD 0x142000 + 0x3000*i) and ran entry 0 (get=1 sub=1) once the push pages were bridged.
* sem: run GR channels - accept CE methods on subchannel 0, discover GR ringsArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | | | | | | | | | - The CE semaphore/memset method groups also arrive on subchannel 0 (CUDA's push library binds the copy class on compute channels to carry the work-submission releases), so the stream decoder accepts both 0 and 4. - GR (compute) channel rings live in the same video-memory allocation as the CE rings, 0x3000 bytes per channel after them: ring (0x2000) at ce_end + 0x3000*rank, USERD at +0x2000. Discover and pin them once the CE ranks are known; verified against ring entry 0 (1 MB aligned push VA in the client window, sane length) and the USERD's put/get, so a layout change costs a failed pin, not a wrong one. Gated by sema_gr_rings (default on). - memprobe: require the sem-VA triple in the sem-object scanner (a bare qword in the window matches thousands of unrelated pointers once the ring/pushbuffer windows are part of the range). Live evidence: ring entries read through the guest's /proc/pid/mem decode to the GR channels' first pushes; pinning the ring (fb 0x140000+0x3000*rank), USERD (ring+0x2000) and first-push pages made all 20 GR channels execute their entry 0 for the first time (get=1 sub=1).
* sema-svc: apply releases promptly and decode compute-push releasesArthur Hanson Rasmusson2026-09-28
| | | | | | | | | | | | | | | | | | The content sweep now: - decodes a release whose method stream continues with any INC_METHOD, not only the CE LAUNCH_DMA group, so the releases at the head of a compute/GR channel's first push are applied too; - remembers releases whose target VA had no translation (deferred list) and retries them every service pass, so a VA->PA injection lands them immediately instead of after the next full sweep; - re-arms the fast sliced sweep for a few seconds after an injection; - treats a channel whose USERD/ring cannot be resolved as stalled, so the sweep keeps looking for the releases its unreadable pushes carry. tools: add per-cdt client-pin helper (sem pages + /dev/nvidia0 windows), sem-page scanner and memprobe fixes (short-read guard, --brief). Live-verified: injecting a client sem page applied 12 deferred releases within a second; the service kept applying (89 -> 202) while cdt ran.
* kernel: add a channel-table dump param; tools: fix memprobe --max parsingArthur Hanson Rasmusson2026-09-26
|
* gsp_sema_service: apply a fast sliced RAM sweep when a channel's pushes stallArthur Hanson Rasmusson2026-09-26
|
* gsp_sema_service: add content rescue for unmapped push-buffer pool VAsArthur Hanson Rasmusson2026-09-25
| | | | | | | | | | - Add expected_sem_payload tracking to svc_channel for CE channels - Implement svc_rescue_push_page() to scan guest RAM for push with expected semaphore release when VA translation fails - Add svc_init_expected_payload() to initialize expected payload from pool - Add rate-limited logging of distinct stalled VAs (svc_log_stalled_va) - Advance expected_sem_payload on successful push decode - Pushes SEMA_MAP_MAX to 65536, SVC_PIN_SLOTS to 32768 for scale
* kernel: enlarge the pin table and its probe window; tools: bridge client ↵Arthur Hanson Rasmusson2026-09-24
| | | | | | | | | | | | | | | | | mappings into the service The pin table became the primary VA->PA store once push-buffer regions and bridged client mappings started adding thousands of pages per boot; at 8192 slots with an 8-probe window, inserts were silently dropped and lookups missed at half load. 32768 slots and a 32-probe window keep the mapped set intact. tools/guest-diag/{guest_pmap_all.py,bridge_sems.sh} translate the CUDA client's /dev/nvidia* mappings through the guest's own pagemap and inject each present page into the service as a sysmem pin. With the client's semaphore pages pinned the service applies their releases into the page the client polls (verified: applied 67 -> 109, misses stop growing for those VAs), where before every write went to the vidmem shadow.
* kernel: resolve semaphores through trusted translations only; tools: dump ↵Arthur Hanson Rasmusson2026-09-24
| | | | | | | | | | | | | | | | | | | the libcuda tracker wait The vidmem window convention turns any VA above the window base into a vidmem offset, but the CUDA client's GPU semaphores are sysmem objects mapped into its address space at those same VAs. A release applied through the convention therefore landed in the vidmem shadow instead of the page the client polls, and the completion was silently lost: the libcuda tracker it waits on never advanced. Semaphore reads and writes now use trusted translations only (pins, learned cache, discovered map, page walks), so an unresolved semaphore is counted as a miss and stays visible instead of corrupting a shadow. tools/guest-diag/trkinfo.py dumps the libcuda tracker the client spins on: the tracker object behind p+0x9410, the semaphore object it references, the u32 semaphore memory it polls (a /dev/nvidiactl mapping backed by guest RAM) and the VMA that memory lives in.
* kernel: self-configure CE rings and push buffers in the semaphore serviceArthur Hanson Rasmusson2026-09-24
| | | | | | | | | | | | | | | | | | | | | The service pins the CE channel rings and push buffers without any guest-supplied addresses. Rings are derived from the channel rank among the live CE channels (ring at FB 0x80000 + 0x20000*rank, USERD at ring + 0x10000) and verified against the ring's first GPFIFO entry before the pin is stored. Push-buffer base pages are found by their first-push signature (SET_OBJECT on subchannel 0, SET_OBJECT on the compute subchannel, tracking-semaphore release at page offset 0x10 with payload 1); the release's in-page slot offset names the channel and the ring's first entry names the push-buffer VA, then the whole 1 MB region is pinned and marked hot. Pinning a pair also re-arms the page-directory discovery and feeds it the verified VA/PA pairs as samples, so the walk can translate the parts of the pool no base page describes. With rings and push buffers pinned the pump executes the submitted work (gpfifo done grows, semaphore releases apply, released kept in vidmem) and the guest kernel UVM waits complete.
* kernel: aperture-aware pinning and UVM CE channel USERD discoveryArthur Hanson Rasmusson2026-09-24
| | | | | | | | | | | | | | | Debug injections could only teach sysmem translations, but the UVM CE channel rings and USERDs live in the frame buffer window, and the progress service had no candidate for their USERD (the allocation parameters carry an offset relative to a client pool, not the FB offset). Add an aperture field to the pinned translations and to the sema_map_add debug parameter (va,pa[,len[,aperture]]), and probe the observed UVM layout as well: the USERD sits one 0x10000 block after the ring for the data-path channels. With the rings pinned, the pump now resolves and decodes the CE rings (the entries point at 1 MB pushbuffer regions); only the pushbuffer VA->PA translation is still missing, so the entries are kept pending.
* kernel: extend RAM scan to the full guest window and rescan hot push pagesArthur Hanson Rasmusson2026-09-24
| | | | | | | | | | | | | | | The learned VA->PA map only covered guest physical addresses below 5 GB, but a 4 GB guest has RAM low plus a remapped window above the PCI hole (top around 6 GB). Structures that landed in the top gigabyte (for example the UVM semaphore pool) were never discovered, which made the semaphore translations flaky from boot to boot: releases then could not be applied and the guest's tracker waits never completed. Scan and accept translations over the full 6 GB window, and rescan the pages that have carried release groups in the rolling sweep (pushbuffer pools are recycled, so those pages hold the next releases). Also log the first distinct release misses and the sweep position so a stuck wait can be told apart from a translation gap.
* kernel: completion-event hints and GSP-RM state introspectionArthur Hanson Rasmusson2026-09-24
| | | | | | | | | | | | | - re-post the completion event for a bounded window after a channel completes work (notifier consumed or semaphore release applied), so a client that starts waiting after the edge-triggered wake-up still gets a wake-up; the OS event classes carry no source object, so the hint broadcasts to the registered events - add rmstate (dump msgq cursors, guest consumption position, event table) and rmpost (post an event record by index or to all) debug parameters, both executing in kthreads because the IOMMU read path only works with a NULL current->mm or the mapping owner's mm - report the underlying error codes from the event post path
* kernel: validate learned semaphore maps and post guest GPU eventsArthur Hanson Rasmusson2026-09-24
| | | | | | | | | | | | | | | - admit {GPU VA -> PA} pairs only when the preceding bytes form a valid client memory descriptor header (type 0/1, CPU+GPU mapped bits), prefer validated pairs over headerless candidates under first-wins dedup, and invalidate the translation cache on every rebuild; fixes stale identity entries shadowing live pool pages and lets the guest UVM channel bring-up complete on its own - capture OS event allocations (class 0x79) and post event records (function 0x1003) into the guest status queue when a channel's busy notification is consumed, with a broadcast fallback, serialized with replies via a queue lock - add BAR0 shadow introspection (dump_bar0/scan_bar0) and guest-side diagnostic scripts for the VM cycle
* kernel: track channels and execute host-class pushed workArthur Hanson Rasmusson2026-09-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | The guest's CUDA stack was stuck inside context creation because the work it submits is never executed by the emulated GPU. Two forms of pushed work were missing, and the completion path had grown far too slow to be useful: - Channel tracking: on a channel allocation parse the GPFIFO GPU VA and entry count, the USERD address/aperture and the instance block, hand them to the progress service and drop them again when the channel is freed. - Host-class (C46F) semaphore releases: pushes on a compute channel signal progress with a five-dword method run (SEM_ADDR_LO/HI, PAYLOAD_LO/HI, EXECUTE) rather than the copy-engine group the service already understood, so those releases were never applied. Decode both forms. - Emulated vidmem: channel blocks (USERD/instance) and some client semaphores live in the emulated frame buffer, whose VAs are a window over the BAR1 backing rather than guest RAM; access them through the right aperture. - Latency: the service's full-RAM sweep took seconds per pass, so guests' progress waits took whole seconds and the driver tore its own setup back down in the meantime. Sweep guest RAM in bounded, chunked windows on every pass, remember the pages pushes are actually found in and revisit those first, and keep the VA->PA map complete (dedup, sort, binary search) so semaphores resolve reliably. Also add a vidmem poke parameter for bringing up and debugging emulated frame-buffer state.
* kernel: execute pushed CE work (PTE memsets, copies) and track semaphoresArthur Hanson Rasmusson2026-09-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The progress service now decodes push buffers as method streams and performs the work the driver pushes, not just the tracking semaphore: - C5B5 method decoder: SET_REMAP_CONST_A/B + COMPONENTS + OFFSET_OUT + LINE_LENGTH_IN + LAUNCH_DMA = memset (into vidmem or guest RAM); OFFSET_IN + OFFSET_OUT + LAUNCH_DMA = copy; SET_SEMAPHORE_A/B/PAYLOAD + LAUNCH_DMA = release. Contiguous method runs (count 2/4) are applied in full - OFFSET_IN/OUT arrive as one run. - Pushes span page boundaries, so pages are decoded as method streams without a start marker. Collected operations execute only when the push's release is reached and still pending (payload ahead of the semaphore), so recycled buffers replaying old pushes are skipped and their stale memsets cannot overwrite newer state. - VA->PA map is first-wins: stale copies of freed allocations and unrelated adjacent u64 pairs produced bogus entries that hijacked a good mapping and sent semaphore writes to the wrong page. - dump_guest module parameter (hex dump of guest PA, kthread via completion; kthread_stop before the thread runs loses the work). With this the guest no longer stalls in uvm_tracker_wait and no longer oopses in the UVM path; the failure moved to a userspace segfault inside libcuda (NULL-0x38) after the driver's page allocations. Also add tools/cuda-ab: run one deterministic CUDA workload on the host (bare metal oracle) and in the guest, then compare the stable result lines. The binary links the CUDA runtime statically so the guest only needs the driver's libcuda.so.
* kernel: semaphore service forward-jump completion, stats, sema_probeArthur Hanson Rasmusson2026-09-23
| | | | | | | | | Relax the in-order rule to forward progress (payload > current), with the jump bounded and counted: UVM tolerates forward jumps up to 2M (2 * UVM_CHANNEL_NUM_GPFIFO_ENTRIES_MAX), and push buffers are recycled so intermediate pushes can be missed. Add miss/stale/jump counters to the rebuild log and a sema_probe module parameter to dump the service's map entry and live slot values for a GPU VA (diagnostics for tracker stalls).
* Open-IOV: initial public releaseOpen-IOV2026-09-23
Open-IOV virtualizes NVIDIA GPUs so that unmodified guest drivers run with real GPU functionality - CUDA first, 3D and video to follow - on unmodified hosts, without a proprietary vGPU license and without patching any driver, firmware or hypervisor. Core principle: emulate the interface, pass through the work. kernel/ open-iov-vfio.ko - host VFIO mdev driver: virtual GPU device (PCI config space, BAR shadows, MSI-X), GSP boot emulation, GSP-RM message-queue/RPC emulation, memory model (GPU-VA to guest-PA discovery) and the semaphore-completion service that advances guest UVM progress. userspace/ libiov.so management API and examples. tools/ guest diagnostics, firmware analysis wrappers, RM probes. scripts/ stack manager, VM harness, build/load/test automation. config/ hardware/version profiles (the portability surface). docs/ documentation tree - start at docs/README.md. wiki/ long-form firmware and protocol deep dives. Status: initialization works end to end for a stock 570.144 Linux guest on Turing (TU104): driver probe, nvidia-smi, the full GSP-RM control battery, object creation and the early CUDA/UVM start-up path. GPU work forwarding - the step that makes CUDA kernels execute on real hardware - is the active work item; see docs/04-implementation/01-known-knowns-and-unknowns.md. License: BSD-3-Clause for the project; GPL-2.0 for kernel modules that link GPL-only kernel interfaces. See LICENSE and docs/09-reference/legal-and-licensing.md.