| Commit message (Collapse) | Author | Age |
| | |
|
| |
|
|
|
|
| |
Guest driver was receiving SUCCESS replies as 'unexpected events' (0x48, 0x49).
These async init RPCs are fire-and-forget per GSP-RM protocol; driver doesn't
expect a reply on the status queue. CONTINUATION_RECORD still sends SUCCESS.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- Added TU104_CTRL_INTERNAL_MEMSYS_L2_INVALIDATE_EVICT (0x20800a6c)
- Added TU104_CTRL_INTERNAL_GR_GET_FECS_TRACE_HW_ENABLE (0x20800a38)
- Added TU104_CTRL_SYSTEM_MAP_SHARED_DATA (0x730151)
- Fixed async RPCs (72 GSP_SET_SYSTEM_INFO, 73 SET_REGISTRY, 71 CONTINUATION_RECORD)
to send SUCCESS replies instead of silent consume
- Added explicit handlers for RPC 47 (UNLOADING_GUEST_DRIVER) and 70 (UPDATE_BAR_PDE)
with proper reply semantics
Guest driver was failing at GSP-RM level with unknown RPCs 47, 70, 72, 73.
Channels registered then immediately unregistered.
Now they should stay registered and complete initialization.
|
| |
|
|
|
|
|
|
|
|
| |
- 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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
- 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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- 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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Two more retry loops surfaced once the guest driver got past the CE binding:
- BAR0 region reads returned -EINVAL ("would be handled by mmap"), so a
QEMU-trapped read of BAR0+0x88084 failed and the driver polled it forever.
Serve reads from the BAR0 shadow/trap handler (and mirror BAR1 reads from
the emulated vidmem backing).
- Config-space writes above offset 0xFF were refused with -EINVAL, so the
driver's write to extended config 0x704 (PCIe device control area) never
took effect and it retried. Accept and store extended-space writes; keep
the legacy identity registers fixed.
|
| |
|
|
|
|
|
|
|
|
| |
The mdev's region write handler returned success without touching the BAR0
shadow or the trap table, so register writes that arrive through the VFIO
region path (QEMU-trapped accesses) never took effect. A fresh guest then
polled a register that never changed and spun forever in cuInit (QEMU log:
vfio_region_write(mdev:region0+0x88704) failed: Resource temporarily
unavailable). Route those writes to the BAR0 shadow/trap handler and mirror
BAR1 writes into the emulated vidmem backing.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- GSP_RM_ALLOC: echo the request payload back with status forced to NV_OK.
The kernel driver copies the reply params over the caller's params buffer
using the class-expected size, so a zeroed reply smashed libcuda's stack
(SIGSEGV at the engine-registration continuation); echoing makes the
copy-back idempotent.
- CE_GET_PHYSICAL_CAPS / CE_GET_ALL(_PHYSICAL)_CAPS: report sysmem, P2P and
BL copy caps and mark the GR-synchronous CE (GRCE, COPY0). Without a GRCE
the client's context walk ends with an empty secondary-engine record and
the engine RM alloc is issued with class 0 (rejected -> cuCtxCreate fails).
- TU104 engine table: CE0 shares the GR PBDMA ids (the driver's GR/GRCE
runqueue validation requires it), plus an entry for the async copy engine
(COPY14) advertised in the GSP static info engine caps.
- tools/guest-diag/ioctl_trace: decode the RM status fields of alloc,
control and free so the first failing driver call is visible in traces.
gitignore: keep the CUDA analysis scratch tree (incl. WORKING-HERE.md) local.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
| |
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 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.
|