summaryrefslogtreecommitdiffstats
path: root/wiki/vGPU-IO-Integration-Guide.md
diff options
context:
space:
mode:
authorOpen-IOV <dev@open-iov.org>2026-09-23 05:44:08 -0400
committerOpen-IOV <dev@open-iov.org>2026-09-23 05:46:43 -0400
commit2302fc09080bad51c73f293294e19fd4db464eb0 (patch)
treec722d186347fdef5a34131e9e143b1549b1daf8e /wiki/vGPU-IO-Integration-Guide.md
downloadopen-iov-2302fc09080bad51c73f293294e19fd4db464eb0.tar.gz
open-iov-2302fc09080bad51c73f293294e19fd4db464eb0.zip
Open-IOV: initial public release
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.
Diffstat (limited to 'wiki/vGPU-IO-Integration-Guide.md')
-rw-r--r--wiki/vGPU-IO-Integration-Guide.md480
1 files changed, 480 insertions, 0 deletions
diff --git a/wiki/vGPU-IO-Integration-Guide.md b/wiki/vGPU-IO-Integration-Guide.md
new file mode 100644
index 0000000..6e248c9
--- /dev/null
+++ b/wiki/vGPU-IO-Integration-Guide.md
@@ -0,0 +1,480 @@
+# vGPU-IO Integration Guide
+
+## Overview
+This guide covers implementing a Linux kernel driver for vGPU-IO using the GSP 570.144W firmware RPC interface.
+
+## Architecture
+
+```
+┌─────────────────────────────────────────────────────────────┐
+│ vGPU-IO Kernel Driver │
+├─────────────────────────────────────────────────────────────┤
+│ gsp_core.c │ gsp_rpc.c │ gsp_vf.c │
+│ - Device probe │ - RPC client │ - VF lifecycle │
+│ - BAR mapping │ - Doorbell │ - Migration │
+│ - IRQ/MSI-X │ - Completion │ - WPR/BAR integration │
+├─────────────────────────────────────────────────────────────┤
+│ GSP Firmware (570.144W) │
+│ Primary Dispatcher (0x057A1AC0) │ Secondary (0x04ED39DC) │
+│ BAR Handler (0x04CB8188) │ WPR Handlers │
+│ Migration (0x04179ED8/0x04179FBC)│ SCHED/ALLOC/PIN │
+└─────────────────────────────────────────────────────────────┘
+```
+
+## Module Structure
+
+```
+drivers/gpu/nvidia/gsp/
+├── gsp.h # Core definitions
+├── gsp_rpc.h # RPC message formats
+├── gsp_vf.h # VF definitions
+├── gsp_bar.h # BAR emulation
+├── gsp_wpr.h # WPR management
+├── gsp_migration.h # Migration protocol
+├── gsp_core.c # Probe/remove, BAR/IRQ
+├── gsp_rpc.c # RPC client implementation
+├── gsp_vf.c # VF create/destroy
+├── gsp_bar.c # BAR trap handler
+├── gsp_wpr.c # WPR protect/unprotect
+├── gsp_migration.c # Live migration
+└── gsp_debugfs.c # Debug interface
+```
+
+## Core Data Structures
+
+### GSP Device
+```c
+struct gsp_device {
+ struct pci_dev *pdev;
+ void __iomem *bar0; // PCIe BAR0 mapping
+ void __iomem *bar1; // PCIe BAR1 (GSP FW)
+ struct gsp_firmware *fw; // Firmware image
+ struct gsp_rpc_client *rpc; // RPC client
+ struct mutex vf_lock;
+ struct idr vf_idr; // VF ID allocator
+ struct list_head vf_list;
+ struct gsp_debugfs *debugfs;
+ spinlock_t doorbell_lock;
+ uint32_t doorbell_seq;
+};
+```
+
+### VF (Virtual Function)
+```c
+struct gsp_vf {
+ struct gsp_device *gsp;
+ uint32_t id; // VF ID (1-7)
+ struct kref ref;
+ struct mutex lock;
+ mig_state_t mig_state;
+ struct gsp_migration *migration;
+ uint64_t bar1_offset; // BAR1 aperture offset
+ uint64_t bar1_size; // BAR1 aperture size
+ uint64_t pt_base; // Page table base
+ uint64_t pt_size; // Page table size
+ uint64_t cmd_base; // Command buffer base
+ uint64_t cmd_size; // Command buffer size
+ struct gsp_wpr_region *wpr_regions;
+ struct list_head wpr_list;
+ struct gsp_bar_state bar_state;
+ atomic_t refcount;
+ bool active;
+};
+```
+
+## Initialization Sequence
+
+### 1. PCI Probe
+```c
+static int gsp_probe(struct pci_dev *pdev, const struct pci_device_id *id) {
+ struct gsp_device *gsp;
+ int ret;
+
+ gsp = devm_kzalloc(&pdev->dev, sizeof(*gsp), GFP_KERNEL);
+ gsp->pdev = pdev;
+ pci_set_drvdata(pdev, gsp);
+
+ // Enable PCI device
+ ret = pcim_enable_device(pdev);
+ if (ret) return ret;
+
+ // Map BARs
+ gsp->bar0 = pcim_iomap(pdev, 0, 0);
+ gsp->bar1 = pcim_iomap(pdev, 1, 0);
+ if (!gsp->bar0 || !gsp->bar1) return -ENOMEM;
+
+ // Load firmware
+ ret = gsp_firmware_load(gsp, "gsp-570.144.fwimage.bin");
+ if (ret) return ret;
+
+ // Initialize RPC client
+ gsp->rpc = gsp_rpc_client_init(gsp);
+ if (IS_ERR(gsp->rpc)) return PTR_ERR(gsp->rpc);
+
+ // Setup IRQ/MSI-X
+ ret = gsp_setup_irq(gsp);
+ if (ret) return ret;
+
+ // Initialize debugfs
+ gsp_debugfs_init(gsp);
+
+ return 0;
+}
+```
+
+### 2. Firmware Loading
+```c
+int gsp_firmware_load(struct gsp_device *gsp, const char *name) {
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, name, &gsp->pdev->dev);
+ if (ret) return ret;
+
+ // Verify MD5: 13ce12a392a31eeb79a2e6ebd3a4a93a
+ if (!gsp_firmware_verify(fw->data, fw->size)) {
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ // Load to GSP memory (via BAR1)
+ ret = gsp_firmware_upload(gsp, fw->data, fw->size);
+ release_firmware(fw);
+
+ return ret;
+}
+```
+
+### 3. GSP Boot
+```c
+int gsp_boot(struct gsp_device *gsp) {
+ // 1. Reset GSP
+ writel(1, gsp->bar0 + GSP_RESET_REG);
+ msleep(10);
+ writel(0, gsp->bar0 + GSP_RESET_REG);
+
+ // 2. Wait for entry point (0x04009000) to signal ready
+ ret = gsp_wait_for_ready(gsp, 5000); // 5s timeout
+ if (ret) return ret;
+
+ // 3. Initialize RPC dispatchers
+ ret = gsp_rpc_init_dispatchers(gsp);
+ if (ret) return ret;
+
+ return 0;
+}
+```
+
+## RPC Client Implementation
+
+### Doorbell Mechanism
+```c
+#define GSP_DOORBELL_OFFSET 0x1000
+#define GSP_MSG_RING_SIZE 256
+#define GSP_MSG_MAX_SIZE 256
+
+struct gsp_rpc_client {
+ struct gsp_device *gsp;
+ struct mutex lock;
+ uint32_t seq;
+ wait_queue_head_t wq;
+ struct gsp_msg_ring *ring;
+ struct completion *pending[GSP_MAX_PENDING];
+};
+
+static int gsp_rpc_send_sync(struct gsp_rpc_client *rpc,
+ uint32_t rpc_type,
+ void *payload, size_t payload_size,
+ void *response, size_t *response_size) {
+ struct gsp_msg msg = {
+ .hdr = {
+ .magic = 0x47535052,
+ .version = 1,
+ .rpc_type = rpc_type,
+ .sequence = atomic_inc_return(&rpc->seq),
+ .timestamp_ns = ktime_get_ns(),
+ .payload_size = payload_size,
+ .flags = MSG_SYNC,
+ }
+ };
+
+ struct completion done;
+ init_completion(&done);
+
+ mutex_lock(&rpc->lock);
+ rpc->pending[msg.hdr.sequence % GSP_MAX_PENDING] = &done;
+
+ // Copy message to ring buffer
+ memcpy(msg.hdr.payload, payload, payload_size);
+ gsp_ring_write(rpc->ring, &msg, GSP_MSG_MAX_SIZE);
+
+ // Ring doorbell
+ writel(1, rpc->gsp->bar0 + GSP_DOORBELL_OFFSET);
+
+ mutex_unlock(&rpc->lock);
+
+ // Wait for completion
+ if (!wait_for_completion_timeout(&done, msecs_to_jiffies(5000)))
+ return -ETIMEDOUT;
+
+ // Copy response
+ if (response && response_size) {
+ *response_size = min(*response_size, done.payload_size);
+ memcpy(response, done.payload, *response_size);
+ }
+
+ return done.status;
+}
+```
+
+### Completion Handler (ISR)
+```c
+static irqreturn_t gsp_isr(int irq, void *data) {
+ struct gsp_device *gsp = data;
+ struct gsp_msg msg;
+
+ while (gsp_ring_read(gsp->rpc->ring, &msg)) {
+ if (msg.hdr.flags & MSG_SYNC) {
+ struct completion *done =
+ gsp->rpc->pending[msg.hdr.sequence % GSP_MAX_PENDING];
+ if (done) {
+ done->status = msg.payload.status;
+ done->payload_size = msg.hdr.payload_size;
+ memcpy(done->payload, msg.payload.data, msg.hdr.payload_size);
+ complete(done);
+ }
+ } else {
+ // Async notification
+ gsp_handle_notification(gsp, &msg);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+```
+
+## VF Lifecycle
+
+### Create VF
+```c
+int gsp_vf_create(struct gsp_device *gsp, uint32_t vf_id,
+ const struct gsp_vf_config *config) {
+ struct gsp_vf *vf;
+ int ret;
+
+ mutex_lock(&gsp->vf_lock);
+
+ if (idr_alloc(&gsp->vf_idr, NULL, vf_id, vf_id + 1, GFP_KERNEL) < 0) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ vf = kzalloc(sizeof(*vf), GFP_KERNEL);
+ vf->gsp = gsp;
+ vf->id = vf_id;
+ kref_init(&vf->ref);
+ mutex_init(&vf->lock);
+ INIT_LIST_HEAD(&vf->wpr_list);
+
+ // Configure VF resources
+ vf->bar1_offset = config->bar1_offset;
+ vf->bar1_size = config->bar1_size;
+ vf->pt_base = config->pt_base;
+ vf->pt_size = config->pt_size;
+ vf->cmd_base = config->cmd_base;
+ vf->cmd_size = config->cmd_size;
+
+ // Initialize WPR for VF
+ ret = gsp_vf_wpr_init(vf);
+ if (ret) goto err_wpr;
+
+ // Initialize BAR for VF
+ ret = gsp_vf_bar_init(vf);
+ if (ret) goto err_bar;
+
+ list_add(&vf->list, &gsp->vf_list);
+ vf->active = true;
+
+ mutex_unlock(&gsp->vf_lock);
+ return 0;
+
+err_bar:
+ gsp_vf_wpr_fini(vf);
+err_wpr:
+ idr_remove(&gsp->vf_idr, vf_id);
+ kfree(vf);
+unlock:
+ mutex_unlock(&gsp->vf_lock);
+ return ret;
+}
+```
+
+### Destroy VF
+```c
+void gsp_vf_destroy(struct gsp_vf *vf) {
+ struct gsp_device *gsp = vf->gsp;
+ uint32_t id = vf->id;
+
+ mutex_lock(&gsp->vf_lock);
+ vf->active = false;
+ list_del(&vf->list);
+ mutex_unlock(&gsp->vf_lock);
+
+ gsp_vf_bar_fini(vf);
+ gsp_vf_wpr_fini(vf);
+
+ if (vf->migration)
+ gsp_migration_cancel(vf->migration);
+
+ kref_put(&vf->ref, gsp_vf_release);
+}
+
+static void gsp_vf_release(struct kref *ref) {
+ struct gsp_vf *vf = container_of(ref, struct gsp_vf, ref);
+ kfree(vf);
+}
+```
+
+## Memory Management (ALLOC/PIN)
+
+### Allocate VF Memory
+```c
+int gsp_vf_mem_alloc(struct gsp_vf *vf,
+ uint64_t size, uint32_t flags,
+ uint64_t *handle, uint64_t *va) {
+ struct alloc_payload payload = {
+ .size = size,
+ .type = MEM_TYPE_VRAM,
+ .alignment = 0x1000,
+ .va_hint = 0,
+ .flags = flags,
+ .pid = current->pid,
+ .vf_id = vf->id,
+ };
+
+ struct alloc_response resp;
+ size_t resp_size = sizeof(resp);
+
+ return gsp_rpc_send_sync(vf->gsp->rpc, RPC_ALLOC,
+ &payload, sizeof(payload),
+ &resp, &resp_size);
+}
+```
+
+### Pin Memory for DMA
+```c
+int gsp_vf_mem_pin(struct gsp_vf *vf, uint64_t handle,
+ uint64_t offset, uint64_t size,
+ uint64_t *dma_addr) {
+ struct pin_payload payload = {
+ .handle = handle,
+ .offset = offset,
+ .size = size,
+ .vf_id = vf->id,
+ .flags = PIN_WRITE | PIN_READ,
+ };
+
+ struct pin_response resp;
+ size_t resp_size = sizeof(resp);
+
+ return gsp_rpc_send_sync(vf->gsp->rpc, RPC_PIN,
+ &payload, sizeof(payload),
+ &resp, &resp_size);
+}
+```
+
+## Debugging & Testing
+
+### Debugfs Interface
+```bash
+# List VFs
+cat /sys/kernel/debug/gsp/vfs
+
+# VF details
+cat /sys/kernel/debug/gsp/vf/1/status
+
+# RPC statistics
+cat /sys/kernel/debug/gsp/rpc/stats
+
+# BAR state
+cat /sys/kernel/debug/gsp/vf/1/bar
+
+# WPR regions
+cat /sys/kernel/debug/gsp/vf/1/wpr
+
+# Migration status
+cat /sys/kernel/debug/gsp/vf/1/migration
+```
+
+### Trace Events
+```bash
+# Enable tracing
+echo 1 > /sys/kernel/debug/tracing/events/gsp/enable
+
+# Trace migration
+trace-cmd record -e gsp_mig_phase -e gsp_mig_transfer
+
+# Trace WPR
+trace-cmd record -e gsp_wpr_event
+```
+
+### Unit Tests
+```c
+// kselftest for gsp-rpc
+static void test_rpc_alloc(void) {
+ struct gsp_vf *vf = create_test_vf();
+ uint64_t handle, va;
+
+ ASSERT_EQ(gsp_vf_mem_alloc(vf, 4096, 0, &handle, &va), 0);
+ ASSERT_NE(handle, 0);
+ ASSERT_NE(va, 0);
+
+ gsp_vf_mem_free(vf, handle);
+ destroy_test_vf(vf);
+}
+```
+
+## Error Handling Checklist
+
+| Scenario | Detection | Recovery |
+|----------|-----------|----------|
+| GSP firmware crash | Watchdog timeout | Reset GSP, reload FW |
+| RPC timeout | Doorbell no response | Retry, then VF reset |
+| BAR trap storm | Rate limit exceeded | Throttle VF |
+| WPR violation | Callback storm | Quarantine VF |
+| Migration fail | Commit verify fail | Rollback to source |
+
+## Performance Tuning
+
+### RPC Batching
+```c
+// Batch multiple ALLOCs in single RPC
+struct batch_alloc_payload {
+ uint32_t count;
+ struct alloc_payload allocs[MAX_BATCH];
+};
+```
+
+### Async Completion
+```c
+// Use async RPC for non-critical paths
+gsp_rpc_send_async(rpc, RPC_NOTIFY, payload, size, callback, ctx);
+```
+
+### Memory Pool
+```c
+// Pre-allocate bounce buffers
+struct gsp_bounce_pool {
+ struct page **pages;
+ int count;
+ spinlock_t lock;
+};
+```
+
+---
+
+## Reference
+- GSP Firmware: gsp-570.144.fwimage.bin
+- Base Address: 0x04000000
+- Primary Dispatcher: 0x057A1AC0
+- Secondary Dispatcher: 0x04ED39DC \ No newline at end of file