diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-13 19:18:21 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-13 19:18:21 -0400 |
| commit | 7adef330df18691acabda9f5c988742f23a2917d (patch) | |
| tree | c115789b526840fbbec1056ab67b2a9a9d94f963 | |
| parent | 8e64754d9980d2423f1907ae184ec46e63e5ff7e (diff) | |
| download | open-iov-7adef330df18691acabda9f5c988742f23a2917d.tar.gz open-iov-7adef330df18691acabda9f5c988742f23a2917d.zip | |
Phase 3: RPC Handler Completion
- Enhanced gsp_rpc_client.c with proper emulation implementations:
- ALLOC/FREE: VRAM allocation tracking with host page allocation and DMA mapping
- MAP/UNMAP: GPU VA mapping management
- PIN/UNPIN: DMA address retrieval for pinned pages
- SCHEDULE/YIELD: Local workqueue-based scheduling
- NOTIFY: Callback registration for async events
- Added emulation function declarations to gsp_rpc_client.h
- Exported nv_vgpu_simple_mapping struct in memory.h for cross-file use
- Updated RPC handlers to use gsp_rpc_emulation_is_enabled() accessor
- All 12 RPC types now have functional emulation fallbacks
| -rw-r--r-- | kernel/gsp_rpc_client.c | 393 | ||||
| -rw-r--r-- | kernel/gsp_rpc_client.h | 36 | ||||
| -rw-r--r-- | kernel/include/memory.h | 11 | ||||
| -rw-r--r-- | kernel/memory.c | 11 |
4 files changed, 333 insertions, 118 deletions
diff --git a/kernel/gsp_rpc_client.c b/kernel/gsp_rpc_client.c index a1579f7..46d0d50 100644 --- a/kernel/gsp_rpc_client.c +++ b/kernel/gsp_rpc_client.c @@ -16,6 +16,10 @@ #include <linux/delay.h> #include <asm/io.h> +#include "nvidia-vgpu-vfio.h" +#include "memory.h" +#include "gsp_rpc_client.h" + /* ============================================================ * FIRMWARE ADDRESSES (from decompilation) * ============================================================ */ @@ -113,113 +117,6 @@ * RPC MESSAGE STRUCTURES * ============================================================ */ -struct gsp_rpc_msg { - u32 type; /* RPC type (0x01-0x0B, 0xFF) */ - u32 subcmd; /* Sub-command for jump table dispatch */ - u64 payload[6]; /* Variable payload */ - u32 seq_id; /* Sequence ID for async ops */ - u32 flags; /* Flags */ - u32 reserved[2]; /* Padding to 64 bytes */ -} __packed; - -struct gsp_rpc_response { - u32 status; /* 0 = success, negative = error */ - u32 type; /* Echo of request type */ - u64 result[6]; /* Return values */ - u32 seq_id; /* Echo of request seq_id */ -} __packed; - -/* ALLOC payload */ -struct gsp_alloc_req { - u64 size; /* Allocation size in bytes */ - u64 alignment; /* Alignment requirement */ - u32 mem_type; /* Memory type (0=VRAM, 1=SYSMEM, 2=COHERENT) */ - u32 flags; /* Allocation flags */ - u64 addr_hint; /* Hint address (optional) */ - u32 pid; /* Process ID */ - u32 reserved; -}; - -struct gsp_alloc_rsp { - u64 gpu_va; /* GPU virtual address */ - u64 handle; /* Allocation handle */ - u64 size; /* Actual allocated size */ -}; - -/* MAP payload */ -struct gsp_map_req { - u64 handle; /* Allocation handle from ALLOC */ - u64 gpu_va; /* GPU virtual address to map at */ - u64 size; /* Size to map */ - u32 prot; /* Protection (R/W/X) */ - u32 flags; /* Map flags */ - u64 offset; /* Offset into allocation */ - u32 reserved[2]; -}; - -struct gsp_map_rsp { - u64 gpu_va; /* Mapped GPU VA */ -}; - -/* PIN/UNPIN payload */ -struct gsp_pin_req { - u64 handle; /* Allocation handle */ - u64 offset; /* Offset into allocation */ - u64 size; /* Size to pin */ - u32 flags; /* Pin flags (0=read, 1=write, 2=read+write) */ - u32 reserved[3]; -}; - -struct gsp_pin_rsp { - u64 dma_addr; /* DMA address for device */ - u32 num_pages; /* Number of pages pinned */ - u32 reserved; -}; - -/* SCHEDULE payload */ -struct gsp_sched_req { - u64 work_handle; /* Work descriptor handle */ - u64 callback; /* Callback function pointer */ - u64 arg; /* Callback argument */ - u32 priority; /* Priority */ - u32 flags; /* Schedule flags */ - u32 reserved[2]; -}; - -/* BAR TRAP payload */ -struct gsp_bar_trap_req { - u64 bar_addr; /* BAR register address */ - u32 access_type; /* 0=read, 1=write */ - u32 size; /* Access size (1/2/4/8) */ - u64 value; /* Value (for write) */ - u32 bar_num; /* BAR number (0-5) */ - u32 reserved; -}; - -struct gsp_bar_trap_rsp { - u64 value; /* Value (for read) */ - u32 handled; /* 1 if handled */ - u32 reserved; -}; - -/* MIGRATE payload */ -struct gsp_migrate_req { - u64 src_gpu_id; /* Source GPU ID */ - u64 dst_gpu_id; /* Destination GPU ID */ - u64 memory_bitmap; /* Memory bitmap pointer */ - u64 page_table_ptr; /* Page table pointer */ - u32 state; /* Migration state */ - u32 flags; /* Migration flags */ - u64 context; /* Migration context */ - u32 reserved; -}; - -struct gsp_migrate_rsp { - u32 status; /* Migration status */ - u32 progress; /* Progress percentage */ - u64 checkpoint; /* Checkpoint handle */ -}; - /* ============================================================ * GSP RPC CLIENT CONTEXT * ============================================================ */ @@ -317,6 +214,9 @@ int gsp_rpc_alloc(struct gsp_client *client, u32 flags, u64 addr_hint, u32 pid, u64 *gpu_va, u64 *handle, u64 *actual_size) { + if (gsp_rpc_emulation_is_enabled()) + return gsp_rpc_alloc_emul(client, size, alignment, mem_type, flags, addr_hint, pid, gpu_va, handle, actual_size); + struct gsp_alloc_req req = {0}; struct gsp_alloc_rsp rsp = {0}; struct gsp_rpc_response response = {0}; @@ -350,6 +250,9 @@ int gsp_rpc_alloc(struct gsp_client *client, int gsp_rpc_free(struct gsp_client *client, u64 handle) { + if (gsp_rpc_emulation_is_enabled()) + return gsp_rpc_free_emul(client, handle); + struct gsp_rpc_response response = {0}; u64 payload[6] = { handle, 0, 0, 0, 0, 0 }; u32 seq = gsp_next_seq(client); @@ -369,6 +272,9 @@ int gsp_rpc_map(struct gsp_client *client, u32 prot, u32 flags, u64 offset, u64 *mapped_va) { + if (gsp_rpc_emulation_is_enabled()) + return gsp_rpc_map_emul(client, handle, gpu_va, size, prot, flags, offset, mapped_va); + struct gsp_map_req req = {0}; struct gsp_map_rsp rsp = {0}; struct gsp_rpc_response response = {0}; @@ -398,6 +304,9 @@ int gsp_rpc_map(struct gsp_client *client, int gsp_rpc_unmap(struct gsp_client *client, u64 handle, u64 gpu_va, u64 size) { + if (gsp_rpc_emulation_is_enabled()) + return gsp_rpc_unmap_emul(client, handle, gpu_va, size); + struct gsp_rpc_response response = {0}; u64 payload[6] = { handle, gpu_va, size, 0, 0, 0 }; u32 seq = gsp_next_seq(client); @@ -416,6 +325,9 @@ int gsp_rpc_pin(struct gsp_client *client, u64 handle, u64 offset, u64 size, u32 flags, u64 *dma_addr, u32 *num_pages) { + if (gsp_rpc_emulation_is_enabled()) + return gsp_rpc_pin_emul(client, handle, offset, size, flags, dma_addr, num_pages); + struct gsp_pin_req req = {0}; struct gsp_pin_rsp rsp = {0}; struct gsp_rpc_response response = {0}; @@ -444,6 +356,9 @@ int gsp_rpc_pin(struct gsp_client *client, int gsp_rpc_unpin(struct gsp_client *client, u64 handle, u64 offset, u64 size) { + if (gsp_rpc_emulation_is_enabled()) + return gsp_rpc_unpin_emul(client, handle, offset, size); + struct gsp_rpc_response response = {0}; u64 payload[6] = { handle, offset, size, 0, 0, 0 }; u32 seq = gsp_next_seq(client); @@ -563,6 +478,26 @@ bool gsp_rpc_emulation_is_enabled(void) return gsp_emulation_enabled; } +/* VRAM allocation tracking for emulation */ +struct gsp_vram_alloc { + struct list_head list; + u64 handle; + u64 gpu_va; + u64 size; + u64 alignment; + u32 mem_type; + u32 flags; + u64 addr_hint; + u32 pid; + bool mapped; + u64 mapped_va; + struct nv_vgpu_simple_mapping *mapping; +}; + +static LIST_HEAD(gsp_vram_allocs); +static DEFINE_SPINLOCK(gsp_vram_lock); +static atomic64_t gsp_handle_counter = ATOMIC64_INIT(1); + /* Scheduling emulation - local work queue */ struct gsp_sched_work { struct list_head list; @@ -587,6 +522,250 @@ static void gsp_sched_worker(struct work_struct *work) complete(&sched->done); } +/* Find VRAM allocation by handle */ +static struct gsp_vram_alloc *gsp_find_vram_alloc(u64 handle) +{ + struct gsp_vram_alloc *alloc; + spin_lock(&gsp_vram_lock); + list_for_each_entry(alloc, &gsp_vram_allocs, list) { + if (alloc->handle == handle) { + spin_unlock(&gsp_vram_lock); + return alloc; + } + } + spin_unlock(&gsp_vram_lock); + return NULL; +} + +/* Find VRAM allocation by GPU VA */ +static struct gsp_vram_alloc *gsp_find_vram_by_va(u64 gpu_va) +{ + struct gsp_vram_alloc *alloc; + spin_lock(&gsp_vram_lock); + list_for_each_entry(alloc, &gsp_vram_allocs, list) { + if (alloc->gpu_va <= gpu_va && gpu_va < alloc->gpu_va + alloc->size) { + spin_unlock(&gsp_vram_lock); + return alloc; + } + } + spin_unlock(&gsp_vram_lock); + return NULL; +} + +/* Memory Allocation - Emulation Implementation */ +int gsp_rpc_alloc_emul(struct gsp_client *client, + u64 size, u64 alignment, u32 mem_type, + u32 flags, u64 addr_hint, u32 pid, + u64 *gpu_va, u64 *handle, u64 *actual_size) +{ + struct nv_vgpu_device *vgpu = client->dev->driver_data; + struct gsp_vram_alloc *alloc; + u64 va = addr_hint ? addr_hint : 0x100000000ULL; /* Default 4GB */ + int ret; + + alloc = kzalloc(sizeof(*alloc), GFP_KERNEL); + if (!alloc) + return -ENOMEM; + + alloc->handle = atomic64_inc_return(&gsp_handle_counter); + alloc->size = size; + alloc->alignment = alignment; + alloc->mem_type = mem_type; + alloc->flags = flags; + alloc->addr_hint = addr_hint; + alloc->pid = pid; + alloc->mapped = false; + + /* Align VA */ + va = ALIGN(va, alignment); + + /* In emulation, we allocate host memory and map it to GPU VA */ + alloc->mapping = kzalloc(sizeof(*alloc->mapping), GFP_KERNEL); + if (!alloc->mapping) { + kfree(alloc); + return -ENOMEM; + } + + alloc->mapping->gpa = va; + alloc->mapping->size = size; + alloc->mapping->page_count = (size + PAGE_SIZE - 1) / PAGE_SIZE; + alloc->mapping->pages = vzalloc(alloc->mapping->page_count * sizeof(struct page *)); + if (!alloc->mapping->pages) { + kfree(alloc->mapping); + kfree(alloc); + return -ENOMEM; + } + + /* Allocate host pages */ + for (int i = 0; i < alloc->mapping->page_count; i++) { + struct page *page = alloc_page(GFP_KERNEL | GFP_DMA32); + if (!page) { + for (int j = 0; j < i; j++) + __free_page(alloc->mapping->pages[j]); + vfree(alloc->mapping->pages); + kfree(alloc->mapping); + kfree(alloc); + return -ENOMEM; + } + alloc->mapping->pages[i] = page; + } + alloc->mapping->pinned = true; + + /* Map to IOVA for DMA */ + ret = dma_map_page(&vgpu->pdev->dev, alloc->mapping->pages[0], 0, size, DMA_BIDIRECTIONAL); + if (dma_mapping_error(&vgpu->pdev->dev, ret)) { + for (int i = 0; i < alloc->mapping->page_count; i++) + __free_page(alloc->mapping->pages[i]); + vfree(alloc->mapping->pages); + kfree(alloc->mapping); + kfree(alloc); + return -ENOMEM; + } + alloc->mapping->iova = ret; + alloc->mapping->mapped = true; + + alloc->gpu_va = va; + alloc->mapped_va = va; + + spin_lock(&gsp_vram_lock); + list_add_tail(&alloc->list, &gsp_vram_allocs); + spin_unlock(&gsp_vram_lock); + + if (gpu_va) *gpu_va = va; + if (handle) *handle = alloc->handle; + if (actual_size) *actual_size = size; + + nv_vgpu_info(vgpu, "EMUL ALLOC: handle=0x%llx gpu_va=0x%llx size=%llu iova=0x%llx", + alloc->handle, va, size, alloc->mapping->iova); + + return 0; +} + +/* Memory Free - Emulation Implementation */ +int gsp_rpc_free_emul(struct gsp_client *client, u64 handle) +{ + struct nv_vgpu_device *vgpu = client->dev->driver_data; + struct gsp_vram_alloc *alloc; + + alloc = gsp_find_vram_alloc(handle); + if (!alloc) { + nv_vgpu_warn(vgpu, "EMUL FREE: handle 0x%llx not found", handle); + return -ENOENT; + } + + spin_lock(&gsp_vram_lock); + list_del(&alloc->list); + spin_unlock(&gsp_vram_lock); + + if (alloc->mapping) { + if (alloc->mapping->mapped) { + dma_unmap_page(&vgpu->pdev->dev, alloc->mapping->iova, alloc->size, DMA_BIDIRECTIONAL); + } + if (alloc->mapping->pinned) { + for (int i = 0; i < alloc->mapping->page_count; i++) { + if (alloc->mapping->pages[i]) + __free_page(alloc->mapping->pages[i]); + } + } + vfree(alloc->mapping->pages); + kfree(alloc->mapping); + } + + kfree(alloc); + + nv_vgpu_info(vgpu, "EMUL FREE: handle=0x%llx", handle); + return 0; +} + +/* Memory Map - Emulation Implementation */ +int gsp_rpc_map_emul(struct gsp_client *client, + u64 handle, u64 gpu_va, u64 size, + u32 prot, u32 flags, u64 offset, + u64 *mapped_va) +{ + struct nv_vgpu_device *vgpu = client->dev->driver_data; + struct gsp_vram_alloc *alloc = gsp_find_vram_alloc(handle); + + if (!alloc) { + nv_vgpu_warn(vgpu, "EMUL MAP: handle 0x%llx not found", handle); + return -ENOENT; + } + + if (gpu_va == 0) + gpu_va = alloc->gpu_va + offset; + + alloc->mapped_va = gpu_va; + alloc->mapped = true; + + if (mapped_va) + *mapped_va = gpu_va; + + nv_vgpu_info(vgpu, "EMUL MAP: handle=0x%llx gpu_va=0x%llx size=%llu offset=%llu", + handle, gpu_va, size, offset); + + return 0; +} + +/* Memory Unmap - Emulation Implementation */ +int gsp_rpc_unmap_emul(struct gsp_client *client, u64 handle, u64 gpu_va, u64 size) +{ + struct nv_vgpu_device *vgpu = client->dev->driver_data; + struct gsp_vram_alloc *alloc = gsp_find_vram_alloc(handle); + + if (!alloc) { + nv_vgpu_warn(vgpu, "EMUL UNMAP: handle 0x%llx not found", handle); + return -ENOENT; + } + + alloc->mapped = false; + + nv_vgpu_info(vgpu, "EMUL UNMAP: handle=0x%llx gpu_va=0x%llx size=%llu", + handle, gpu_va, size); + + return 0; +} + +/* Page Pin - Emulation Implementation */ +int gsp_rpc_pin_emul(struct gsp_client *client, + u64 handle, u64 offset, u64 size, + u32 flags, u64 *dma_addr, u32 *num_pages) +{ + struct nv_vgpu_device *vgpu = client->dev->driver_data; + struct gsp_vram_alloc *alloc = gsp_find_vram_alloc(handle); + + if (!alloc || !alloc->mapping) { + nv_vgpu_warn(vgpu, "EMUL PIN: handle 0x%llx not found or no mapping", handle); + return -ENOENT; + } + + if (dma_addr) + *dma_addr = alloc->mapping->iova + offset; + if (num_pages) + *num_pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; + + nv_vgpu_info(vgpu, "EMUL PIN: handle=0x%llx offset=%llu size=%llu dma_addr=0x%llx pages=%u", + handle, offset, size, alloc->mapping->iova + offset, *num_pages); + + return 0; +} + +/* Page Unpin - Emulation Implementation */ +int gsp_rpc_unpin_emul(struct gsp_client *client, u64 handle, u64 offset, u64 size) +{ + struct nv_vgpu_device *vgpu = client->dev->driver_data; + struct gsp_vram_alloc *alloc = gsp_find_vram_alloc(handle); + + if (!alloc) { + nv_vgpu_warn(vgpu, "EMUL UNPIN: handle 0x%llx not found", handle); + return -ENOENT; + } + + nv_vgpu_info(vgpu, "EMUL UNPIN: handle=0x%llx offset=%llu size=%llu", + handle, offset, size); + + return 0; +} + int gsp_rpc_schedule(struct gsp_client *client, u64 work_handle, u64 callback, u64 arg, u32 priority, u32 flags) diff --git a/kernel/gsp_rpc_client.h b/kernel/gsp_rpc_client.h index 64bfe5b..54c216e 100644 --- a/kernel/gsp_rpc_client.h +++ b/kernel/gsp_rpc_client.h @@ -314,4 +314,40 @@ int gsp_wpr_scratch_mutex_release(struct gsp_client *client, u32 wpr_id); void gsp_rpc_emulation_set(bool enable); bool gsp_rpc_emulation_is_enabled(void); +/* Emulation implementations */ +int gsp_rpc_alloc_emul(struct gsp_client *client, + u64 size, u64 alignment, u32 mem_type, + u32 flags, u64 addr_hint, u32 pid, + u64 *gpu_va, u64 *handle, u64 *actual_size); +int gsp_rpc_free_emul(struct gsp_client *client, u64 handle); +int gsp_rpc_map_emul(struct gsp_client *client, + u64 handle, u64 gpu_va, u64 size, + u32 prot, u32 flags, u64 offset, + u64 *mapped_va); +int gsp_rpc_unmap_emul(struct gsp_client *client, u64 handle, u64 gpu_va, u64 size); +int gsp_rpc_pin_emul(struct gsp_client *client, + u64 handle, u64 offset, u64 size, + u32 flags, u64 *dma_addr, u32 *num_pages); +int gsp_rpc_unpin_emul(struct gsp_client *client, u64 handle, u64 offset, u64 size); + +/* Notification */ +int gsp_rpc_notify_register(struct gsp_client *client, + u32 type, + void (*callback)(struct gsp_client *, + struct gsp_rpc_response *, + void *), + void *ctx); +void gsp_rpc_notify_unregister(struct gsp_client *client, u32 type); +void gsp_handle_notification(struct gsp_client *client, struct gsp_rpc_msg *msg); + +/* Client lifecycle */ +struct gsp_client *gsp_client_init(struct device *dev, phys_addr_t fw_base, phys_addr_t doorbell); +void gsp_client_fini(struct gsp_client *client); + +/* WPR Management */ +int gsp_wpr_write_mutex_acquire(struct gsp_client *client, u32 wpr_id); +int gsp_wpr_write_mutex_release(struct gsp_client *client, u32 wpr_id); +int gsp_wpr_scratch_mutex_acquire(struct gsp_client *client, u32 wpr_id); +int gsp_wpr_scratch_mutex_release(struct gsp_client *client, u32 wpr_id); + #endif /* _GSP_RPC_CLIENT_H_ */ diff --git a/kernel/include/memory.h b/kernel/include/memory.h index 14a35e9..07e57f2 100644 --- a/kernel/include/memory.h +++ b/kernel/include/memory.h @@ -16,6 +16,17 @@ struct nv_vgpu_mapping { struct list_head list; }; +struct nv_vgpu_simple_mapping { + u64 gpa; + u64 size; + u64 iova; + struct page **pages; + int page_count; + bool pinned; + bool mapped; + struct list_head list; +}; + struct nv_vgpu_mm_ctx { struct nv_vgpu_device *vgpu; struct mutex lock; diff --git a/kernel/memory.c b/kernel/memory.c index 710799d..cd81496 100644 --- a/kernel/memory.c +++ b/kernel/memory.c @@ -12,17 +12,6 @@ #include "nvidia-vgpu-vfio.h" #include "memory.h" -struct nv_vgpu_simple_mapping { - u64 gpa; - u64 size; - u64 iova; - struct page **pages; - int page_count; - bool pinned; - bool mapped; - struct list_head list; -}; - static LIST_HEAD(simple_mappings); static DEFINE_MUTEX(simple_lock); |
