diff options
| -rw-r--r-- | .gitignore | 17 | ||||
| -rw-r--r-- | STATE.md | 2 | ||||
| -rw-r--r-- | docs/ONBOARDING.md | 2 | ||||
| -rw-r--r-- | docs/VERSION_UPGRADE.md | 2 | ||||
| -rw-r--r-- | docs/old/ARCHITECTURE.md | 476 | ||||
| -rwxr-xr-x | install.sh | 2 | ||||
| -rw-r--r-- | legacy-driver-guest/Makefile | 44 | ||||
| -rw-r--r-- | legacy-driver-guest/README.md | 21 | ||||
| -rw-r--r-- | legacy-driver-guest/bar/gsp_bar.c | 242 | ||||
| -rw-r--r-- | legacy-driver-guest/core/gsp_core.c | 654 | ||||
| -rw-r--r-- | legacy-driver-guest/debugfs/gsp_debugfs.c | 273 | ||||
| -rw-r--r-- | legacy-driver-guest/include/gsp_core.h | 613 | ||||
| -rw-r--r-- | legacy-driver-guest/kernel-tests/gsp_vgpu_comprehensive_test.c | 432 | ||||
| -rw-r--r-- | legacy-driver-guest/kernel-tests/gsp_vgpu_kunit_test.c | 327 | ||||
| -rw-r--r-- | legacy-driver-guest/kernel-tests/gsp_vgpu_mock_test.c | 624 | ||||
| -rw-r--r-- | legacy-driver-guest/migration/gsp_migration.c | 339 | ||||
| -rw-r--r-- | legacy-driver-guest/rpc/gsp_rpc.c | 331 | ||||
| -rw-r--r-- | legacy-driver-guest/vf/gsp_vf.c | 312 | ||||
| -rw-r--r-- | legacy-driver-guest/wpr/gsp_wpr.c | 285 | ||||
| -rw-r--r-- | patches/nvidia/0001-Build-fixes-and-vGPU-VFIO-interface-integration.patch | 484 | ||||
| -rw-r--r-- | patches/nvidia/README.md | 45 |
21 files changed, 17 insertions, 5510 deletions
@@ -40,13 +40,22 @@ userspace/examples/example_vgpu userspace/tests/*_test # ---------------------------------------------------------------------------- -# NVIDIA open-gpu-kernel-modules (vendor tree) -# Cloned at a pinned tag and patched by install.sh - see patches/nvidia/ +# NVIDIA open-gpu-kernel-modules (public upstream) +# Cloned at a pinned tag and patched by install.sh - see legacy-patches/nvidia/ # ---------------------------------------------------------------------------- /nvidia-open-gpu-kernel-modules/ -# NVIDIA open-gpu-kernel-modules @ 570.144 (local checkout of the open kernel modules -# driver's exact wire protocol - used by kernel/gsp_rm_emulation.c) +# Legacy NVIDIA patches (kept locally, no longer tracked) +/legacy-patches/ + +# Legacy guest driver (gsp-vgpu.ko, superseded by stock guest driver; kept +# locally, no longer tracked) +/legacy-driver-guest/ + +# Purely legacy docs (describe the superseded guest-driver architecture) +/docs/old/ + +# Local checkout of the open kernel modules @ 570.144 (not tracked) /nvidia-570.144-reference/ # rmq build artifact (source stays) @@ -82,7 +82,7 @@ regression → unit test → CUDA validation (`docs/DEBUGGING.md` §5 checklist) ## Reproducibility notes - NVIDIA base: `open-gpu-kernel-modules` tag **610.57.04** + patch series - in `patches/nvidia/` (re-brands version string to 570.144 to match the + in `legacy-patches/nvidia/` (re-brands version string to 570.144 to match the GSP firmware ABI; adds the vGPU VFIO interface headers + symbol exports). - GSP firmware: `nvidia/tu102/gsp/gsp-570.144.bin` from [linux-firmware.git](https://github.com/NVIDIA/linux-firmware) diff --git a/docs/ONBOARDING.md b/docs/ONBOARDING.md index 1d0a4f7..bc61a03 100644 --- a/docs/ONBOARDING.md +++ b/docs/ONBOARDING.md @@ -53,7 +53,7 @@ open-iov/ ├── legacy-driver-guest/ # historical guest-side driver (reference only, NOT built) ├── firmware/57X-GSP/570.144/ # GSP blob + analysis scripts (per-version dirs) ├── nvidia-open-gpu-kernel-modules/ # NVIDIA OpenRM source (patched, builds nvidia.ko) -├── patches/nvidia/ # our delta vs upstream OpenRM tag +├── legacy-patches/nvidia/ # our delta vs upstream OpenRM tag ├── scripts/ # stack_manager.sh (THE tool), vgpu_vm.py (THE harness), helpers ├── tools/ # guest monitor, failure analyzer, benchmarks, ghidra ├── config/ # declarative YAML: hardware/, versions/ diff --git a/docs/VERSION_UPGRADE.md b/docs/VERSION_UPGRADE.md index 94c7d68..b9bd387 100644 --- a/docs/VERSION_UPGRADE.md +++ b/docs/VERSION_UPGRADE.md @@ -92,7 +92,7 @@ versions safely. ## 6. Rebuild host + guest against the new anchor -1. Point `patches/nvidia/` at the new OpenRM tag (rebase our delta; verify +1. Point `legacy-patches/nvidia/` at the new OpenRM tag (rebase our delta; verify `modinfo nvidia.ko | grep depends` still shows `open-iov-vfio`). 2. `./scripts/stack_manager.sh build-all` (kernel → nvidia → userspace). 3. Install the new host firmware to `/lib/firmware/` diff --git a/docs/old/ARCHITECTURE.md b/docs/old/ARCHITECTURE.md deleted file mode 100644 index f9b7ae4..0000000 --- a/docs/old/ARCHITECTURE.md +++ /dev/null @@ -1,476 +0,0 @@ -# Open-IOV vGPU-IO Architecture Document - -## Overview - -Open-IOV vGPU-IO is a complete open-source implementation of NVIDIA vGPU (virtual GPU) technology for Turing architecture GPUs (TU102/TU104), enabling GPU virtualization without proprietary GRID host drivers. The project provides: - -- **Host-side VFIO mdev driver** (`open-iov-vfio.ko`) - Creates mediated devices for QEMU/KVM -- **Guest-side vGPU driver** (`gsp-vgpu.ko`) - Communicates with GSP firmware via RPC -- **Userspace library** (`libiov.so`/`libvgpu.so`) - C API for VF management and GPU operations -- **Firmware decompilation** - Complete reverse engineering of GSP 570.144W firmware - -## System Architecture - -``` -╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ -║ HOST SYSTEM ║ -║ ╔════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ -║ ║ ║ ║ -║ ║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║ ║ -║ ║ │ USERSPACE (Host) │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌──────────────┐ ┌─────────────────────┐ ┌──────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ QEMU/KVM │ │ libvfio-user │ │ mdev management CLI / mdev management daemon │ │ ║ ║ -║ ║ │ │ │ │ │ │ (GPU Virtualization Management CLI/Manager) │ │ ║ ║ -║ ║ │ │ -device vfio-│ │ - VFIO userspace │ │ │ │ ║ ║ -║ ║ │ │ pci,sysfsdev│ │ library │ │ • mdev create/destroy │ │ ║ ║ -║ ║ │ │ │ │ - ioctl/eventfd │ │ • VF lifecycle management │ │ ║ ║ -║ ║ │ │ ┌──────────┐ │ │ - mmap support │ │ • Migration orchestration │ │ ║ ║ -║ ║ │ │ │ VFIO │ │ │ │ │ • Resource allocation │ │ ║ ║ -║ ║ │ │ │ Region │ │ └──────────┬──────────┘ └──────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ │ (mdev) │ │ │ │ ║ ║ -║ ║ │ │ └────┬─────┘ │ │ │ ║ ║ -║ ║ │ │ │ │ ▼ │ ║ ║ -║ ║ │ │ │ │ ┌──────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ │ │ │ libvgpu.so / libiov.so (Host-side) │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_open/close/get_info │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_vf_create/destroy/get_info │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_mem_alloc/free/map/unmap/pin/unpin │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_bar_config/force_access/save/restore │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_wpr_protect_write/read/unprotect/set_timeout/register_callback │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_schedule/yield │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_register/unregister_event_callback, vgpu_process_events │ │ ║ ║ -║ ║ │ │ │ │ │ • vgpu_migrate_start/status/cancel │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ ║ ║ -║ ║ │ │ │ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ ║ ║ -║ ║ │ │ │ │ │ │ rpc_emulator.c (Host-side Emulation) │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ • rpc_emu_bar_config/save/restore/get_state │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ • rpc_emu_wpr_protect/unprotect/set_timeout/check_access │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ • rpc_emu_schedule/yield │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ • rpc_emu_notify_register/unregister/send │ │ │ ║ ║ -║ ║ │ │ │ │ │ └──────────────────────────────────────────────────────────────────┘ │ │ ║ ║ -║ ║ │ │ │ │ └──────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ └──────┼────────┘ │ ║ ║ -║ ║ │ │ VFIO_DEVICE_GET_REGION_INFO / VFIO_DEVICE_GET_IRQ_INFO / VFIO_DEVICE_RESET │ ║ ║ -║ ║ │ │ mmap() / ioctl() / read() / write() / poll() │ ║ ║ -║ ║ │ ▼ │ ║ ║ -║ ║ └─────────┼──────────────────────────────────────────────────────────────────────────────────────────┘ ║ ║ -║ ║ │ ║ ║ -║ ║ ▼ ║ ║ -║ ║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║ ║ -║ ║ │ KERNEL SPACE (Host) │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ nvidia.ko (Host RM Kernel Module) │ │ ║ ║ -║ ║ │ │ (NVIDIA OpenRM 570.144 - Host Driver) │ │ ║ ║ -║ ║ │ │ │ │ ║ ║ -║ ║ │ │ • GSP Firmware Boot & Management │ │ ║ ║ -║ ║ │ │ • Physical GPU Resource Management (VRAM, engines, etc.) │ │ ║ ║ -║ ║ │ │ • vGPU VFIO Symbol Exports: │ │ ║ ║ -║ ║ │ │ - nvidia_vgpu_vfio_get_ops() │ │ ║ ║ -║ ║ │ │ - nvidia_vgpu_vfio_set_ops() │ │ ║ ║ -║ ║ │ │ - nv_vgpu_mdev_register_parent() │ │ ║ ║ -║ ║ │ │ - nv_vgpu_mdev_unregister_parent() │ │ ║ ║ -║ ║ │ │ • GPC Callbacks (from open-iov-vfio.ko): │ │ ║ ║ -║ ║ │ │ - vgpu_create / vgpu_delete / vgpu_bar_info / vgpu_start │ │ ║ ║ -║ ║ │ │ - get_name / get_description / get_instances / get_sparse_mmap │ │ ║ ║ -║ ║ │ │ - update_request │ │ ║ ║ -║ ║ │ │ • Host IRQ/MSI-X Handler (owns physical GPU interrupt) │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ open-iov-vfio.ko (Host VFIO mdev Driver) │ │ ║ ║ -║ ║ │ │ │ │ ║ ║ -║ ║ │ │ • mdev_parent registration with nvidia.ko │ │ ║ ║ -║ ║ │ │ • VFIO Device Ops: probe/remove/open/close/ioctl/mmap │ │ ║ ║ -║ ║ │ │ • PCI Config Space Emulation (256 bytes): │ │ ║ ║ -║ ║ │ │ - Vendor=0x10DE, Device=0x1ED3 (TU104 vGPU) │ │ ║ ║ -║ ║ │ │ - BAR0=16MB, BAR1=256MB, BAR2=32MB, BAR3=32MB (all 64-bit) │ │ ║ ║ -║ ║ │ │ - Capabilities: PM, MSI, MSI-X (Table@BAR0+0x2000), PCIe │ │ ║ ║ -║ ║ │ │ • BAR Trap Emulation (bar_emulation.c): │ │ ║ ║ -║ ║ │ │ - 64 trapped regions covering all BAR0 registers │ │ ║ ║ -║ ║ │ │ - Shadow memory for register state │ │ ║ ║ -║ ║ │ │ • GSP Communication (gsp_comm.c): │ │ ║ ║ -║ ║ │ │ - Polling-based doorbell (queue head @ 0x110c00) │ │ ║ ║ -║ ║ │ │ - Shared memory region for RPC messages │ │ ║ ║ -║ ║ │ │ • Firmware-Decompiled RPC Client (gsp_rpc_client.c + gsp_rpc_integration.c): │ │ ║ ║ -║ ║ │ │ - All 12 RPC types: ALLOC, FREE, MAP, UNMAP, PIN, UNPIN, │ │ ║ ║ -║ ║ │ │ SCHEDULE, YIELD, NOTIFY, BAR_TRAP, MIGRATE, DEBUG │ │ ║ ║ -║ ║ │ │ - Real firmware addresses from decompilation │ │ ║ ║ -║ ║ │ │ • Memory Management (memory.c): │ │ ║ ║ -║ ║ │ │ - DMA mapping, pin/unpin, map/unmap │ │ ║ ║ -║ ║ │ │ • IRQ Forwarding (irq.c): │ │ ║ ║ -║ ║ │ │ - MSI-X table/PBA emulation │ │ ║ ║ -║ ║ │ │ - eventfd trigger injection to guest │ │ ║ ║ -║ ║ │ │ • Live Migration (migration.c): │ │ ║ ║ -║ ║ │ │ - 4-phase: QUERY→PREPARE→TRANSFER→COMMIT→CLEANUP │ │ ║ ║ -║ ║ │ │ - Dual jump tables (0x04179ED8, 0x04179FBC) │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ vfio-mdev.ko / vfio-pci.ko (Kernel VFIO Core) │ │ ║ ║ -║ ║ │ │ • Mediated device framework │ │ ║ ║ -║ ║ │ │ • VFIO PCI device emulation │ │ ║ ║ -║ ║ │ │ • IOMMU DMA mapping (DMA remapping) │ │ ║ ║ -║ ║ │ │ • Region/IRQ index mapping: │ │ ║ ║ -║ ║ │ │ - VFIO_PCI_BAR0_REGION_INDEX → BAR0 (16MB) │ │ ║ ║ -║ ║ │ │ - VFIO_PCI_BAR1_REGION_INDEX → BAR1 (256MB) │ │ ║ ║ -║ ║ │ │ - VFIO_PCI_BAR2_REGION_INDEX → BAR2 (32MB) │ │ ║ ║ -║ ║ │ │ - VFIO_PCI_BAR3_REGION_INDEX → BAR3 (32MB) │ │ ║ ║ -║ ║ │ │ - VFIO_PCI_CONFIG_REGION_INDEX → PCI Config Space (256B) │ │ ║ ║ -║ ║ │ │ - VFIO_PCI_MSIX_REGION_INDEX → MSI-X Table/PBA │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ └──────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║ ║ -║ ║ ║ ║ -║ ║ ════════════════════════════════════════════════════════════════════════════════════════════════════════════ ║ ║ -║ ║ HARDWARE (Physical GPU) ║ ║ -║ ║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║ ║ -║ ║ │ NVIDIA TU102/TU104 GPU (RTX 2080 Ti / T4 / etc.) │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ ║ ║ -║ ║ │ │ BAR0 │ │ BAR1 │ │ BAR2 │ │ BAR3 │ │ GSP FALCON │ │ ║ ║ -║ ║ │ │ (16 MB) │ │ (256 MB) │ │ (32 MB) │ │ (32 MB) │ │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ ┌─────────────────┐ │ │ ║ ║ -║ ║ │ │ Config Regs │ │ Framebuffer │ │ Reserved │ │ Reserved │ │ │ REAL GSP │ │ │ ║ ║ -║ ║ │ │ Doorbell │ │ (VRAM) │ │ │ │ │ │ │ FIRMWARE │ │ │ ║ ║ -║ ║ │ │ Queue Heads │ │ │ │ │ │ │ │ │ (570.144W) │ │ │ ║ ║ -║ ║ │ │ Shared Mem │ │ │ │ │ │ │ │ │ │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ RPC Dispatchers │ │ │ ║ ║ -║ ║ │ │ 0x110c00 │ │ │ │ │ │ │ │ │ • Primary │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x057A1AC0 │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ • Secondary │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x04ED39DC │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ Specialized │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ Handlers: │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ • BAR_TRAP │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x04CB8188 │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ • WPR x2 │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x04F00B0C │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x04F00C78 │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ • ALLOC │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x057E94EC │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ • SCHEDULE │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x051EFBF4 │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ • Migration │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x04179ED8 │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 0x04179FBC │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ 12 RPC Types: │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ ALLOC, FREE, │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ MAP, UNMAP, │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ PIN, UNPIN, │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ SCHEDULE, │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ YIELD, NOTIFY, │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ BAR_TRAP, │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ │ MIGRATE, DEBUG │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ │ │ │ │ └─────────────────┘ │ │ ║ ║ -║ ║ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ Physical IRQ (MSI-X) ──────────────────────────────────────────────► nvidia.ko ISR │ ║ ║ -║ ║ └──────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║ ║ -║ ║ ║ ║ -║ ╚════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ ║ -║ ║ -╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ - - │ VFIO MEDIATED DEVICE (mdev) │ - │ sysfs: /sys/bus/mdev/devices/<UUID>/ │ - │ • PCI Config Space (256B) │ - │ • BAR0 Region (16MB) │ - │ • BAR1 Region (256MB) │ - │ • BAR2 Region (32MB) │ - │ • BAR3 Region (32MB) │ - │ • MSI-X Table/PBA Region │ - │ • IRQs (MSI-X vectors) │ - ▼ - -╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ -║ GUEST VM ║ -║ ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ -║ ║ ║ ║ -║ ║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║ ║ -║ ║ │ USERSPACE (Guest) │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ Guest Applications │ │ ║ ║ -║ ║ │ │ │ │ ║ ║ -║ ║ │ │ • CUDA Applications │ │ ║ ║ -║ ║ │ │ • OpenGL/Vulkan Applications │ │ ║ ║ -║ ║ │ │ • Video Encode/Decode (NVENC/NVDEC) │ │ ║ ║ -║ ║ │ │ • AI/ML Workloads (cuDNN, TensorRT) │ │ ║ ║ -║ ║ │ │ • Custom vGPU Management (via libvgpu.so) │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ libvgpu.so / libiov.so (Guest-side Userspace Library) │ │ ║ ║ -║ ║ │ │ │ │ ║ ║ -║ ║ │ │ • vgpu_open/close/get_info │ │ ║ ║ -║ ║ │ │ • vgpu_vf_create/destroy/get_info │ │ ║ ║ -║ ║ │ │ • vgpu_mem_alloc/free/map/unmap/pin/unpin │ │ ║ ║ -║ ║ │ │ • vgpu_bar_config/force_access/save/restore │ │ ║ ║ -║ ║ │ │ • vgpu_wpr_protect_write/read/unprotect/set_timeout/register_callback │ │ ║ ║ -║ ║ │ │ • vgpu_schedule/yield │ │ ║ ║ -║ ║ │ │ • vgpu_register/unregister_event_callback, vgpu_process_events │ │ ║ ║ -║ ║ │ │ • vgpu_migrate_start/status/cancel │ │ ║ ║ -║ ║ │ │ │ │ ║ ║ -║ ║ │ │ ┌────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ ║ ║ -║ ║ │ │ │ rpc_emulator.c (Guest-side Emulation Fallbacks) │ │ │ ║ ║ -║ ║ │ │ │ │ │ │ ║ ║ -║ ║ │ │ │ • rpc_emu_bar_config/save/restore/get_state │ │ │ ║ ║ -║ ║ │ │ │ • rpc_emu_wpr_protect/unprotect/set_timeout/check_access │ │ │ ║ ║ -║ ║ │ │ │ • rpc_emu_schedule/yield │ │ │ ║ ║ -║ ║ │ │ │ • rpc_emu_notify_register/unregister/send │ │ │ ║ ║ -║ ║ │ │ └────────────────────────────────────────────────────────────────────────────────────────────┘ │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ libnvidia-ml.so / libnvidia-opencl.so / libcuda.so (NVIDIA Userspace Drivers) │ │ ║ ║ -║ ║ │ │ • Standard NVIDIA userspace driver stack (unchanged) │ │ ║ ║ -║ ║ │ │ • Communicates with guest nvidia.ko via ioctl on /dev/nvidia* │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║ ║ -║ ║ ║ ║ -║ ║ ═════════════════════════════════════════════════════════════════════════════════════════════════════════════ ║ ║ -║ ║ KERNEL SPACE (Guest) ║ ║ -║ ║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ nvidia.ko (Guest RM Kernel Module) │ │ ║ ║ -║ ║ │ │ (NVIDIA OpenRM 570.144 - Guest Driver, UNMODIFIED) │ │ ║ ║ -║ ║ │ │ │ │ ║ ║ -║ ║ │ │ • Detects vGPU via PCI Config Space (Vendor=0x10DE, Device=0x1ED3) │ │ ║ ║ -║ ║ │ │ • Maps BAR0 (config), BAR1 (framebuffer), BAR2, BAR3 │ │ ║ ║ -║ ║ │ │ • Sets up MSI-X interrupts (table @ BAR0+0x2000, PBA @ BAR0+0x3000) │ │ ║ ║ -║ ║ │ │ • GSP Client: │ │ ║ ║ -║ ║ │ │ - Writes to BAR0 doorbell (queue head @ 0x110c00) │ │ ║ ║ -║ ║ │ │ - Reads/writes shared memory for RPC messages │ │ ║ ║ -║ ║ │ │ - Expects GSP firmware with vGPU RPC handlers │ │ ║ ║ -║ ║ │ │ • RM (Resource Manager) for GPU resources │ │ ║ ║ -║ ║ │ │ • nvidia-modeset.ko / nvidia-uvm.ko / nvidia-peermem.ko │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ gsp-vgpu.ko (Guest vGPU Driver - Open-IOV) │ │ ║ ║ -║ ║ │ │ │ │ ║ ║ -║ ║ │ │ • Char Device: /dev/gsp-vgpu (misc device) │ │ ║ ║ -║ ║ │ │ • IOCTL Interface (matches libvgpu.so API): │ │ ║ ║ -║ ║ │ │ - GSP_IOCTL_CREATE_VF / DESTROY_VF │ │ ║ ║ -║ ║ │ │ - GSP_IOCTL_ALLOC / FREE / MAP / UNMAP / PIN / UNPIN │ │ ║ ║ -║ ║ │ │ - GSP_IOCTL_BAR_CONFIG / FORCE / SAVE / RESTORE │ │ ║ ║ -║ ║ │ │ - GSP_IOCTL_WPR_PROTECT / UNPROTECT / TIMEOUT │ │ ║ ║ -║ ║ │ │ - GSP_IOCTL_SCHEDULE / YIELD │ │ ║ ║ -║ ║ │ │ - GSP_IOCTL_MIGRATE │ │ ║ ║ -║ ║ │ │ - GSP_IOCTL_GET_INFO │ │ ║ ║ -║ ║ │ │ • RPC Client (rpc/gsp_rpc.c): │ │ ║ ║ -║ ║ │ │ - Doorbell writes to queue head │ │ ║ ║ -║ ║ │ │ - Ring buffer management │ │ ║ ║ -║ ║ │ │ • Emulation Mode (AUTO-DETECTED): │ │ ║ ║ -║ ║ │ │ - Test BAR_TRAP RPC at load; if timeout → enable emulation │ │ ║ ║ -║ ║ │ │ - Module params: emulation_mode (ro), emulation_override (force) │ │ ║ ║ -║ ║ │ │ - In emulation: BAR_TRAP, WPR, ALLOC, PIN, MAP handled locally │ │ ║ ║ -║ ║ │ │ • Debugfs: /sys/kernel/debug/gsp-vgpu/ │ │ ║ ║ -║ ║ │ │ • VF Lifecycle (vf/gsp_vf.c) │ │ ║ ║ -║ ║ │ │ • BAR Emulation (bar/gsp_bar.c) │ │ ║ ║ -║ ║ │ │ • WPR Management (wpr/gsp_wpr.c) │ │ ║ ║ -║ ║ │ │ • Migration (migration/gsp_migration.c) │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ │ ┌────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ║ ║ -║ ║ │ │ VFIO-PCI Core (Guest Kernel) │ │ ║ ║ -║ ║ │ │ • vfio-pci.ko: PCI device emulation for VFIO │ │ ║ ║ -║ ║ │ │ • Handles mmap of BAR regions │ │ ║ ║ -║ ║ │ │ • MSI-X interrupt handling │ │ ║ ║ -║ ║ │ │ • Config space read/write │ │ ║ ║ -║ ║ │ └────────────────────────────────────────────────────────────────────────────────────────────────────┘ │ ║ ║ -║ ║ │ │ ║ ║ -║ ║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║ ║ -║ ║ ║ ║ -║ ║ ══════════════════════════════════════════════════════════════════════════════════════════════════════════════ ║ ║ -║ ║ VIRTUAL GPU (mdev Device as seen by Guest) ║ ║ -║ ║ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ║ ║ -║ ║ │ PCI Config Space (256B) │ BAR0 (16MB) │ BAR1 (256MB) │ BAR2 (32MB) │ BAR3 (32MB) │ MSI-X │ ║ ║ -║ ║ │ • Vendor=0x10DE │ Config Regs │ Framebuffer │ Reserved │ Reserved │ Table │ ║ ║ -║ ║ │ • Device=0x1ED3 │ Doorbell │ (VRAM) │ │ │ @0x2000│ ║ ║ -║ ║ │ • Class=0x030000 │ Queue Heads │ │ │ │ PBA │ ║ ║ -║ ║ │ • BARs: 64-bit, prefetch │ Shared Mem │ │ │ │ @0x3000│ ║ ║ -║ ║ │ • Caps: PM, MSI, MSI-X, │ @0x110c00 │ │ │ │ │ ║ ║ -║ ║ │ PCIe │ ║ ║ -║ ║ └──────────────────────────────────────────────────────────────────────────────────────────────────────────┘ ║ ║ -║ ║ ║ ║ -║ ╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ ║ -╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝ -``` - -## Communication Pathways (Host ↔ Guest) - -### 1. **VFIO Region Access (Memory-Mapped I/O)** -``` -Guest App → libvgpu.so → ioctl(/dev/gsp-vgpu) → gsp-vgpu.ko - → Guest vfio-pci.ko → mmap(BAR0/BAR1/BAR2/BAR3) - → Host vfio-pci.ko → open-iov-vfio.ko BAR emulation - → Host nvidia.ko → Physical GPU BARs -``` -**Path**: Guest userspace → Guest kernel → Host kernel → Physical GPU -**Mechanism**: VFIO mmap with IOMMU DMA remapping - -### 2. **PCI Config Space Access** -``` -Guest nvidia.ko → pci_read_config_* / pci_write_config_* - → Guest vfio-pci.ko → VFIO_DEVICE_GET_REGION_INFO (CONFIG_REGION) - → Host open-iov-vfio.ko → nv_vgpu_config_read/write() - → Returns emulated 256-byte config space -``` -**Path**: Guest kernel → Host kernel (via VFIO ioctl) -**Mechanism**: VFIO config space region emulation - -### 3. **GSP RPC Communication (Native Path)** -``` -Guest nvidia.ko → Write BAR0 doorbell (0x110c00) + shared memory - → Physical GPU GSP firmware receives RPC - → GSP processes RPC (ALLOC, MAP, PIN, SCHEDULE, BAR_TRAP, etc.) - → GSP writes response to shared memory - → Guest nvidia.ko reads response -``` -**Path**: Guest kernel → Physical GPU (direct, no host kernel involvement) -**Mechanism**: Doorbell register + shared memory in BAR0 - -### 4. **GSP RPC Communication (Emulation Path - Host Mediated)** -``` -Guest nvidia.ko → Write BAR0 doorbell (0x110c00) - → Host open-iov-vfio.ko (polling) detects doorbell - → gsp_comm.c → gsp_rpc_integration.c → gsp_rpc_client.c - → Firmware-decompiled RPC handlers (emulated in host kernel) - → Response written to shared memory - → Guest nvidia.ko reads response -``` -**Path**: Guest kernel → Host kernel (open-iov-vfio.ko) → Emulated RPC -**Mechanism**: Host polls GSP doorbell, processes RPC in software - -### 5. **BAR Trap Emulation** -``` -Guest nvidia.ko → Write to trapped BAR register (page fault) - → Guest vfio-pci.ko → VFIO page fault handler - → Host open-iov-vfio.ko → nv_vgpu_bar_trap() - → If native: gsp_rpc_bar_trap() → GSP firmware (0x04CB8188) - → If emulated: rpc_emu_bar_trap() in host userspace (libvgpu.so) - → Result written back to guest BAR mapping -``` -**Path**: Guest kernel page fault → Host kernel → Host userspace (emulation) or GSP firmware -**Mechanism**: VFIO page fault + BAR trap emulation - -### 6. **Interrupt Forwarding (Host → Guest)** -``` -Physical GPU → MSI-X IRQ → Host nvidia.ko ISR - → nvidia.ko calls nv_vgpu_vfio_inject_interrupt() (VFIO ops) - → open-iov-vfio.ko → eventfd_signal() - → QEMU/KVM → Guest MSI-X interrupt injected - → Guest nvidia.ko ISR handles interrupt -``` -**Path**: Physical GPU → Host kernel → Host userspace (QEMU) → Guest kernel -**Mechanism**: VFIO interrupt injection via eventfd - -### 7. **Userspace Management (mdev management CLI/mdev management daemon)** -``` -mdev management CLI → libvgpu.so (host) → ioctl(/dev/vfio/<mdev>) - → open-iov-vfio.ko → mdev VFIO ops - → VF creation, BAR config, memory ops, migration -``` -**Path**: Host userspace → Host kernel (VFIO mdev) -**Mechanism**: Standard VFIO ioctl on mdev device - -### 8. **Guest vGPU Driver Communication** -``` -Guest App → libvgpu.so (guest) → ioctl(/dev/gsp-vgpu) - → gsp-vgpu.ko → Internal RPC client - → If emulation: Local handling in gsp-vgpu.ko - → If native: GSP RPC via BAR0 doorbell -``` -**Path**: Guest userspace → Guest kernel (gsp-vgpu.ko) → GSP or emulation - -## Key Component Summary - -| Component | Location | Type | Purpose | -|-----------|----------|------|---------| -| **nvidia.ko (Host)** | Host Kernel | RM Driver | Boots GSP, manages physical GPU, exports vGPU VFIO symbols | -| **open-iov-vfio.ko** | Host Kernel | VFIO mdev Driver | Creates mdev, PCI config space, BAR emulation, RPC integration, IRQ forwarding | -| **gsp-vgpu.ko** | Guest Kernel | vGPU Driver | Char device `/dev/gsp-vgpu`, ioctl API, emulation mode, RPC client | -| **nvidia.ko (Guest)** | Guest Kernel | RM Driver | Standard NVIDIA driver, detects vGPU, communicates with GSP | -| **libvgpu.so / libiov.so (Host)** | Host Userspace | Library | Management API (mdev management CLI/mdev management daemon), emulation fallbacks | -| **libvgpu.so / libiov.so (Guest)** | Guest Userspace | Library | Application API, emulation fallbacks | -| **libnvidia-*.so** | Guest Userspace | NVIDIA Drivers | Standard CUDA/OpenGL/OpenCL userspace stack | -| **mdev management CLI / mdev management daemon** | Host Userspace | Tools | mdev lifecycle, VF management, migration orchestration | -| **REAL GSP Firmware** | Physical GPU | Firmware | 570.144W, 12 RPC types, BAR_TRAP/WPR/SCHEDULE/MIGRATE handlers | -| **EMULATED GSP** | Host Kernel + Userspace | Software | rpc_emulator.c, gsp_rpc_client.c (when GSP lacks vGPU handlers) | - -## Emulation Mode Details - -### When Enabled -- **Auto-detect**: At gsp-vgpu.ko load, sends test BAR_TRAP RPC -- **Timeout/Error** → `emulation_mode = true` -- **Module params**: `emulation_override=1` (force on), `emulation_override=0` (force off) - -### What Gets Emulated -| Operation | Host Kernel (open-iov-vfio.ko) | Host Userspace (libvgpu.so) | Guest Kernel (gsp-vgpu.ko) | -|-----------|-------------------------------|----------------------------|---------------------------| -| BAR_TRAP | nv_vgpu_bar_trap() → rpc_emu_bar_trap() | rpc_emu_bar_config/save/restore | gsp_bar_force_access() | -| WPR | nv_vgpu_wpr_*() | rpc_emu_wpr_protect/unprotect | gsp_vf_wpr_protect/unprotect | -| ALLOC/MAP/PIN | gsp_rpc_client.c (local) | rpc_emu_* fallbacks | gsp_vf_mem_alloc/map/pin | -| SCHEDULE/YIELD | gsp_rpc_schedule/yield (workqueue) | rpc_emu_schedule/yield | gsp_vf_schedule/yield | -| NOTIFY | gsp_rpc_notify_register/unregister | rpc_emu_notify_register/unregister/send | gsp_vf_notify_* | -| MIGRATION | migration.c (4-phase) | rpc_emu_migrate_* | gsp_migration_start | - -## Build Artifacts - -``` -$OPEN_IOV_ROOT/ -├── nvidia-open-gpu-kernel-modules/kernel-open/nvidia.ko (34MB) Host RM Driver -├── kernel/open-iov-vfio.ko (2.8MB) Host VFIO mdev Driver -├── driver/gsp-vgpu.ko (1.8MB) Guest vGPU Driver -├── userspace/lib/libiov.so (76KB) Userspace Library (libvgpu.so symlink) -├── userspace/examples/example_vgpu (28KB) Test Application -├── firmware/570-GSP/gsp-570.144.fwimage.bin (28MB) GSP Firmware -├── scripts/load_vgpu_stack.sh Host module loader -├── scripts/create_mdev.sh mdev creation -├── scripts/launch_qemu_vgpu.sh QEMU launcher -├── scripts/test_vgpu_stack.sh Test suite -├── scripts/setup_guest_driver.sh Guest driver setup -├── scripts/unload_vgpu_stack.sh Cleanup -├── docs/ARCHITECTURE.md This document -└── wiki/ 10 technical docs -``` - -## Deployment Sequence - -```bash -# HOST (after reboot to clear module_blacklist) -# 1. Load NVIDIA OpenRM host driver (exports vGPU VFIO symbols) -sudo insmod nvidia-open-gpu-kernel-modules/kernel-open/nvidia.ko - -# 2. Load Open-IOV VFIO mdev driver (registers mdev parent with nvidia.ko) -sudo insmod kernel/open-iov-vfio.ko - -# 3. Create mediated device for QEMU -./scripts/create_mdev.sh # Creates /sys/bus/mdev/devices/<UUID>/ - -# 4. Launch QEMU with vGPU -./scripts/launch_qemu_vgpu.sh # -device vfio-pci,sysfsdev=/sys/bus/mdev/devices/<UUID> - -# GUEST (inside VM) -# 5. Install NVIDIA driver (unmodified OpenRM) -./scripts/setup_guest_driver.sh # Installs nvidia.ko, firmware, loads driver - -# 6. Verify -nvidia-smi # Should show vGPU (T4 / A100 / etc.) -lspci -d 10de: # Should show 10de:1ed3 (TU104 vGPU) -``` - ---- - -*Architecture Version: 2.0 (with detailed host/guest communication pathways)* -*Last Updated: $(date)* -*Project: $OPEN_IOV_ROOT*
\ No newline at end of file @@ -56,7 +56,7 @@ set -euo pipefail OPEN_IOV_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PATCH_DIR="$OPEN_IOV_ROOT/patches/nvidia" +PATCH_DIR="$OPEN_IOV_ROOT/legacy-patches/nvidia" NVIDIA_DIR="$OPEN_IOV_ROOT/nvidia-open-gpu-kernel-modules" NVIDIA_REPO="https://github.com/NVIDIA/open-gpu-kernel-modules.git" NVIDIA_TAG="${NVIDIA_TAG:-610.57.04}" diff --git a/legacy-driver-guest/Makefile b/legacy-driver-guest/Makefile deleted file mode 100644 index 4675cbf..0000000 --- a/legacy-driver-guest/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# GSP vGPU-IO Driver Makefile - -obj-m += gsp-vgpu.o - -gsp-vgpu-y := \ - core/gsp_core.o \ - rpc/gsp_rpc.o \ - vf/gsp_vf.o \ - bar/gsp_bar.o \ - wpr/gsp_wpr.o \ - migration/gsp_migration.o \ - debugfs/gsp_debugfs.o - -ccflags-y += -I$(src)/include -ccflags-y += -I$(src)/../kernel/include - -# Build against the kernel source -KDIR ?= /lib/modules/$(shell uname -r)/build - -all: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean - -install: - $(MAKE) -C $(KDIR) M=$(PWD) modules_install - -load: all - sudo insmod gsp-vgpu.ko firmware_name=gsp-570.144.fwimage.bin - -unload: - sudo rmmod gsp-vgpu - -test: all load - @echo "Driver loaded, checking status..." - sleep 2 - dmesg -T | tail -20 - @echo "Checking debugfs..." - ls -la /sys/kernel/debug/gsp-vgpu/ 2>/dev/null || echo "Debugfs not available" - @echo "Checking device nodes..." - ls -la /dev/gsp-vgpu* 2>/dev/null || echo "No device nodes" - -.PHONY: all clean install load unload test
\ No newline at end of file diff --git a/legacy-driver-guest/README.md b/legacy-driver-guest/README.md deleted file mode 100644 index 309613a..0000000 --- a/legacy-driver-guest/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# legacy-driver-guest — historical guest-side driver (NOT BUILT) - -This directory preserves the **old guest-side vGPU driver** (`gsp-vgpu.ko`) -from the pre-refactor architecture, where GSP RPC handling lived in a kernel -module *inside the guest*. - -It is kept for reference only: - -- The current architecture is **host-only GSP emulation** — the guest runs - the stock, unmodified `nvidia.ko`, and there is no Open-IOV code in the - guest. See `docs/GSP_EMULATION_ARCHITECTURE.md`. -- Nothing here is part of any build target (the top-level Makefile no longer - references it). -- `kernel-tests/` holds the old test modules written against this driver's - internal API (`gsp_core.h`); they are superseded by - `kernel/tests/gsp_emulation_test.c`, which tests the host-side emulation - engine through `gsp_emu_process_rpc()`. - -Do not add new code here. If you need behavior that only exists in this tree -(e.g. WPR eventfd work, migration WPR state), port it into the host-side -`kernel/` modules rather than reviving the guest driver. diff --git a/legacy-driver-guest/bar/gsp_bar.c b/legacy-driver-guest/bar/gsp_bar.c deleted file mode 100644 index aa3ed62..0000000 --- a/legacy-driver-guest/bar/gsp_bar.c +++ /dev/null @@ -1,242 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - BAR Emulation - */ - -#include "gsp_core.h" -#include <linux/slab.h> -#include <linux/vmalloc.h> - -/* BAR Emulation Ops */ -static int gsp_bar_trap_handler(struct gsp_vf *vf, struct gsp_bar_trap_payload *trap) -{ - struct gsp_bar_state *bar = &vf->bar_state; - struct gsp_bar_trap_response resp = {0}; - size_t resp_size = sizeof(resp); - int ret; - - /* Validate BAR index (we only support BAR1) */ - if (trap->bar_index != 1) - return -EINVAL; - - /* Validate offset */ - if (trap->offset >= bar->aperture_size) - return -ERANGE; - - /* Check ForceBarAccess */ - if (bar->force_access && vf->id != bar->force_vf) - return -EPERM; - - /* In emulation mode, handle locally */ - if (emulation_mode) { - /* Simulate BAR trap handling */ - if (trap->trap_type == GSP_BAR_WRITE) { - /* Config write - update aperture */ - bar->aperture_offset = trap->offset; - bar->aperture_size = trap->value; - } else if (trap->trap_type == GSP_BAR_ATOMIC) { - /* Force access control */ - bar->force_access = trap->offset ? true : false; - bar->force_vf = trap->offset ? vf->id : 0; - } - resp.value = 0; - return 0; - } - - /* Forward to GSP BAR trap handler (0x04CB8188) */ - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, - trap, sizeof(*trap), &resp, &resp_size); - - return ret; -} - -/* Aperture Configuration */ -static int gsp_bar_config_aperture(struct gsp_vf *vf, uint64_t offset, uint64_t size) -{ - struct gsp_bar_state *bar = &vf->bar_state; - struct gsp_bar_trap_payload payload = {0}; - struct gsp_bar_trap_response resp = {0}; - size_t resp_size = sizeof(resp); - int ret; - - /* Validate alignment (4KB) */ - if (offset & 0xFFF || size & 0xFFF) - return -EINVAL; - - /* Validate max size (256KB per firmware) */ - if (size > 0x40000) - return -EINVAL; - - /* In emulation mode, handle locally */ - if (emulation_mode) { - bar->aperture_offset = offset; - bar->aperture_size = size; - return 0; - } - - payload.bar_index = 1; - payload.trap_type = GSP_BAR_WRITE; /* Config write */ - payload.offset = offset; - payload.value = size; - payload.size = 8; - payload.vf_id = vf->id; - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, - &payload, sizeof(payload), &resp, &resp_size); - if (!ret) { - bar->aperture_offset = offset; - bar->aperture_size = size; - } - - return ret; -} - -/* ForceBarAccess Control */ -int gsp_bar_force_access(struct gsp_vf *vf, bool enable) -{ - struct gsp_bar_state *bar = &vf->bar_state; - struct gsp_bar_trap_payload payload = {0}; - struct gsp_bar_trap_response resp = {0}; - size_t resp_size = sizeof(resp); - int ret; - - /* In emulation mode, handle locally */ - if (emulation_mode) { - bar->force_access = enable; - bar->force_vf = enable ? vf->id : 0; - return 0; - } - - payload.bar_index = 1; - payload.trap_type = GSP_BAR_ATOMIC; /* Force access control */ - payload.offset = enable ? 1 : 0; - payload.value = enable ? vf->id : 0; - payload.size = 8; - payload.vf_id = vf->id; - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_BAR_TRAP, - &payload, sizeof(payload), &resp, &resp_size); - if (!ret) { - bar->force_access = enable; - bar->force_vf = enable ? vf->id : 0; - } - - return ret; -} - -/* State Save for Migration */ -static int gsp_bar_save_state(struct gsp_vf *vf, void *buf, size_t *size) -{ - struct gsp_bar_state *bar = &vf->bar_state; - size_t needed = sizeof(*bar) + bar->backing_size; - - if (!buf || *size < needed) - return -ENOSPC; - - memcpy(buf, bar, sizeof(*bar)); - if (bar->backing_store && bar->backing_size > 0) - memcpy(buf + sizeof(*bar), bar->backing_store, bar->backing_size); - - *size = needed; - return 0; -} - -/* State Restore for Migration */ -static int gsp_bar_restore_state(struct gsp_vf *vf, void *buf, size_t size) -{ - struct gsp_bar_state *bar = &vf->bar_state; - size_t min_size = sizeof(*bar); - - if (!buf || size < min_size) - return -EINVAL; - - memcpy(bar, buf, sizeof(*bar)); - - if (size > min_size && bar->backing_size > 0) { - if (!bar->backing_store) { - bar->backing_store = vzalloc(bar->backing_size); - if (!bar->backing_store) - return -ENOMEM; - } - memcpy(bar->backing_store, buf + min_size, - min(size - min_size, bar->backing_size)); - } - - /* Reconfigure BAR in GSP */ - return gsp_bar_config_aperture(vf, bar->aperture_offset, bar->aperture_size); -} - -/* VF BAR Initialization */ -int gsp_vf_bar_init(struct gsp_vf *vf) -{ - struct gsp_bar_state *bar = &vf->bar_state; - int ret; - - /* Initialize with config values */ - bar->aperture_offset = vf->bar1_offset; - bar->aperture_size = vf->bar1_size; - bar->force_access = false; - bar->force_vf = 0; - bar->backing_store = NULL; - bar->backing_size = 0; - - /* Allocate backing store (max 256KB) */ - if (bar->aperture_size > 0) { - bar->backing_size = min(bar->aperture_size, (uint64_t)0x40000); - bar->backing_store = vzalloc(bar->backing_size); - if (!bar->backing_store) - return -ENOMEM; - } - - /* Configure aperture in GSP (skip in emulation mode) */ - if (!emulation_mode) { - ret = gsp_bar_config_aperture(vf, bar->aperture_offset, bar->aperture_size); - if (ret) { - dev_err(vf->gsp->dev, "VF %u: BAR aperture config failed: %d\n", vf->id, ret); - goto err_backing; - } - } else { - dev_info(vf->gsp->dev, "VF %u: BAR1 initialized in emulation mode [0x%llx, 0x%llx)\n", - vf->id, bar->aperture_offset, bar->aperture_offset + bar->aperture_size); - } - - dev_info(vf->gsp->dev, "VF %u: BAR1 initialized [0x%llx, 0x%llx)\n", - vf->id, bar->aperture_offset, bar->aperture_offset + bar->aperture_size); - - return 0; - -err_backing: - vfree(bar->backing_store); - bar->backing_store = NULL; - bar->backing_size = 0; - return ret; -} - -/* VF BAR Cleanup */ -void gsp_vf_bar_fini(struct gsp_vf *vf) -{ - struct gsp_bar_state *bar = &vf->bar_state; - - vfree(bar->backing_store); - bar->backing_store = NULL; - bar->backing_size = 0; - - dev_info(vf->gsp->dev, "VF %u: BAR1 cleaned up\n", vf->id); -} - -/* BAR Trap Entry Point (called from ISR/notification) */ -int gsp_vf_bar_trap(struct gsp_vf *vf, struct gsp_bar_trap_payload *trap) -{ - return gsp_bar_trap_handler(vf, trap); -} - -/* Migration Interface */ -int gsp_migration_bar_save(struct gsp_vf *vf, void *buf, size_t *size) -{ - return gsp_bar_save_state(vf, buf, size); -} - -int gsp_migration_bar_restore(struct gsp_vf *vf, void *buf, size_t size) -{ - return gsp_bar_restore_state(vf, buf, size); -}
\ No newline at end of file diff --git a/legacy-driver-guest/core/gsp_core.c b/legacy-driver-guest/core/gsp_core.c deleted file mode 100644 index cd41bd2..0000000 --- a/legacy-driver-guest/core/gsp_core.c +++ /dev/null @@ -1,654 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - Core Implementation - * Guest vGPU driver - communicates with GSP already booted by host GRID driver - */ - -#include "gsp_core.h" -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/firmware.h> -#include <linux/interrupt.h> -#include <linux/dma-mapping.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/delay.h> -#include <linux/msi.h> -#include <linux/miscdevice.h> -#include <linux/uaccess.h> - -#define DRIVER_NAME "gsp-vgpu" -#define DRIVER_VERSION "0.1.0" - -/* Emulation mode: skip GSP RPC for BAR/WPR when GSP lacks vGPU handlers */ -bool emulation_mode = true; /* ON by default */ -static bool emulation_override = false; /* true = force emulation, false = force native */ -module_param(emulation_mode, bool, 0444); -MODULE_PARM_DESC(emulation_mode, "Enable emulation mode for BAR/WPR (skip GSP RPC) - default ON, auto-detects if GSP has vGPU handlers"); -module_param(emulation_override, bool, 0444); -MODULE_PARM_DESC(emulation_override, "Override auto-detection: 1=force emulation, 0=force native (default: auto-detect)"); - -/* Forward declarations */ -int gsp_firmware_load(struct gsp_device *gsp); -int gsp_setup_irq(struct gsp_device *gsp); -int gsp_rpc_init(struct gsp_device *gsp); -void gsp_shutdown(struct gsp_device *gsp); -static void gsp_detect_emulation_mode(struct gsp_device *gsp); -static long gsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static int gsp_open(struct inode *inode, struct file *file); -static int gsp_release(struct inode *inode, struct file *file); - -/* Char device file operations */ -static const struct file_operations gsp_fops = { - .owner = THIS_MODULE, - .open = gsp_open, - .release = gsp_release, - .unlocked_ioctl = gsp_ioctl, - .compat_ioctl = gsp_ioctl, -}; - -/* Char device open */ -static int gsp_open(struct inode *inode, struct file *file) -{ - struct gsp_device *gsp = container_of(file->private_data, struct gsp_device, miscdev); - file->private_data = gsp; - return 0; -} - -/* Char device release */ -static int gsp_release(struct inode *inode, struct file *file) -{ - return 0; -} - -/* Char device ioctl */ -static long gsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct gsp_device *gsp = file->private_data; - void __user *argp = (void __user *)arg; - int ret = 0; - - mutex_lock(&gsp->chardev_lock); - - switch (cmd) { - case GSP_IOCTL_CREATE_VF: { - struct gsp_vf_config config; - if (copy_from_user(&config, argp, sizeof(config))) { - ret = -EFAULT; - break; - } - ret = gsp_vf_create(gsp, &config); - break; - } - case GSP_IOCTL_DESTROY_VF: { - uint32_t vf_id; - if (copy_from_user(&vf_id, argp, sizeof(vf_id))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - gsp_vf_destroy(vf); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_ALLOC: { - struct gsp_alloc_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_mem_alloc(vf, args.size, args.flags, &args.handle, &args.va); - if (!ret) - ret = copy_to_user(argp, &args, sizeof(args)) ? -EFAULT : 0; - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_FREE: { - struct gsp_free_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_mem_free(vf, args.handle); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_PIN: { - struct gsp_pin_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_mem_pin(vf, args.handle, args.offset, args.size, &args.dma_addr); - if (!ret) - ret = copy_to_user(argp, &args, sizeof(args)) ? -EFAULT : 0; - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_UNPIN: { - struct gsp_unpin_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_mem_unpin(vf, args.handle); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_MAP: { - struct gsp_map_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_mem_map(vf, args.handle, args.gpu_va, args.size, - args.prot, args.flags, args.offset, &args.mapped_va); - if (!ret) - ret = copy_to_user(argp, &args, sizeof(args)) ? -EFAULT : 0; - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_UNMAP: { - struct gsp_unmap_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_mem_unmap(vf, args.handle, args.gpu_va, args.size); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_BAR_CONFIG: { - struct gsp_bar_config_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_bar_init(vf); /* Re-init with new aperture */ - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_BAR_FORCE: { - struct gsp_bar_force_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_bar_force_access(vf, args.enable); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_BAR_SAVE: { - struct gsp_bar_save_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_migration_bar_save(vf, args.buf, args.size); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_BAR_RESTORE: { - struct gsp_bar_restore_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_migration_bar_restore(vf, args.buf, args.size); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_WPR_PROTECT: { - struct gsp_wpr_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_wpr_protect(vf, args.base, args.size, args.flags); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_WPR_UNPROTECT: { - struct gsp_wpr_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_wpr_unprotect(vf, args.base); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_WPR_TIMEOUT: { - struct gsp_wpr_timeout_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_wpr_set_timeout(vf, args.timeout_ns); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_SCHEDULE: { - struct gsp_schedule_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_schedule(vf, args.priority, args.time_slice_ns); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_YIELD: { - uint32_t vf_id; - if (copy_from_user(&vf_id, argp, sizeof(vf_id))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_vf_yield(vf); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_MIGRATE: { - struct gsp_migrate_args args; - if (copy_from_user(&args, argp, sizeof(args))) { - ret = -EFAULT; - break; - } - struct gsp_vf *vf = gsp_vf_get(gsp, args.vf_id); - if (!vf) { - ret = -ENOENT; - break; - } - ret = gsp_migration_start(vf, args.dst_vf); - gsp_vf_put(vf); - break; - } - case GSP_IOCTL_GET_INFO: { - char info[256]; - snprintf(info, sizeof(info), "GSP vGPU-IO Driver v%s (FW: 570.144W)", DRIVER_VERSION); - ret = copy_to_user(argp, info, sizeof(info)) ? -EFAULT : 0; - break; - } - default: - ret = -ENOTTY; - } - - mutex_unlock(&gsp->chardev_lock); - return ret; -} - -/* PCI Device IDs */ -static const struct pci_device_id gsp_pci_ids[] = { - { PCI_DEVICE(0x10DE, 0x1E07), .driver_data = 0 }, /* TU102 */ - { PCI_DEVICE(0x10DE, 0x1E08), .driver_data = 0 }, /* TU104 */ - { PCI_DEVICE(0x10DE, 0x1ED3), .driver_data = 0 }, /* TU104 RTX 2080 Super Mobile */ - { 0 } -}; -MODULE_DEVICE_TABLE(pci, gsp_pci_ids); - -/* Module Parameters */ -static int max_vfs = 7; -module_param(max_vfs, int, 0444); -MODULE_PARM_DESC(max_vfs, "Maximum number of VFs (default: 7)"); - -static char *firmware_name = "gsp-570.144.fwimage.bin"; -module_param(firmware_name, charp, 0444); -MODULE_PARM_DESC(firmware_name, "GSP firmware filename (for version verification only)"); - -/* PCI Probe */ -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); - if (!gsp) - return -ENOMEM; - - gsp->pdev = pdev; - gsp->dev = &pdev->dev; - gsp->max_vfs = max_vfs; - pci_set_drvdata(pdev, gsp); - - mutex_init(&gsp->vf_lock); - idr_init(&gsp->vf_idr); - INIT_LIST_HEAD(&gsp->vf_list); - - /* Enable PCI device */ - ret = pcim_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "Failed to enable PCI device: %d\n", ret); - return ret; - } - - pci_set_master(pdev); - - /* Map BARs */ - gsp->bar0 = pcim_iomap(pdev, 0, 0); - gsp->bar1 = pcim_iomap(pdev, 1, 0); - if (!gsp->bar0 || !gsp->bar1) { - dev_err(&pdev->dev, "Failed to map BARs\n"); - return -ENOMEM; - } - - dev_info(&pdev->dev, "BAR0: %p, BAR1: %p\n", gsp->bar0, gsp->bar1); - - /* Load Firmware (for version verification only - GSP already booted by host) */ - ret = gsp_firmware_load(gsp); - if (ret) { - dev_err(&pdev->dev, "Firmware load failed: %d\n", ret); - return ret; - } - - /* Initialize RPC client (sets up rings, doorbells) */ - gsp->rpc = gsp_rpc_client_init(gsp); - if (IS_ERR(gsp->rpc)) { - ret = PTR_ERR(gsp->rpc); - dev_err(&pdev->dev, "RPC client init failed: %d\n", ret); - return ret; - } - - /* Initialize RPC communication with GSP */ - ret = gsp_rpc_init(gsp); - if (ret) { - dev_err(&pdev->dev, "RPC init failed: %d\n", ret); - return ret; - } - - /* Setup IRQ */ - ret = gsp_setup_irq(gsp); - if (ret) { - dev_err(&pdev->dev, "IRQ setup failed: %d\n", ret); - return ret; - } - - /* Initialize char device */ - mutex_init(&gsp->chardev_lock); - gsp->miscdev.minor = MISC_DYNAMIC_MINOR; - gsp->miscdev.name = "gsp-vgpu"; - gsp->miscdev.fops = &gsp_fops; - gsp->miscdev.parent = &pdev->dev; - gsp->miscdev.mode = 0660; - - ret = misc_register(&gsp->miscdev); - if (ret) { - dev_err(&pdev->dev, "Failed to register misc device: %d\n", ret); - return ret; - } - - /* Debugfs */ - gsp_debugfs_init(gsp); - - dev_info(&pdev->dev, "GSP vGPU-IO driver loaded (FW: 570.144W)\n"); - return 0; -} - -/* PCI Remove */ -void gsp_remove(struct pci_dev *pdev) -{ - struct gsp_device *gsp = pci_get_drvdata(pdev); - struct gsp_vf *vf, *tmp; - - if (!gsp) - return; - - /* Destroy all VFs */ - list_for_each_entry_safe(vf, tmp, &gsp->vf_list, list) - gsp_vf_destroy(vf); - - /* Unregister char device */ - misc_deregister(&gsp->miscdev); - - gsp_debugfs_fini(gsp); - gsp_shutdown(gsp); - gsp_rpc_client_fini(gsp->rpc); - - if (gsp->fw) - release_firmware(gsp->fw); - - idr_destroy(&gsp->vf_idr); - - dev_info(&pdev->dev, "GSP vGPU-IO driver unloaded\n"); -} - -/* Firmware Load - only for version verification */ -int gsp_firmware_load(struct gsp_device *gsp) -{ - const struct firmware *fw; - int ret; - - ret = request_firmware(&fw, firmware_name, gsp->dev); - if (ret) { - dev_err(gsp->dev, "Failed to load firmware '%s': %d\n", firmware_name, ret); - return ret; - } - - /* Verify MD5: 13ce12a392a31eeb79a2e6ebd3a4a93a */ - if (fw->size != 0x1C50000) { /* ~28.5 MB */ - dev_warn(gsp->dev, "Firmware size unexpected: %zu (expected ~28.5MB)\n", fw->size); - } - - dev_info(gsp->dev, "Firmware verified: %zu bytes\n", fw->size); - gsp->fw = fw; - return 0; -} - -/* Initialize RPC communication with already-running GSP */ -int gsp_rpc_init(struct gsp_device *gsp) -{ - /* - * The GSP is already running (booted by host GRID driver). - * We just need to verify communication works by reading mailbox registers - * and optionally sending a test RPC. - */ - - /* Read mailbox registers to verify GSP is responsive */ - uint32_t mbox0 = readl(gsp->bar0 + GSP_BAR0_FALCON_MAILBOX0); - uint32_t mbox1 = readl(gsp->bar0 + GSP_BAR0_FALCON_MAILBOX1); - - dev_info(gsp->dev, "GSP mailbox0: 0x%08x, mailbox1: 0x%08x\n", mbox0, mbox1); - - /* Check if GSP appears to be running (non-zero mailbox or queue heads) */ - uint32_t qhead0 = readl(gsp->bar0 + GSP_BAR0_QUEUE_HEAD(0)); - dev_info(gsp->dev, "GSP queue head 0: 0x%08x\n", qhead0); - - /* Ring doorbell to signal we're ready - write to queue head */ - writel(1, gsp->bar0 + GSP_BAR0_QUEUE_HEAD(0)); - - gsp->fw_loaded = true; /* Indicates GSP communication established */ - dev_info(gsp->dev, "GSP RPC communication initialized\n"); - - /* Auto-detect emulation mode if not overridden */ - if (!emulation_override) { - gsp_detect_emulation_mode(gsp); - } else if (emulation_mode) { - dev_info(gsp->dev, "Emulation mode FORCED ON by module parameter\n"); - } else { - dev_info(gsp->dev, "Emulation mode FORCED OFF by module parameter\n"); - } - - return 0; -} - -/* Auto-detect if GSP has vGPU RPC handlers */ -static void gsp_detect_emulation_mode(struct gsp_device *gsp) -{ - struct gsp_bar_trap_payload test_payload = {0}; - struct gsp_bar_trap_response test_resp = {0}; - size_t resp_size = sizeof(test_resp); - int ret; - - dev_info(gsp->dev, "Auto-detecting GSP vGPU RPC handler support...\n"); - - /* Send a test BAR_TRAP RPC to check if GSP has vGPU handlers */ - test_payload.bar_index = 1; - test_payload.trap_type = GSP_BAR_READ; /* Non-destructive read */ - test_payload.offset = 0; - test_payload.value = 0; - test_payload.size = 8; - test_payload.vf_id = 0; - - /* Try synchronous RPC with short timeout (1 second) */ - ret = gsp_rpc_send_sync(gsp->rpc, GSP_RPC_BAR_TRAP, - &test_payload, sizeof(test_payload), - &test_resp, &resp_size); - - if (ret == -ETIMEDOUT || ret == -ENOTTY || ret == -EIO || ret == -ENODEV) { - /* GSP doesn't have vGPU handlers - enable emulation */ - emulation_mode = true; - dev_info(gsp->dev, "GSP lacks vGPU RPC handlers (ret=%d) - ENABLING emulation mode\n", ret); - } else if (ret == 0) { - /* GSP responded - has vGPU handlers */ - emulation_mode = false; - dev_info(gsp->dev, "GSP has vGPU RPC handlers - DISABLING emulation mode\n"); - } else { - /* Other error - default to emulation for safety */ - emulation_mode = true; - dev_info(gsp->dev, "GSP RPC test returned %d - ENABLING emulation mode (safe default)\n", ret); - } -} - -/* GSP Shutdown - just clean up our side */ -void gsp_shutdown(struct gsp_device *gsp) -{ - if (gsp->fw_loaded) { - /* Don't reset GSP - host driver owns it */ - gsp->fw_loaded = false; - } -} - -/* IRQ Setup */ -int gsp_setup_irq(struct gsp_device *gsp) -{ - int ret; - struct msix_entry entries[1]; - - /* Try MSI-X first */ - ret = pci_enable_msix_range(gsp->pdev, entries, 1, 1); - if (ret > 0) { - gsp->msix_enabled = true; - gsp->irq = entries[0].vector; - gsp->msix_entries[0] = entries[0]; - } else { - gsp->irq = gsp->pdev->irq; - } - - ret = devm_request_irq(gsp->dev, gsp->irq, gsp_isr, - gsp->msix_enabled ? 0 : IRQF_SHARED, - DRIVER_NAME, gsp); - if (ret) { - dev_err(gsp->dev, "Failed to request IRQ %d: %d\n", gsp->irq, ret); - return ret; - } - - dev_info(gsp->dev, "IRQ %d registered (MSI-X: %s)\n", - gsp->irq, gsp->msix_enabled ? "yes" : "no"); - return 0; -} - -/* PCI Driver Structure */ -static struct pci_driver gsp_pci_driver = { - .name = DRIVER_NAME, - .id_table = gsp_pci_ids, - .probe = gsp_probe, - .remove = gsp_remove, -}; - -/* Module Init/Exit */ -static int __init gsp_module_init(void) -{ - return pci_register_driver(&gsp_pci_driver); -} - -static void __exit gsp_module_exit(void) -{ - pci_unregister_driver(&gsp_pci_driver); -} - -module_init(gsp_module_init); -module_exit(gsp_module_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("NVIDIA vGPU-IO Team"); -MODULE_DESCRIPTION("NVIDIA GSP 570.144W vGPU-IO Driver"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_FIRMWARE("gsp-570.144.fwimage.bin"); diff --git a/legacy-driver-guest/debugfs/gsp_debugfs.c b/legacy-driver-guest/debugfs/gsp_debugfs.c deleted file mode 100644 index f3df124..0000000 --- a/legacy-driver-guest/debugfs/gsp_debugfs.c +++ /dev/null @@ -1,273 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - Debugfs Interface - */ - -#include "gsp_core.h" -#include <linux/debugfs.h> -#include <linux/seq_file.h> - -static int gsp_debugfs_vfs_show(struct seq_file *s, void *unused) -{ - struct gsp_device *gsp = s->private; - struct gsp_vf *vf; - - seq_printf(s, "%-4s %-12s %-10s %-18s %-18s\n", - "ID", "STATE", "REFCNT", "BAR1", "PAGE_TABLE"); - - mutex_lock(&gsp->vf_lock); - list_for_each_entry(vf, &gsp->vf_list, list) { - seq_printf(s, "%-4u %-12d %-10d 0x%016llx-0x%016llx 0x%016llx-0x%016llx\n", - vf->id, vf->state, atomic_read(&vf->refcount), - vf->bar1_offset, vf->bar1_offset + vf->bar1_size, - vf->pt_base, vf->pt_base + vf->pt_size); - } - mutex_unlock(&gsp->vf_lock); - - return 0; -} - -static int gsp_debugfs_vfs_open(struct inode *inode, struct file *file) -{ - return single_open(file, gsp_debugfs_vfs_show, inode->i_private); -} - -static const struct file_operations gsp_debugfs_vfs_fops = { - .open = gsp_debugfs_vfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int gsp_debugfs_vf_show(struct seq_file *s, void *unused) -{ - struct gsp_vf *vf = s->private; - struct gsp_wpr_region *rgn; - - seq_printf(s, "VF %u\n", vf->id); - seq_printf(s, " State: %d\n", vf->state); - seq_printf(s, " Refcount: %d\n", atomic_read(&vf->refcount)); - seq_printf(s, " BAR1: 0x%llx - 0x%llx (size: 0x%llx)\n", - vf->bar1_offset, vf->bar1_offset + vf->bar1_size, vf->bar1_size); - seq_printf(s, " Page Table: 0x%llx - 0x%llx (size: 0x%llx)\n", - vf->pt_base, vf->pt_base + vf->pt_size, vf->pt_size); - seq_printf(s, " Cmd Buffer: 0x%llx - 0x%llx (size: 0x%llx)\n", - vf->cmd_base, vf->cmd_base + vf->cmd_size, vf->cmd_size); - seq_printf(s, " BAR State:\n"); - seq_printf(s, " Aperture: 0x%llx - 0x%llx\n", - vf->bar_state.aperture_offset, - vf->bar_state.aperture_offset + vf->bar_state.aperture_size); - seq_printf(s, " ForceAcc: %s (VF: %u)\n", - vf->bar_state.force_access ? "enabled" : "disabled", - vf->bar_state.force_vf); - seq_printf(s, " WPR Regions:\n"); - - mutex_lock(&vf->wpr_lock); - list_for_each_entry(rgn, &vf->wpr_list, list) { - seq_printf(s, " [0x%llx, 0x%llx) flags=0x%x\n", - rgn->base, rgn->base + rgn->size, rgn->flags); - } - mutex_unlock(&vf->wpr_lock); - - if (vf->migration) { - seq_printf(s, " Migration:\n"); - seq_printf(s, " State: %d\n", vf->migration->state); - seq_printf(s, " Dst VF: %llu\n", vf->migration->dst_vf); - seq_printf(s, " Token: 0x%llx\n", vf->migration->token); - seq_printf(s, " Progress: %llu pages, %llu bytes\n", - vf->migration->progress.pages_transferred, - vf->migration->progress.bytes_transferred); - } - - return 0; -} - -static int gsp_debugfs_vf_open(struct inode *inode, struct file *file) -{ - return single_open(file, gsp_debugfs_vf_show, inode->i_private); -} - -static const struct file_operations gsp_debugfs_vf_fops = { - .open = gsp_debugfs_vf_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int gsp_debugfs_rpc_show(struct seq_file *s, void *unused) -{ - struct gsp_device *gsp = s->private; - - seq_printf(s, "RPC Statistics:\n"); - seq_printf(s, " Total: %lld\n", atomic64_read(&gsp->rpc_total)); - seq_printf(s, " Errors: %lld\n", atomic64_read(&gsp->rpc_errors)); - seq_printf(s, " BAR Traps: %lld\n", atomic64_read(&gsp->bar_traps)); - seq_printf(s, " WPR Events: %lld\n", atomic64_read(&gsp->wpr_events)); - seq_printf(s, " Migrations: %lld\n", atomic64_read(&gsp->migrations)); - - return 0; -} - -static int gsp_debugfs_rpc_open(struct inode *inode, struct file *file) -{ - return single_open(file, gsp_debugfs_rpc_show, inode->i_private); -} - -static const struct file_operations gsp_debugfs_rpc_fops = { - .open = gsp_debugfs_rpc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int gsp_debugfs_bar_show(struct seq_file *s, void *unused) -{ - struct gsp_vf *vf = s->private; - - seq_printf(s, "VF %u BAR State:\n", vf->id); - seq_printf(s, " Aperture Offset: 0x%llx\n", vf->bar_state.aperture_offset); - seq_printf(s, " Aperture Size: 0x%llx\n", vf->bar_state.aperture_size); - seq_printf(s, " Force Access: %s\n", vf->bar_state.force_access ? "enabled" : "disabled"); - seq_printf(s, " Force VF: %u\n", vf->bar_state.force_vf); - seq_printf(s, " Backing Store: %p\n", vf->bar_state.backing_store); - seq_printf(s, " Backing Size: 0x%zx\n", vf->bar_state.backing_size); - - return 0; -} - -static int gsp_debugfs_bar_open(struct inode *inode, struct file *file) -{ - return single_open(file, gsp_debugfs_bar_show, inode->i_private); -} - -static const struct file_operations gsp_debugfs_bar_fops = { - .open = gsp_debugfs_bar_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int gsp_debugfs_wpr_show(struct seq_file *s, void *unused) -{ - struct gsp_vf *vf = s->private; - struct gsp_wpr_region *rgn; - - seq_printf(s, "VF %u WPR Regions:\n", vf->id); - - mutex_lock(&vf->wpr_lock); - list_for_each_entry(rgn, &vf->wpr_list, list) { - seq_printf(s, " [0x%llx, 0x%llx) size=0x%llx flags=0x%x\n", - rgn->base, rgn->base + rgn->size, rgn->size, rgn->flags); - } - mutex_unlock(&vf->wpr_lock); - - return 0; -} - -static int gsp_debugfs_wpr_open(struct inode *inode, struct file *file) -{ - return single_open(file, gsp_debugfs_wpr_show, inode->i_private); -} - -static const struct file_operations gsp_debugfs_wpr_fops = { - .open = gsp_debugfs_wpr_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int gsp_debugfs_migration_show(struct seq_file *s, void *unused) -{ - struct gsp_vf *vf = s->private; - - if (!vf->migration) { - seq_printf(s, "No active migration\n"); - return 0; - } - - seq_printf(s, "VF %u Migration:\n", vf->id); - seq_printf(s, " State: %d\n", vf->migration->state); - seq_printf(s, " Destination VF: %llu\n", vf->migration->dst_vf); - seq_printf(s, " Token: 0x%llx\n", vf->migration->token); - seq_printf(s, " Flags: 0x%x\n", vf->migration->flags); - seq_printf(s, " Pages Xfer: %llu\n", vf->migration->progress.pages_transferred); - seq_printf(s, " Bytes Xfer: %llu\n", vf->migration->progress.bytes_transferred); - seq_printf(s, " Dirty Pages: %llu\n", vf->migration->progress.dirty_pages); - seq_printf(s, " Cancelled: %s\n", vf->migration->cancelled ? "yes" : "no"); - - return 0; -} - -static int gsp_debugfs_migration_open(struct inode *inode, struct file *file) -{ - return single_open(file, gsp_debugfs_migration_show, inode->i_private); -} - -static const struct file_operations gsp_debugfs_migration_fops = { - .open = gsp_debugfs_migration_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* VF Debugfs Directory Creation */ -static void gsp_debugfs_vf_create(struct gsp_vf *vf) -{ - char name[16]; - struct dentry *vf_dir; - - snprintf(name, sizeof(name), "vf%u", vf->id); - vf_dir = debugfs_create_dir(name, vf->gsp->debugfs_vfs_dir); - if (!vf_dir) - return; - - debugfs_create_file("status", 0444, vf_dir, vf, &gsp_debugfs_vf_fops); - debugfs_create_file("bar", 0444, vf_dir, vf, &gsp_debugfs_bar_fops); - debugfs_create_file("wpr", 0444, vf_dir, vf, &gsp_debugfs_wpr_fops); - debugfs_create_file("migration", 0444, vf_dir, vf, &gsp_debugfs_migration_fops); -} - -/* Main Debugfs Init */ -int gsp_debugfs_init(struct gsp_device *gsp) -{ - gsp->debugfs_root = debugfs_create_dir("gsp-vgpu", NULL); - if (!gsp->debugfs_root) - return -ENOMEM; - - debugfs_create_file("vfs", 0444, gsp->debugfs_root, gsp, &gsp_debugfs_vfs_fops); - debugfs_create_file("rpc", 0444, gsp->debugfs_root, gsp, &gsp_debugfs_rpc_fops); - - gsp->debugfs_vfs_dir = debugfs_create_dir("vfs", gsp->debugfs_root); - if (!gsp->debugfs_vfs_dir) { - debugfs_remove_recursive(gsp->debugfs_root); - return -ENOMEM; - } - - /* Create entries for existing VFs */ - mutex_lock(&gsp->vf_lock); - struct gsp_vf *vf; - list_for_each_entry(vf, &gsp->vf_list, list) - gsp_debugfs_vf_create(vf); - mutex_unlock(&gsp->vf_lock); - - return 0; -} - -void gsp_debugfs_fini(struct gsp_device *gsp) -{ - if (gsp->debugfs_root) - debugfs_remove_recursive(gsp->debugfs_root); -} - -/* Export for VF creation/destruction */ -void gsp_debugfs_vf_add(struct gsp_vf *vf) -{ - gsp_debugfs_vf_create(vf); -} - -void gsp_debugfs_vf_remove(struct gsp_vf *vf) -{ - char name[16]; - snprintf(name, sizeof(name), "vf%u", vf->id); - debugfs_remove_recursive(debugfs_lookup(name, vf->gsp->debugfs_vfs_dir)); -}
\ No newline at end of file diff --git a/legacy-driver-guest/include/gsp_core.h b/legacy-driver-guest/include/gsp_core.h deleted file mode 100644 index 569d6f8..0000000 --- a/legacy-driver-guest/include/gsp_core.h +++ /dev/null @@ -1,613 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - Core Definitions - * NVIDIA GSP 570.144W (TU102/TU104) Firmware Interface - */ - -#ifndef _GSP_CORE_H_ -#define _GSP_CORE_H_ - -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/mutex.h> -#include <linux/idr.h> -#include <linux/list.h> -#include <linux/kref.h> -#include <linux/completion.h> -#include <linux/wait.h> -#include <linux/spinlock.h> -#include <linux/miscdevice.h> - -/* Firmware Constants */ -#define GSP_FW_BASE_ADDR 0x04000000ULL -#define GSP_FW_SIZE 0x02000000ULL -#define GSP_ENTRY_POINT 0x04009000ULL -#define GSP_PRIMARY_DISPATCHER 0x057A1AC0ULL -#define GSP_SECONDARY_DISPATCHER 0x04ED39DCULL -#define GSP_RPC_JUMP_TABLE 0x059BFEB0ULL - -/* PCIe BAR Offsets */ -#define GSP_BAR0_FALCON_ENGINE 0x1103c0 -#define GSP_BAR0_FALCON_MAILBOX0 0x110040 -#define GSP_BAR0_FALCON_MAILBOX1 0x110044 -#define GSP_BAR0_MAILBOX(i) (0x110804 + (i) * 4) -#define GSP_BAR0_QUEUE_HEAD(i) (0x110c00 + (i) * 8) - -/* IOCTL definitions (must match userspace libvgpu.h) */ -#define GSP_IOCTL_MAGIC 'G' -#define GSP_IOCTL_CREATE_VF _IOW(GSP_IOCTL_MAGIC, 0x01, struct gsp_vf_config) -#define GSP_IOCTL_DESTROY_VF _IOW(GSP_IOCTL_MAGIC, 0x02, uint32_t) -#define GSP_IOCTL_ALLOC _IOWR(GSP_IOCTL_MAGIC, 0x10, struct gsp_alloc_args) -#define GSP_IOCTL_FREE _IOW(GSP_IOCTL_MAGIC, 0x11, struct gsp_free_args) -#define GSP_IOCTL_MAP _IOWR(GSP_IOCTL_MAGIC, 0x12, struct gsp_map_args) -#define GSP_IOCTL_UNMAP _IOW(GSP_IOCTL_MAGIC, 0x13, struct gsp_unmap_args) -#define GSP_IOCTL_PIN _IOWR(GSP_IOCTL_MAGIC, 0x14, struct gsp_pin_args) -#define GSP_IOCTL_UNPIN _IOW(GSP_IOCTL_MAGIC, 0x15, struct gsp_unpin_args) -#define GSP_IOCTL_BAR_CONFIG _IOWR(GSP_IOCTL_MAGIC, 0x16, struct gsp_bar_config_args) -#define GSP_IOCTL_BAR_FORCE _IOW(GSP_IOCTL_MAGIC, 0x17, struct gsp_bar_force_args) -#define GSP_IOCTL_BAR_SAVE _IOWR(GSP_IOCTL_MAGIC, 0x18, struct gsp_bar_save_args) -#define GSP_IOCTL_BAR_RESTORE _IOWR(GSP_IOCTL_MAGIC, 0x19, struct gsp_bar_restore_args) -#define GSP_IOCTL_WPR_PROTECT _IOWR(GSP_IOCTL_MAGIC, 0x1A, struct gsp_wpr_args) -#define GSP_IOCTL_WPR_UNPROTECT _IOW(GSP_IOCTL_MAGIC, 0x1B, struct gsp_wpr_args) -#define GSP_IOCTL_WPR_TIMEOUT _IOW(GSP_IOCTL_MAGIC, 0x1C, struct gsp_wpr_timeout_args) -#define GSP_IOCTL_SCHEDULE _IOW(GSP_IOCTL_MAGIC, 0x1D, struct gsp_schedule_args) -#define GSP_IOCTL_YIELD _IOW(GSP_IOCTL_MAGIC, 0x1E, uint32_t) -#define GSP_IOCTL_MIGRATE _IOWR(GSP_IOCTL_MAGIC, 0x1F, struct gsp_migrate_args) -#define GSP_IOCTL_GET_INFO _IOR(GSP_IOCTL_MAGIC, 0x20, char[256]) - -/* Kernel argument structures (matching userspace) */ -struct gsp_vf_config { - uint32_t id; - uint64_t bar1_offset; - uint64_t bar1_size; - uint64_t pt_base; - uint64_t pt_size; - uint64_t cmd_base; - uint64_t cmd_size; - uint32_t max_memory_mb; - uint32_t num_engines; -}; - -struct gsp_alloc_args { - uint32_t vf_id; - uint64_t size; - uint32_t type; - uint64_t alignment; - uint64_t va_hint; - uint32_t flags; - uint32_t pid; - uint64_t handle; - uint64_t va; - uint64_t actual_size; -}; - -struct gsp_free_args { - uint32_t vf_id; - uint64_t handle; -}; - -struct gsp_map_args { - uint32_t vf_id; - uint64_t handle; - uint64_t gpu_va; - uint64_t size; - uint32_t prot; - uint32_t flags; - uint64_t offset; - uint64_t mapped_va; -}; - -struct gsp_unmap_args { - uint32_t vf_id; - uint64_t handle; - uint64_t gpu_va; - uint64_t size; -}; - -struct gsp_pin_args { - uint32_t vf_id; - uint64_t handle; - uint64_t offset; - uint64_t size; - uint32_t flags; - uint64_t dma_addr; - uint32_t num_pages; -}; - -struct gsp_unpin_args { - uint32_t vf_id; - uint64_t handle; - uint64_t offset; - uint64_t size; -}; - -struct gsp_bar_config_args { - uint32_t vf_id; - uint64_t aperture_offset; - uint64_t aperture_size; -}; - -struct gsp_bar_force_args { - uint32_t vf_id; - uint32_t enable; -}; - -struct gsp_bar_save_args { - uint32_t vf_id; - void *buf; - size_t *size; -}; - -struct gsp_bar_restore_args { - uint32_t vf_id; - void *buf; - size_t size; -}; - -struct gsp_wpr_args { - uint32_t vf_id; - uint64_t base; - uint64_t size; - uint32_t flags; -}; - -struct gsp_wpr_timeout_args { - uint32_t vf_id; - uint64_t timeout_ns; -}; - -struct gsp_schedule_args { - uint32_t vf_id; - uint32_t priority; - uint64_t time_slice_ns; -}; - -struct gsp_migrate_args { - uint32_t vf_id; - uint64_t dst_vf; - uint32_t phase; - uint32_t flags; - uint64_t token; -}; - -/* Message Ring */ -#define GSP_MSG_RING_SIZE 256 -#define GSP_MSG_MAX_SIZE 256 -#define GSP_MAX_PENDING 64 - -/* RPC Types */ -enum gsp_rpc_type { - GSP_RPC_ALLOC = 0x01, - GSP_RPC_FREE = 0x02, - GSP_RPC_MAP = 0x03, - GSP_RPC_UNMAP = 0x04, - GSP_RPC_PIN = 0x05, - GSP_RPC_UNPIN = 0x06, - GSP_RPC_SCHEDULE = 0x07, - GSP_RPC_YIELD = 0x08, - GSP_RPC_NOTIFY = 0x09, - GSP_RPC_BAR_TRAP = 0x0A, - GSP_RPC_MIGRATE = 0x0B, - GSP_RPC_DEBUG = 0x0C, -}; - -/* RPC Message Flags */ -#define GSP_MSG_SYNC (1 << 0) -#define GSP_MSG_ASYNC (1 << 1) -#define GSP_MSG_NOREPLY (1 << 2) - -/* Memory Types */ -enum gsp_mem_type { - GSP_MEM_VRAM = 0, - GSP_MEM_SYSMEM = 1, - GSP_MEM_UNCACHED = 2, -}; - -/* Pin Flags */ -#define GSP_PIN_READ (1 << 0) -#define GSP_PIN_WRITE (1 << 1) -#define GSP_PIN_LONGTERM (1 << 2) - -/* BAR Trap Types */ -#define GSP_BAR_READ 0 -#define GSP_BAR_WRITE 1 -#define GSP_BAR_ATOMIC 2 - -/* Migration Phases */ -enum gsp_migrate_phase { - GSP_MIG_QUERY = 0, - GSP_MIG_PREPARE = 1, - GSP_MIG_TRANSFER = 2, - GSP_MIG_COMMIT = 3, - GSP_MIG_CLEANUP = 4, -}; - -/* Migration Flags */ -#define GSP_MIG_LIVE (1 << 0) -#define GSP_MIG_POSTCOPY (1 << 1) -#define GSP_MIG_AUTO_COMMIT (1 << 2) -#define GSP_MIG_VERIFY (1 << 3) - -/* Error Codes (from firmware) */ -#define GSP_OK 0 -#define GSP_EPERM 0xFFFFFFFF -#define GSP_ENOENT 0xFFFFFFFE -#define GSP_EINVAL 0xFFFFFFFD -#define GSP_ENODEV 0xFFFFFFFA -#define GSP_ENOMEM 0xFFFFFFF4 -#define GSP_EBUSY 0xFFFFFFEE -#define GSP_ENOSPC 0xFFFFFFE4 -#define GSP_ETIMEDOUT 0x0000001E -#define GSP_EOVERFLOW 0x00000025 -#define GSP_EDEV 0x0000001F - -/* Forward Declarations */ -struct gsp_device; -struct gsp_vf; -struct gsp_rpc_client; -struct gsp_migration; -struct gsp_wpr_region; - -/* WPR Region */ -struct gsp_wpr_region { - struct list_head list; - uint64_t base; - uint64_t size; - uint32_t flags; - uint32_t vf_id; - void (*completion_cb)(struct gsp_vf *, uint64_t, uint32_t); - void (*timeout_cb)(struct gsp_vf *, uint64_t, uint32_t); - uint64_t timeout_ns; -}; - -/* WPR Flags */ -#define GSP_WPR_WRITE (1 << 0) -#define GSP_WPR_READ (1 << 1) -#define GSP_WPR_EXECUTE (1 << 2) - -/* WPR Event Types */ -enum gsp_wpr_event { - GSP_WPR_WRITE_COMPLETE = 0, - GSP_WPR_READ_COMPLETE = 1, - GSP_WPR_WRITE_TIMEOUT = 2, - GSP_WPR_READ_TIMEOUT = 3, -}; - -/* Migration State */ -enum gsp_mig_state { - GSP_MIG_S_IDLE = 0, - GSP_MIG_S_QUERY = 1, - GSP_MIG_S_PREPARE = 2, - GSP_MIG_S_TRANSFER = 3, - GSP_MIG_S_COMMIT = 4, - GSP_MIG_S_CLEANUP = 5, - GSP_MIG_S_FAILED = 6, - GSP_MIG_S_COMPLETED = 7, -}; - -/* Migration Context */ -struct gsp_migration { - struct gsp_vf *vf; - struct mutex lock; - enum gsp_mig_state state; - uint64_t token; - uint64_t dst_vf; - uint32_t flags; - - struct { - uint64_t pages_transferred; - uint64_t bytes_transferred; - uint64_t dirty_pages; - uint64_t *page_list; - uint32_t page_count; - } progress; - - struct { - void *buf; - size_t size; - } bar_state; - - struct task_struct *thread; - struct completion comp; - bool cancelled; - int error; -}; - -/* Emulation mode: skip GSP RPC for BAR/WPR when GSP lacks vGPU handlers */ -extern bool emulation_mode; - -/* RPC Message Header (64 bytes) */ -struct gsp_rpc_header { - uint32_t magic; /* 0x47535052 "GSPR" */ - uint32_t version; /* Protocol version */ - uint32_t rpc_type; /* enum gsp_rpc_type */ - uint32_t sequence; /* Monotonic sequence */ - uint64_t timestamp_ns; /* Submission timestamp */ - uint32_t payload_size; /* Payload size in bytes */ - uint32_t flags; /* GSP_MSG_* */ - uint64_t correlation_id; /* Async matching */ - uint64_t reserved[3]; /* Padding to 64 bytes */ -} __attribute__((packed)); - -/* Complete RPC Message */ -struct gsp_rpc_message { - struct gsp_rpc_header hdr; - uint8_t payload[GSP_MSG_MAX_SIZE - sizeof(struct gsp_rpc_header)]; -} __attribute__((packed)); - -/* RPC Response Header */ -struct gsp_rpc_response { - int64_t status; /* 0 = success, negative = error */ - uint32_t rpc_type; /* Echo of request */ - uint32_t sequence; /* Echo of request */ - uint64_t timestamp_ns; /* Completion timestamp */ - uint32_t payload_size; /* Response payload size */ - uint32_t reserved; - uint8_t payload[]; -} __attribute__((packed)); - -/* Primary Dispatcher Sub-Command Descriptor */ -struct gsp_subcmd_desc { - uint32_t subcmd_id; /* Constant ID (e.g., 0x10, 0x14, 0x40) */ - uint8_t echo_flags_b; /* Copy of input flags_b */ - uint8_t echo_flags_a; /* Copy of input flags_a */ - uint8_t echo_flags_c; /* Copy of input flags_c */ - uint8_t reserved; -} __attribute__((packed)); - -/* ALLOC Payload */ -struct gsp_alloc_payload { - uint64_t size; - uint32_t type; /* enum gsp_mem_type */ - uint32_t alignment; - uint64_t va_hint; - uint32_t flags; - uint32_t pid; - uint32_t vf_id; - uint32_t reserved; -} __attribute__((packed)); - -struct gsp_alloc_response { - uint64_t handle; - uint64_t va; - uint64_t pa; -} __attribute__((packed)); - -/* PIN Payload */ -struct gsp_pin_payload { - uint64_t handle; - uint64_t offset; - uint64_t size; - uint32_t vf_id; - uint32_t flags; /* GSP_PIN_* */ - uint32_t reserved[2]; -} __attribute__((packed)); - -struct gsp_pin_response { - uint64_t dma_addr; -} __attribute__((packed)); - -/* BAR Trap Payload */ -struct gsp_bar_trap_payload { - uint32_t bar_index; - uint32_t trap_type; /* GSP_BAR_* */ - uint64_t offset; - uint64_t value; - uint32_t size; - uint32_t vf_id; - uint32_t reserved; -} __attribute__((packed)); - -struct gsp_bar_trap_response { - uint64_t value; -} __attribute__((packed)); - -/* Migration Payload */ -struct gsp_migrate_payload { - uint32_t phase; /* enum gsp_migrate_phase */ - uint32_t subcmd; /* Sub-command index */ - uint64_t src_vf; - uint64_t dst_vf; - uint64_t data_ptr; - uint64_t data_size; - uint32_t flags; /* GSP_MIG_* */ - uint32_t reserved; - uint64_t token; -} __attribute__((packed)); - -/* Message Ring Buffer */ -struct gsp_msg_ring { - void *base; - size_t size; - uint32_t head; - uint32_t tail; - spinlock_t lock; -}; - -/* RPC Client */ -struct gsp_rpc_client { - struct gsp_device *gsp; - struct mutex lock; - atomic_t seq; - wait_queue_head_t wq; - struct gsp_msg_ring *tx_ring; - struct gsp_msg_ring *rx_ring; - dma_addr_t tx_ring_dma; - dma_addr_t rx_ring_dma; - struct completion *pending[GSP_MAX_PENDING]; - struct gsp_rpc_response *resp_buf[GSP_MAX_PENDING]; -}; - -/* BAR State per VF */ -struct gsp_bar_state { - uint64_t aperture_offset; - uint64_t aperture_size; - bool force_access; - uint32_t force_vf; - void *backing_store; - size_t backing_size; -}; - -/* VF State */ -enum gsp_vf_state { - GSP_VF_CREATING = 0, - GSP_VF_ACTIVE, - GSP_VF_MIGRATING, - GSP_VF_SUSPENDED, - GSP_VF_DESTROYING, -}; - -/* GSP Virtual Function */ -struct gsp_vf { - struct gsp_device *gsp; - uint32_t id; - struct kref ref; - struct mutex lock; - enum gsp_vf_state state; - struct gsp_migration *migration; - - /* Resource configuration */ - uint64_t bar1_offset; - uint64_t bar1_size; - uint64_t pt_base; - uint64_t pt_size; - uint64_t cmd_base; - uint64_t cmd_size; - - /* WPR regions */ - struct list_head wpr_list; - struct mutex wpr_lock; - - /* BAR state */ - struct gsp_bar_state bar_state; - - atomic_t refcount; - bool active; - struct list_head list; -}; - -/* GSP Device */ -struct gsp_device { - struct pci_dev *pdev; - struct device *dev; - void __iomem *bar0; - void __iomem *bar1; - - /* Firmware */ - const struct firmware *fw; - bool fw_loaded; - - /* RPC */ - struct gsp_rpc_client *rpc; - - /* VF Management */ - struct mutex vf_lock; - struct idr vf_idr; - struct list_head vf_list; - uint32_t max_vfs; - - /* IRQ */ - int irq; - bool msix_enabled; - struct msix_entry msix_entries[1]; - - /* Debug */ - struct dentry *debugfs_root; - struct dentry *debugfs_vfs_dir; - - /* Char device */ - struct miscdevice miscdev; - struct mutex chardev_lock; - - /* Statistics */ - atomic64_t rpc_total; - atomic64_t rpc_errors; - atomic64_t bar_traps; - atomic64_t wpr_events; - atomic64_t migrations; -}; - -/* Function Prototypes */ - -/* Core */ -int gsp_probe(struct pci_dev *pdev, const struct pci_device_id *id); -void gsp_remove(struct pci_dev *pdev); -int gsp_firmware_load(struct gsp_device *gsp); -int gsp_rpc_init(struct gsp_device *gsp); -void gsp_shutdown(struct gsp_device *gsp); - -/* RPC Client */ -struct gsp_rpc_client *gsp_rpc_client_init(struct gsp_device *gsp); -void gsp_rpc_client_fini(struct gsp_rpc_client *rpc); -int gsp_rpc_send_sync(struct gsp_rpc_client *rpc, - enum gsp_rpc_type type, - void *payload, size_t payload_size, - void *response, size_t *response_size); -int gsp_rpc_send_async(struct gsp_rpc_client *rpc, - enum gsp_rpc_type type, - void *payload, size_t payload_size, - void (*callback)(struct gsp_rpc_client *, - struct gsp_rpc_response *, - void *), - void *ctx); -irqreturn_t gsp_isr(int irq, void *data); -void gsp_handle_notification(struct gsp_device *gsp, struct gsp_rpc_message *msg); -int gsp_errno_to_errno(int gsp_err); - -/* VF Management */ -int gsp_vf_create(struct gsp_device *gsp, const struct gsp_vf_config *config); -void gsp_vf_destroy(struct gsp_vf *vf); -struct gsp_vf *gsp_vf_get(struct gsp_device *gsp, uint32_t id); -void gsp_vf_put(struct gsp_vf *vf); - -/* Memory Management */ -int gsp_vf_mem_alloc(struct gsp_vf *vf, uint64_t size, uint32_t flags, - uint64_t *handle, uint64_t *va); -int gsp_vf_mem_free(struct gsp_vf *vf, uint64_t handle); -int gsp_vf_mem_pin(struct gsp_vf *vf, uint64_t handle, - uint64_t offset, uint64_t size, - uint64_t *dma_addr); -int gsp_vf_mem_unpin(struct gsp_vf *vf, uint64_t handle); -int gsp_vf_mem_map(struct gsp_vf *vf, uint64_t handle, uint64_t gpu_va, - uint64_t size, uint32_t prot, uint32_t flags, - uint64_t offset, uint64_t *mapped_va); -int gsp_vf_mem_unmap(struct gsp_vf *vf, uint64_t handle, uint64_t gpu_va, uint64_t size); - -/* BAR Emulation */ -int gsp_vf_bar_init(struct gsp_vf *vf); -void gsp_vf_bar_fini(struct gsp_vf *vf); -int gsp_vf_bar_trap(struct gsp_vf *vf, struct gsp_bar_trap_payload *trap); -int gsp_bar_force_access(struct gsp_vf *vf, bool enable); -int gsp_migration_bar_save(struct gsp_vf *vf, void *buf, size_t *size); -int gsp_migration_bar_restore(struct gsp_vf *vf, void *buf, size_t size); - -/* WPR Management */ -int gsp_vf_wpr_init(struct gsp_vf *vf); -void gsp_vf_wpr_fini(struct gsp_vf *vf); -int gsp_vf_wpr_protect(struct gsp_vf *vf, uint64_t base, uint64_t size, - uint32_t flags); -int gsp_vf_wpr_unprotect(struct gsp_vf *vf, uint64_t base); -int gsp_vf_wpr_protect_write(struct gsp_vf *vf, uint64_t base, uint64_t size); -int gsp_vf_wpr_protect_read(struct gsp_vf *vf, uint64_t base, uint64_t size); -int gsp_vf_wpr_set_timeout(struct gsp_vf *vf, uint64_t timeout_ns); -int gsp_vf_wpr_register_callback(struct gsp_vf *vf, enum gsp_wpr_event type, - void (*cb)(struct gsp_vf *, uint64_t, uint32_t), - void *ctx); -void gsp_wpr_handle_event(struct gsp_device *gsp, struct gsp_rpc_message *msg); - -/* Scheduling */ -int gsp_vf_schedule(struct gsp_vf *vf, uint32_t priority, uint64_t time_slice_ns); -int gsp_vf_yield(struct gsp_vf *vf); - -/* Migration */ -int gsp_migration_start(struct gsp_vf *vf, uint64_t dst_vf); -void gsp_migration_cancel(struct gsp_migration *mig); -int gsp_migration_status(struct gsp_migration *mig); - -/* Debugfs */ -int gsp_debugfs_init(struct gsp_device *gsp); -void gsp_debugfs_fini(struct gsp_device *gsp); -void gsp_debugfs_vf_add(struct gsp_vf *vf); -void gsp_debugfs_vf_remove(struct gsp_vf *vf); - -#endif /* _GSP_CORE_H_ */
\ No newline at end of file diff --git a/legacy-driver-guest/kernel-tests/gsp_vgpu_comprehensive_test.c b/legacy-driver-guest/kernel-tests/gsp_vgpu_comprehensive_test.c deleted file mode 100644 index 7918beb..0000000 --- a/legacy-driver-guest/kernel-tests/gsp_vgpu_comprehensive_test.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * GSP vGPU-IO Driver - Comprehensive Test Suite - * Tests all driver components: RPC, VF, BAR, WPR, Migration - * Compiles against kernel headers only (no driver dependency) - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/ktime.h> -#include <linux/atomic.h> -#include <linux/list.h> -#include <linux/idr.h> -#include <linux/mutex.h> -#include <linux/kref.h> -#include <linux/completion.h> -#include <linux/wait.h> -#include <linux/spinlock.h> -#include <linux/debugfs.h> -#include <linux/vmalloc.h> - -#include <gsp_core.h> - -static int test_count = 0; -static int pass_count = 0; -static int fail_count = 0; - -#define TEST_ASSERT(cond, msg) \ - do { \ - test_count++; \ - if (cond) { \ - pass_count++; \ - pr_info("PASS: %s\n", msg); \ - } else { \ - fail_count++; \ - pr_err("FAIL: %s\n", msg); \ - } \ - } while (0) - -#define TEST_ASSERT_EQ(a, b, msg) \ - TEST_ASSERT((a) == (b), msg " (expected " #b ", got " #a ")") - -#define TEST_ASSERT_NE(a, b, msg) \ - TEST_ASSERT((a) != (b), msg " (expected not " #b ", got " #a ")") - -/* ============================================================ - * Test: Kernel API Availability - * ============================================================ */ - -static int test_kernel_apis(void) -{ - pr_info("=== Testing Kernel API Availability ===\n"); - - /* Test kref */ - struct kref *ref = kmalloc(sizeof(*ref), GFP_KERNEL); - TEST_ASSERT(ref != NULL, "kref allocation"); - kref_init(ref); - TEST_ASSERT(kref_read(ref) == 1, "kref_init sets refcount to 1"); - - kref_get(ref); - TEST_ASSERT(kref_read(ref) == 2, "kref_get increments refcount"); - - kref_put(ref, (void (*)(struct kref *))kfree); - TEST_ASSERT(kref_read(ref) == 1, "kref_put decrements refcount"); - - kref_put(ref, (void (*)(struct kref *))kfree); - TEST_ASSERT(kref_read(ref) == 0, "kref_put reaches zero"); - - /* Test completion */ - struct completion comp; - init_completion(&comp); - TEST_ASSERT(!completion_done(&comp), "completion initially not done"); - complete(&comp); - TEST_ASSERT(completion_done(&comp), "completion marked done"); - - init_completion(&comp); - TEST_ASSERT(wait_for_completion_timeout(&comp, msecs_to_jiffies(100)) > 0, - "wait_for_completion_timeout works"); - - /* Test atomic64 */ - atomic64_t a64 = ATOMIC64_INIT(0); - atomic64_inc(&a64); - TEST_ASSERT_EQ(atomic64_read(&a64), 1, "atomic64_inc"); - atomic64_add(5, &a64); - TEST_ASSERT_EQ(atomic64_read(&a64), 6, "atomic64_add"); - atomic64_sub(3, &a64); - TEST_ASSERT_EQ(atomic64_read(&a64), 3, "atomic64_sub"); - - /* Test mutex */ - struct mutex mtx; - mutex_init(&mtx); - mutex_lock(&mtx); - TEST_ASSERT(mutex_is_locked(&mtx), "mutex_is_locked after lock"); - mutex_unlock(&mtx); - TEST_ASSERT(!mutex_is_locked(&mtx), "mutex_is_locked after unlock"); - - /* Test spinlock */ - spinlock_t sl = __SPIN_LOCK_UNLOCKED(sl); - unsigned long flags; - spin_lock_irqsave(&sl, flags); - TEST_ASSERT(spin_is_locked(&sl), "spin_is_locked after lock"); - spin_unlock_irqrestore(&sl, flags); - TEST_ASSERT(!spin_is_locked(&sl), "spin_is_locked after unlock"); - - /* Test idr */ - struct idr idr; - idr_init(&idr); - int id = idr_alloc(&idr, (void *)0xdeadbeef, 1, 100, GFP_KERNEL); - TEST_ASSERT(id >= 1 && id < 100, "idr_alloc returns valid id"); - void *ptr = idr_find(&idr, id); - TEST_ASSERT(ptr == (void *)0xdeadbeef, "idr_find returns correct pointer"); - idr_remove(&idr, id); - TEST_ASSERT(idr_find(&idr, id) == NULL, "idr_remove works"); - idr_destroy(&idr); - - /* Test list */ - struct list_head head; - INIT_LIST_HEAD(&head); - TEST_ASSERT(list_empty(&head), "list_empty on new list"); - - struct list_head item; - INIT_LIST_HEAD(&item); - list_add(&item, &head); - TEST_ASSERT(!list_empty(&head), "list not empty after add"); - list_del(&item); - TEST_ASSERT(list_empty(&head), "list empty after del"); - - /* Test ktime */ - ktime_t start = ktime_get(); - ktime_t end = ktime_get(); - s64 diff = ktime_to_ns(ktime_sub(end, start)); - TEST_ASSERT(diff >= 0, "ktime_get and ktime_to_ns work"); - - return 0; -} - -/* ============================================================ - * Test: Structure Sizes (from driver header) - * ============================================================ */ - -static int test_structure_sizes(void) -{ - pr_info("=== Testing Structure Sizes ===\n"); - - /* These sizes must match driver/include/gsp_core.h */ - TEST_ASSERT_EQ(sizeof(struct gsp_rpc_header), 64, "gsp_rpc_header size"); - TEST_ASSERT_EQ(sizeof(struct gsp_rpc_message), 256, "gsp_rpc_message size"); - TEST_ASSERT_EQ(sizeof(struct gsp_rpc_response), 32, "gsp_rpc_response size"); - TEST_ASSERT_EQ(sizeof(struct gsp_alloc_payload), 40, "gsp_alloc_payload size"); - TEST_ASSERT_EQ(sizeof(struct gsp_alloc_response), 24, "gsp_alloc_response size"); - TEST_ASSERT_EQ(sizeof(struct gsp_pin_payload), 40, "gsp_pin_payload size"); - TEST_ASSERT_EQ(sizeof(struct gsp_pin_response), 8, "gsp_pin_response size"); - TEST_ASSERT_EQ(sizeof(struct gsp_bar_trap_payload), 40, "gsp_bar_trap_payload size"); - TEST_ASSERT_EQ(sizeof(struct gsp_bar_trap_response), 8, "gsp_bar_trap_response size"); - TEST_ASSERT_EQ(sizeof(struct gsp_migrate_payload), 56, "gsp_migrate_payload size"); - TEST_ASSERT_EQ(sizeof(struct gsp_subcmd_desc), 8, "gsp_subcmd_desc size"); - TEST_ASSERT_EQ(sizeof(struct gsp_vf_config), 56, "gsp_vf_config size"); - - return 0; -} - -/* ============================================================ - * Test: Enum Values (from driver header) - * ============================================================ */ - -static int test_enum_values(void) -{ - pr_info("=== Testing Enum Values ===\n"); - - TEST_ASSERT_EQ(GSP_RPC_ALLOC, 0x01, "RPC_ALLOC"); - TEST_ASSERT_EQ(GSP_RPC_FREE, 0x02, "RPC_FREE"); - TEST_ASSERT_EQ(GSP_RPC_MAP, 0x03, "RPC_MAP"); - TEST_ASSERT_EQ(GSP_RPC_UNMAP, 0x04, "RPC_UNMAP"); - TEST_ASSERT_EQ(GSP_RPC_PIN, 0x05, "RPC_PIN"); - TEST_ASSERT_EQ(GSP_RPC_UNPIN, 0x06, "RPC_UNPIN"); - TEST_ASSERT_EQ(GSP_RPC_SCHEDULE, 0x07, "RPC_SCHEDULE"); - TEST_ASSERT_EQ(GSP_RPC_YIELD, 0x08, "RPC_YIELD"); - TEST_ASSERT_EQ(GSP_RPC_NOTIFY, 0x09, "RPC_NOTIFY"); - TEST_ASSERT_EQ(GSP_RPC_BAR_TRAP, 0x0A, "RPC_BAR_TRAP"); - TEST_ASSERT_EQ(GSP_RPC_MIGRATE, 0x0B, "RPC_MIGRATE"); - TEST_ASSERT_EQ(GSP_RPC_DEBUG, 0x0C, "RPC_DEBUG"); - - TEST_ASSERT_EQ(GSP_MEM_VRAM, 0, "MEM_VRAM"); - TEST_ASSERT_EQ(GSP_MEM_SYSMEM, 1, "MEM_SYSMEM"); - TEST_ASSERT_EQ(GSP_MEM_UNCACHED, 2, "MEM_UNCACHED"); - - TEST_ASSERT_EQ(GSP_PIN_READ, (1 << 0), "PIN_READ"); - TEST_ASSERT_EQ(GSP_PIN_WRITE, (1 << 1), "PIN_WRITE"); - TEST_ASSERT_EQ(GSP_PIN_LONGTERM, (1 << 2), "PIN_LONGTERM"); - - TEST_ASSERT_EQ(GSP_MIG_QUERY, 0, "MIG_QUERY"); - TEST_ASSERT_EQ(GSP_MIG_PREPARE, 1, "MIG_PREPARE"); - TEST_ASSERT_EQ(GSP_MIG_TRANSFER, 2, "MIG_TRANSFER"); - TEST_ASSERT_EQ(GSP_MIG_COMMIT, 3, "MIG_COMMIT"); - TEST_ASSERT_EQ(GSP_MIG_CLEANUP, 4, "MIG_CLEANUP"); - - TEST_ASSERT_EQ(GSP_MIG_LIVE, (1 << 0), "MIG_LIVE"); - TEST_ASSERT_EQ(GSP_MIG_POSTCOPY, (1 << 1), "MIG_POSTCOPY"); - TEST_ASSERT_EQ(GSP_MIG_AUTO_COMMIT, (1 << 2), "MIG_AUTO_COMMIT"); - TEST_ASSERT_EQ(GSP_MIG_VERIFY, (1 << 3), "MIG_VERIFY"); - - TEST_ASSERT_EQ(GSP_VF_CREATING, 0, "VF_CREATING"); - TEST_ASSERT_EQ(GSP_VF_ACTIVE, 1, "VF_ACTIVE"); - TEST_ASSERT_EQ(GSP_VF_MIGRATING, 2, "VF_MIGRATING"); - TEST_ASSERT_EQ(GSP_VF_SUSPENDED, 3, "VF_SUSPENDED"); - TEST_ASSERT_EQ(GSP_VF_DESTROYING, 4, "VF_DESTROYING"); - - return 0; -} - -/* ============================================================ - * Test: Error Code Mapping - * ============================================================ */ - -static int test_error_codes(void) -{ - pr_info("=== Testing Error Codes ===\n"); - - TEST_ASSERT_EQ(GSP_OK, 0, "GSP_OK"); - TEST_ASSERT_EQ(GSP_EPERM, 0xFFFFFFFF, "GSP_EPERM"); - TEST_ASSERT_EQ(GSP_ENOENT, 0xFFFFFFFE, "GSP_ENOENT"); - TEST_ASSERT_EQ(GSP_EINVAL, 0xFFFFFFFD, "GSP_EINVAL"); - TEST_ASSERT_EQ(GSP_ENODEV, 0xFFFFFFFA, "GSP_ENODEV"); - TEST_ASSERT_EQ(GSP_ENOMEM, 0xFFFFFFF4, "GSP_ENOMEM"); - TEST_ASSERT_EQ(GSP_EBUSY, 0xFFFFFFEE, "GSP_EBUSY"); - TEST_ASSERT_EQ(GSP_ENOSPC, 0xFFFFFFE4, "GSP_ENOSPC"); - TEST_ASSERT_EQ(GSP_ETIMEDOUT, 0x0000001E, "GSP_ETIMEDOUT"); - TEST_ASSERT_EQ(GSP_EOVERFLOW, 0x00000025, "GSP_EOVERFLOW"); - TEST_ASSERT_EQ(GSP_EDEV, 0x0000001F, "GSP_EDEV"); - - return 0; -} - -/* ============================================================ - * Test: Firmware Constants - * ============================================================ */ - -static int test_firmware_constants(void) -{ - pr_info("=== Testing Firmware Constants ===\n"); - - TEST_ASSERT_EQ(GSP_FW_BASE_ADDR, 0x04000000ULL, "FW_BASE_ADDR"); - TEST_ASSERT_EQ(GSP_FW_SIZE, 0x02000000ULL, "FW_SIZE"); - TEST_ASSERT_EQ(GSP_ENTRY_POINT, 0x04009000ULL, "ENTRY_POINT"); - TEST_ASSERT_EQ(GSP_PRIMARY_DISPATCHER, 0x057A1AC0ULL, "PRIMARY_DISPATCHER"); - TEST_ASSERT_EQ(GSP_SECONDARY_DISPATCHER, 0x04ED39DCULL, "SECONDARY_DISPATCHER"); - TEST_ASSERT_EQ(GSP_RPC_JUMP_TABLE, 0x059BFEB0ULL, "RPC_JUMP_TABLE"); - TEST_ASSERT_EQ(GSP_BAR0_DOORBELL, 0x1000, "BAR0_DOORBELL"); - TEST_ASSERT_EQ(GSP_BAR0_MSIX, 0x2000, "BAR0_MSIX"); - TEST_ASSERT_EQ(GSP_MSG_RING_SIZE, 256, "MSG_RING_SIZE"); - TEST_ASSERT_EQ(GSP_MSG_MAX_SIZE, 256, "MSG_MAX_SIZE"); - TEST_ASSERT_EQ(GSP_MAX_PENDING, 64, "MAX_PENDING"); - - return 0; -} - -/* ============================================================ - * Test: Migration State Enum (internal) - * ============================================================ */ - -static int test_migration_states(void) -{ - pr_info("=== Testing Migration States ===\n"); - - TEST_ASSERT_EQ(GSP_MIG_S_IDLE, 0, "MIG_S_IDLE"); - TEST_ASSERT_EQ(GSP_MIG_S_QUERY, 1, "MIG_S_QUERY"); - TEST_ASSERT_EQ(GSP_MIG_S_PREPARE, 2, "MIG_S_PREPARE"); - TEST_ASSERT_EQ(GSP_MIG_S_TRANSFER, 3, "MIG_S_TRANSFER"); - TEST_ASSERT_EQ(GSP_MIG_S_COMMIT, 4, "MIG_S_COMMIT"); - TEST_ASSERT_EQ(GSP_MIG_S_CLEANUP, 5, "MIG_S_CLEANUP"); - TEST_ASSERT_EQ(GSP_MIG_S_FAILED, 6, "MIG_S_FAILED"); - TEST_ASSERT_EQ(GSP_MIG_S_COMPLETED, 7, "MIG_S_COMPLETED"); - - return 0; -} - -/* ============================================================ - * Test: WPR Flags and Events - * ============================================================ */ - -static int test_wpr_flags(void) -{ - pr_info("=== Testing WPR Flags ===\n"); - - TEST_ASSERT_EQ(GSP_WPR_WRITE, (1 << 0), "WPR_WRITE"); - TEST_ASSERT_EQ(GSP_WPR_READ, (1 << 1), "WPR_READ"); - TEST_ASSERT_EQ(GSP_WPR_EXECUTE, (1 << 2), "WPR_EXECUTE"); - - TEST_ASSERT_EQ(GSP_WPR_WRITE_COMPLETE, 0, "WPR_WRITE_COMPLETE"); - TEST_ASSERT_EQ(GSP_WPR_READ_COMPLETE, 1, "WPR_READ_COMPLETE"); - TEST_ASSERT_EQ(GSP_WPR_WRITE_TIMEOUT, 2, "WPR_WRITE_TIMEOUT"); - TEST_ASSERT_EQ(GSP_WPR_READ_TIMEOUT, 3, "WPR_READ_TIMEOUT"); - - return 0; -} - -/* ============================================================ - * Test: Message Flags - * ============================================================ */ - -static int test_message_flags(void) -{ - pr_info("=== Testing Message Flags ===\n"); - - TEST_ASSERT_EQ(GSP_MSG_SYNC, (1 << 0), "MSG_SYNC"); - TEST_ASSERT_EQ(GSP_MSG_ASYNC, (1 << 1), "MSG_ASYNC"); - TEST_ASSERT_EQ(GSP_MSG_NOREPLY, (1 << 2), "MSG_NOREPLY"); - - return 0; -} - -/* ============================================================ - * Test: BAR Trap Types - * ============================================================ */ - -static int test_bar_trap_types(void) -{ - pr_info("=== Testing BAR Trap Types ===\n"); - - TEST_ASSERT_EQ(GSP_BAR_READ, 0, "BAR_READ"); - TEST_ASSERT_EQ(GSP_BAR_WRITE, 1, "BAR_WRITE"); - TEST_ASSERT_EQ(GSP_BAR_ATOMIC, 2, "BAR_ATOMIC"); - - return 0; -} - -/* ============================================================ - * Test: Memory Allocation Patterns - * ============================================================ */ - -static int test_memory_patterns(void) -{ - pr_info("=== Testing Memory Allocation Patterns ===\n"); - - /* Test vzalloc/vfree */ - void *ptr = vzalloc(4096); - TEST_ASSERT(ptr != NULL, "vzalloc allocates memory"); - vfree(ptr); - - /* Test kmalloc/kfree */ - ptr = kmalloc(1024, GFP_KERNEL); - TEST_ASSERT(ptr != NULL, "kmalloc allocates memory"); - kfree(ptr); - - /* Test kcalloc */ - ptr = kcalloc(10, 64, GFP_KERNEL); - TEST_ASSERT(ptr != NULL, "kcalloc allocates zeroed memory"); - kfree(ptr); - - return 0; -} - -/* ============================================================ - * Test: String Operations - * ============================================================ */ - -static int test_string_ops(void) -{ - pr_info("=== Testing String Operations ===\n"); - - char buf[64]; - int len = snprintf(buf, sizeof(buf), "test_%d", 42); - TEST_ASSERT(len > 0 && len < sizeof(buf), "snprintf works"); - TEST_ASSERT(strcmp(buf, "test_42") == 0, "snprintf formats correctly"); - - char *dup = kstrdup("test_string", GFP_KERNEL); - TEST_ASSERT(dup != NULL, "kstrdup works"); - TEST_ASSERT(strcmp(dup, "test_string") == 0, "kstrdup copies correctly"); - kfree(dup); - - return 0; -} - -/* ============================================================ - * Test Suite Runner - * ============================================================ */ - -static int run_all_tests(void) -{ - pr_info("\n============================================================\n"); - pr_info("GSP vGPU-IO Comprehensive Test Suite Starting\n"); - pr_info("============================================================\n\n"); - - test_kernel_apis(); - test_structure_sizes(); - test_enum_values(); - test_error_codes(); - test_firmware_constants(); - test_migration_states(); - test_wpr_flags(); - test_message_flags(); - test_bar_trap_types(); - test_memory_patterns(); - test_string_ops(); - - pr_info("\n============================================================\n"); - pr_info("TEST RESULTS: %d total, %d passed, %d failed\n", - test_count, pass_count, fail_count); - pr_info("============================================================\n"); - - if (fail_count == 0) { - pr_info("TEST SUITE PASSED\n"); - return 0; - } else { - pr_err("TEST SUITE FAILED\n"); - return -1; - } -} - -/* ============================================================ - * Module Init/Exit - * ============================================================ */ - -static int __init gsp_test_init(void) -{ - return run_all_tests(); -} - -static void __exit gsp_test_exit(void) -{ - pr_info("GSP vGPU-IO test module unloaded\n"); -} - -module_init(gsp_test_init); -module_exit(gsp_test_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("NVIDIA vGPU-IO Team"); -MODULE_DESCRIPTION("GSP vGPU-IO Comprehensive Test Suite"); -MODULE_VERSION("1.0.0");
\ No newline at end of file diff --git a/legacy-driver-guest/kernel-tests/gsp_vgpu_kunit_test.c b/legacy-driver-guest/kernel-tests/gsp_vgpu_kunit_test.c deleted file mode 100644 index c661f91..0000000 --- a/legacy-driver-guest/kernel-tests/gsp_vgpu_kunit_test.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * GSP vGPU-IO KUnit Tests - * In-kernel unit tests for the driver - */ - -#include <kunit/test.h> -#include <kunit/mock.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/atomic.h> -#include <linux/list.h> -#include <linux/idr.h> -#include <linux/mutex.h> -#include <linux/kref.h> -#include <linux/completion.h> -#include <linux/wait.h> -#include <linux/spinlock.h> - -#include <gsp_core.h> - -/* ============================================================ - * Test: Structure Sizes and Alignments - * ============================================================ */ - -static void test_structure_sizes(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_rpc_header), 64); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_rpc_message), 256); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_rpc_response), 32); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_subcmd_desc), 8); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_vf_config), 64); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_alloc_payload), 48); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_alloc_response), 24); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_pin_payload), 40); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_pin_response), 8); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_bar_trap_payload), 40); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_bar_trap_response), 8); - KUNIT_EXPECT_EQ(test, sizeof(struct gsp_migrate_payload), 64); -} - -static void test_structure_alignments(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_rpc_header), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_rpc_message), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_rpc_response), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_subcmd_desc), 4); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_vf_config), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_alloc_payload), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_alloc_response), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_pin_payload), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_pin_response), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_bar_trap_payload), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_bar_trap_response), 8); - KUNIT_EXPECT_EQ(test, __alignof__(struct gsp_migrate_payload), 8); -} - -/* ============================================================ - * Test: Payload Encoding/Decoding - * ============================================================ */ - -static void test_alloc_payload_encoding(struct kunit *test) -{ - struct gsp_alloc_payload payload = {0}; - - payload.size = cpu_to_le64(0x100000); - payload.type = cpu_to_le32(GSP_MEM_VRAM); - payload.alignment = cpu_to_le32(0x1000); - payload.va_hint = cpu_to_le64(0x0); - payload.flags = cpu_to_le32(0x3); - payload.pid = cpu_to_le32(0x456); - payload.vf_id = cpu_to_le32(0x1); - - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.size), 0x100000); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.type), GSP_MEM_VRAM); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.alignment), 0x1000); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.va_hint), 0x0); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.flags), 0x3); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.pid), 0x456); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.vf_id), 0x1); -} - -static void test_pin_payload_encoding(struct kunit *test) -{ - struct gsp_pin_payload payload = {0}; - - payload.handle = cpu_to_le64(0xCAFEBABE); - payload.offset = cpu_to_le64(0x1000); - payload.size = cpu_to_le64(0x10000); - payload.vf_id = cpu_to_le32(0x2); - payload.flags = cpu_to_le32(GSP_PIN_READ | GSP_PIN_WRITE); - - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.handle), 0xCAFEBABE); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.offset), 0x1000); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.size), 0x10000); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.vf_id), 0x2); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.flags), GSP_PIN_READ | GSP_PIN_WRITE); -} - -static void test_bar_trap_payload_encoding(struct kunit *test) -{ - struct gsp_bar_trap_payload payload = {0}; - - payload.bar_index = cpu_to_le32(1); - payload.trap_type = cpu_to_le32(GSP_BAR_WRITE); - payload.offset = cpu_to_le64(0x1000); - payload.value = cpu_to_le64(0xDEADBEEF); - payload.size = cpu_to_le32(4); - payload.vf_id = cpu_to_le32(0x1); - - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.bar_index), 1); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.trap_type), GSP_BAR_WRITE); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.offset), 0x1000); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.value), 0xDEADBEEF); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.size), 4); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.vf_id), 0x1); -} - -static void test_migrate_payload_encoding(struct kunit *test) -{ - struct gsp_migrate_payload payload = {0}; - - payload.phase = cpu_to_le32(GSP_MIG_PREPARE); - payload.subcmd = cpu_to_le32(3); - payload.src_vf = cpu_to_le64(0x1); - payload.dst_vf = cpu_to_le64(0x2); - payload.data_ptr = cpu_to_le64(0x80000000); - payload.data_size = cpu_to_le64(0x1000); - payload.flags = cpu_to_le32(GSP_MIG_LIVE | GSP_MIG_VERIFY); - payload.token = cpu_to_le64(0xABCDEF1234567890); - - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.phase), GSP_MIG_PREPARE); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.subcmd), 3); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.src_vf), 0x1); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.dst_vf), 0x2); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.data_ptr), 0x80000000); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.data_size), 0x1000); - KUNIT_EXPECT_EQ(test, le32_to_cpu(payload.flags), GSP_MIG_LIVE | GSP_MIG_VERIFY); - KUNIT_EXPECT_EQ(test, le64_to_cpu(payload.token), 0xABCDEF1234567890); -} - -static void test_subcmd_desc_encoding(struct kunit *test) -{ - struct gsp_subcmd_desc desc = {0}; - - desc.subcmd_id = cpu_to_le32(0x14); - desc.echo_flags_b = 0xAA; - desc.echo_flags_a = 0xBB; - desc.echo_flags_c = 0xCC; - - KUNIT_EXPECT_EQ(test, le32_to_cpu(desc.subcmd_id), 0x14); - KUNIT_EXPECT_EQ(test, desc.echo_flags_b, 0xAA); - KUNIT_EXPECT_EQ(test, desc.echo_flags_a, 0xBB); - KUNIT_EXPECT_EQ(test, desc.echo_flags_c, 0xCC); -} - -/* ============================================================ - * Test: Firmware Address Constants - * ============================================================ */ - -static void test_firmware_addresses(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_FW_BASE_ADDR, 0x04000000ULL); - KUNIT_EXPECT_EQ(test, GSP_ENTRY_POINT, 0x04009000ULL); - KUNIT_EXPECT_EQ(test, GSP_PRIMARY_DISPATCHER, 0x057A1AC0ULL); - KUNIT_EXPECT_EQ(test, GSP_SECONDARY_DISPATCHER, 0x04ED39DCULL); - KUNIT_EXPECT_EQ(test, GSP_RPC_JUMP_TABLE, 0x059BFEB0ULL); - KUNIT_EXPECT_EQ(test, 0x04179ED8ULL, 0x04179ED8ULL); /* Migration Table 1 */ - KUNIT_EXPECT_EQ(test, 0x04179FBCULL, 0x04179FBCULL); /* Migration Table 2 */ - KUNIT_EXPECT_EQ(test, 0x04CB8188ULL, 0x04CB8188ULL); /* BAR Handler */ - KUNIT_EXPECT_EQ(test, 0x04F00B0CULL, 0x04F00B0CULL); /* WPR Handler 1 */ - KUNIT_EXPECT_EQ(test, 0x04F00C78ULL, 0x04F00C78ULL); /* WPR Handler 2 */ - KUNIT_EXPECT_EQ(test, 0x057E94ECULL, 0x057E94ECULL); /* ALLOC Main */ - KUNIT_EXPECT_EQ(test, 0x051EFBF4ULL, 0x051EFBF4ULL); /* SCHEDULE Main */ -} - -/* ============================================================ - * Test: RPC Type Constants - * ============================================================ */ - -static void test_rpc_types(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_RPC_ALLOC, 0x01); - KUNIT_EXPECT_EQ(test, GSP_RPC_FREE, 0x02); - KUNIT_EXPECT_EQ(test, GSP_RPC_MAP, 0x03); - KUNIT_EXPECT_EQ(test, GSP_RPC_UNMAP, 0x04); - KUNIT_EXPECT_EQ(test, GSP_RPC_PIN, 0x05); - KUNIT_EXPECT_EQ(test, GSP_RPC_UNPIN, 0x06); - KUNIT_EXPECT_EQ(test, GSP_RPC_SCHEDULE, 0x07); - KUNIT_EXPECT_EQ(test, GSP_RPC_YIELD, 0x08); - KUNIT_EXPECT_EQ(test, GSP_RPC_NOTIFY, 0x09); - KUNIT_EXPECT_EQ(test, GSP_RPC_BAR_TRAP, 0x0A); - KUNIT_EXPECT_EQ(test, GSP_RPC_MIGRATE, 0x0B); - KUNIT_EXPECT_EQ(test, GSP_RPC_DEBUG, 0x0C); -} - -static void test_migration_constants(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_MIG_QUERY, 0); - KUNIT_EXPECT_EQ(test, GSP_MIG_PREPARE, 1); - KUNIT_EXPECT_EQ(test, GSP_MIG_TRANSFER, 2); - KUNIT_EXPECT_EQ(test, GSP_MIG_COMMIT, 3); - KUNIT_EXPECT_EQ(test, GSP_MIG_CLEANUP, 4); - - KUNIT_EXPECT_EQ(test, GSP_MIG_LIVE, (1 << 0)); - KUNIT_EXPECT_EQ(test, GSP_MIG_POSTCOPY, (1 << 1)); - KUNIT_EXPECT_EQ(test, GSP_MIG_AUTO_COMMIT, (1 << 2)); - KUNIT_EXPECT_EQ(test, GSP_MIG_VERIFY, (1 << 3)); -} - -static void test_bar_trap_types(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_BAR_READ, 0); - KUNIT_EXPECT_EQ(test, GSP_BAR_WRITE, 1); - KUNIT_EXPECT_EQ(test, GSP_BAR_ATOMIC, 2); -} - -static void test_pin_flags(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_PIN_READ, (1 << 0)); - KUNIT_EXPECT_EQ(test, GSP_PIN_WRITE, (1 << 1)); - KUNIT_EXPECT_EQ(test, GSP_PIN_LONGTERM, (1 << 2)); -} - -static void test_wpr_flags(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_WPR_WRITE, (1 << 0)); - KUNIT_EXPECT_EQ(test, GSP_WPR_READ, (1 << 1)); - KUNIT_EXPECT_EQ(test, GSP_WPR_EXECUTE, (1 << 2)); -} - -static void test_vf_states(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_VF_CREATING, 0); - KUNIT_EXPECT_EQ(test, GSP_VF_ACTIVE, 1); - KUNIT_EXPECT_EQ(test, GSP_VF_MIGRATING, 2); - KUNIT_EXPECT_EQ(test, GSP_VF_SUSPENDED, 3); - KUNIT_EXPECT_EQ(test, GSP_VF_DESTROYING, 4); -} - -static void test_msg_flags(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_MSG_SYNC, (1 << 0)); - KUNIT_EXPECT_EQ(test, GSP_MSG_ASYNC, (1 << 1)); - KUNIT_EXPECT_EQ(test, GSP_MSG_NOREPLY, (1 << 2)); -} - -/* ============================================================ - * Test: Error Code Translation - * ============================================================ */ - -static void test_error_codes(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_OK), 0); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_EPERM), -EPERM); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_ENOENT), -ENOENT); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_EINVAL), -EINVAL); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_ENODEV), -ENODEV); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_ENOMEM), -ENOMEM); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_EBUSY), -EBUSY); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_ENOSPC), -ENOSPC); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_ETIMEDOUT), -ETIMEDOUT); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_EOVERFLOW), -EOVERFLOW); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(GSP_EDEV), -EIO); - KUNIT_EXPECT_EQ(test, gsp_errno_to_errno(0xDEADBEEF), -EIO); -} - -/* ============================================================ - * Test: Memory Types - * ============================================================ */ - -static void test_memory_types(struct kunit *test) -{ - KUNIT_EXPECT_EQ(test, GSP_MEM_VRAM, 0); - KUNIT_EXPECT_EQ(test, GSP_MEM_SYSMEM, 1); - KUNIT_EXPECT_EQ(test, GSP_MEM_UNCACHED, 2); -} - -/* ============================================================ - * Test: Payload Capacity - * ============================================================ */ - -static void test_payload_capacity(struct kunit *test) -{ - KUNIT_EXPECT_TRUE(test, sizeof(struct gsp_alloc_payload) <= 192); - KUNIT_EXPECT_TRUE(test, sizeof(struct gsp_pin_payload) <= 192); - KUNIT_EXPECT_TRUE(test, sizeof(struct gsp_bar_trap_payload) <= 192); - KUNIT_EXPECT_TRUE(test, sizeof(struct gsp_migrate_payload) <= 192); - KUNIT_EXPECT_TRUE(test, sizeof(struct gsp_subcmd_desc) <= 192); -} - -/* ============================================================ - * Test Suite Registration - * ============================================================ */ - -static struct kunit_case gsp_vgpu_test_cases[] = { - KUNIT_CASE(test_structure_sizes), - KUNIT_CASE(test_structure_alignments), - KUNIT_CASE(test_alloc_payload_encoding), - KUNIT_CASE(test_pin_payload_encoding), - KUNIT_CASE(test_bar_trap_payload_encoding), - KUNIT_CASE(test_migrate_payload_encoding), - KUNIT_CASE(test_subcmd_desc_encoding), - KUNIT_CASE(test_firmware_addresses), - KUNIT_CASE(test_rpc_types), - KUNIT_CASE(test_migration_constants), - KUNIT_CASE(test_bar_trap_types), - KUNIT_CASE(test_pin_flags), - KUNIT_CASE(test_wpr_flags), - KUNIT_CASE(test_vf_states), - KUNIT_CASE(test_msg_flags), - KUNIT_CASE(test_error_codes), - KUNIT_CASE(test_memory_types), - KUNIT_CASE(test_payload_capacity), - {} -}; - -static struct kunit_suite gsp_vgpu_test_suite = { - .name = "gsp-vgpu-io", - .test_cases = gsp_vgpu_test_cases, -}; - -kunit_test_suites(&gsp_vgpu_test_suite); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Open-IOV Project"); -MODULE_DESCRIPTION("GSP vGPU-IO KUnit Tests");
\ No newline at end of file diff --git a/legacy-driver-guest/kernel-tests/gsp_vgpu_mock_test.c b/legacy-driver-guest/kernel-tests/gsp_vgpu_mock_test.c deleted file mode 100644 index b9a46df..0000000 --- a/legacy-driver-guest/kernel-tests/gsp_vgpu_mock_test.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - * GSP vGPU-IO Driver Mock Test - * Tests driver logic with mocked hardware interfaces - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/mutex.h> -#include <linux/list.h> -#include <linux/idr.h> -#include <linux/kref.h> -#include <linux/completion.h> -#include <linux/atomic.h> - -#define TEST_PASS 0 -#define TEST_FAIL -1 - -static int test_count = 0; -static int pass_count = 0; -static int fail_count = 0; - -#define TEST_ASSERT(cond, msg) \ - do { \ - test_count++; \ - if (cond) { \ - pass_count++; \ - pr_info("PASS: %s\n", msg); \ - } else { \ - fail_count++; \ - pr_err("FAIL: %s\n", msg); \ - } \ - } while (0) - -#define TEST_ASSERT_EQ(a, b, msg) \ - TEST_ASSERT((a) == (b), msg " (expected " #b ", got " #a ")") - -/* ============================================================ - * Mock Hardware Abstraction - * ============================================================ */ - -struct mock_hw { - u64 bar0_regs[256]; - u64 bar1_regs[256]; - u8 *fw_memory; - size_t fw_size; - bool doorbell_triggered; - u32 doorbell_count; - spinlock_t lock; -}; - -static struct mock_hw *mock_hw_create(void) -{ - struct mock_hw *hw = kzalloc(sizeof(*hw), GFP_KERNEL); - if (!hw) - return NULL; - - hw->fw_memory = vmalloc(32 * 1024 * 1024); // 32MB - if (!hw->fw_memory) { - kfree(hw); - return NULL; - } - hw->fw_size = 32 * 1024 * 1024; - spin_lock_init(&hw->lock); - return hw; -} - -static void mock_hw_destroy(struct mock_hw *hw) -{ - if (!hw) - return; - vfree(hw->fw_memory); - kfree(hw); -} - -static void mock_hw_write_bar0(struct mock_hw *hw, u32 offset, u32 value) -{ - unsigned long flags; - spin_lock_irqsave(&hw->lock, flags); - if (offset / 4 < 256) - hw->bar0_regs[offset / 4] = value; - if (offset == 0x1000) { // Doorbell - hw->doorbell_triggered = true; - hw->doorbell_count++; - } - spin_unlock_irqrestore(&hw->lock, flags); -} - -static u32 mock_hw_read_bar0(struct mock_hw *hw, u32 offset) -{ - unsigned long flags; - u32 value = 0; - spin_lock_irqsave(&hw->lock, flags); - if (offset / 4 < 256) - value = hw->bar0_regs[offset / 4]; - spin_unlock_irqrestore(&hw->lock, flags); - return value; -} - -static void mock_hw_write_bar1(struct mock_hw *hw, u64 offset, u64 value) -{ - unsigned long flags; - spin_lock_irqsave(&hw->lock, flags); - if (offset < hw->fw_size) - *(u64 *)(hw->fw_memory + offset) = value; - spin_unlock_irqrestore(&hw->lock, flags); -} - -static u64 mock_hw_read_bar1(struct mock_hw *hw, u64 offset) -{ - unsigned long flags; - u64 value = 0; - spin_lock_irqsave(&hw->lock, flags); - if (offset < hw->fw_size) - value = *(u64 *)(hw->fw_memory + offset); - spin_unlock_irqrestore(&hw->lock, flags); - return value; -} - -/* ============================================================ - * Mock VF Operations - * ============================================================ */ - -struct mock_vf { - u32 id; - u64 bar1_offset; - u64 bar1_size; - u64 pt_base; - u64 pt_size; - u64 cmd_base; - u64 cmd_size; - bool active; - struct { - u64 aperture_offset; - u64 aperture_size; - bool force_access; - u32 force_vf; - } bar_state; - struct list_head wpr_list; - struct mutex lock; -}; - -struct mock_wpr_region { - struct list_head list; - u64 base; - u64 size; - u32 flags; -}; - -static struct mock_vf *mock_vf_create(u32 id, u64 bar1_offset, u64 bar1_size, - u64 pt_base, u64 pt_size, - u64 cmd_base, u64 cmd_size) -{ - struct mock_vf *vf = kzalloc(sizeof(*vf), GFP_KERNEL); - if (!vf) - return NULL; - - vf->id = id; - vf->bar1_offset = bar1_offset; - vf->bar1_size = bar1_size; - vf->pt_base = pt_base; - vf->pt_size = pt_size; - vf->cmd_base = cmd_base; - vf->cmd_size = cmd_size; - vf->active = true; - INIT_LIST_HEAD(&vf->wpr_list); - mutex_init(&vf->lock); - - vf->bar_state.aperture_offset = bar1_offset; - vf->bar_state.aperture_size = bar1_size; - vf->bar_state.force_access = false; - vf->bar_state.force_vf = 0; - - return vf; -} - -static void mock_vf_destroy(struct mock_vf *vf) -{ - if (!vf) - return; - - struct mock_wpr_region *rgn, *tmp; - mutex_lock(&vf->lock); - list_for_each_entry_safe(rgn, tmp, &vf->wpr_list, list) { - list_del(&rgn->list); - kfree(rgn); - } - mutex_unlock(&vf->lock); - - kfree(vf); -} - -static int mock_vf_wpr_add(struct mock_vf *vf, u64 base, u64 size, u32 flags) -{ - struct mock_wpr_region *rgn = kzalloc(sizeof(*rgn), GFP_KERNEL); - if (!rgn) - return -ENOMEM; - - rgn->base = base; - rgn->size = size; - rgn->flags = flags; - - mutex_lock(&vf->lock); - list_add(&rgn->list, &vf->wpr_list); - mutex_unlock(&vf->lock); - - return 0; -} - -static int mock_vf_wpr_remove(struct mock_vf *vf, u64 base) -{ - struct mock_wpr_region *rgn, *tmp; - bool found = false; - - mutex_lock(&vf->lock); - list_for_each_entry_safe(rgn, tmp, &vf->wpr_list, list) { - if (rgn->base == base) { - list_del(&rgn->list); - kfree(rgn); - found = true; - break; - } - } - mutex_unlock(&vf->lock); - - return found ? 0 : -ENOENT; -} - -/* ============================================================ - * Mock RPC Client - * ============================================================ */ - -struct mock_rpc_client { - u32 seq; - u32 pending_seq[64]; - u32 pending_count; - struct mutex lock; -}; - -static struct mock_rpc_client *mock_rpc_create(void) -{ - struct mock_rpc_client *rpc = kzalloc(sizeof(*rpc), GFP_KERNEL); - if (!rpc) - return NULL; - mutex_init(&rpc->lock); - return rpc; -} - -static void mock_rpc_destroy(struct mock_rpc_client *rpc) -{ - if (!rpc) - return; - kfree(rpc); -} - -static int mock_rpc_send(struct mock_rpc_client *rpc, u32 rpc_type, - void *payload, size_t payload_size, - void *response, size_t *response_size) -{ - if (!rpc) - return -EINVAL; - - mutex_lock(&rpc->lock); - rpc->seq++; - rpc->pending_seq[rpc->pending_count++] = rpc->seq; - mutex_unlock(&rpc->lock); - - /* Simulate successful response */ - if (response && response_size) { - struct gsp_rpc_response *resp = response; - resp->status = 0; - resp->rpc_type = rpc_type; - resp->sequence = rpc->seq; - *response_size = sizeof(*resp); - } - - return 0; -} - -/* ============================================================ - * Driver Logic Tests with Mocks - * ============================================================ */ - -static int test_mock_hardware(void) -{ - struct mock_hw *hw = mock_hw_create(); - TEST_ASSERT(hw != NULL, "Mock HW create"); - - /* Test BAR0 write/read */ - mock_hw_write_bar0(hw, 0x1000, 0x1); - TEST_ASSERT(hw->doorbell_triggered, "Doorbell triggered"); - TEST_ASSERT_EQ(hw->doorbell_count, 1, "Doorbell count"); - - u32 val = mock_hw_read_bar0(hw, 0x1000); - TEST_ASSERT_EQ(val, 0x1, "BAR0 read back"); - - /* Test BAR1 write/read */ - mock_hw_write_bar1(hw, 0x1000, 0xDEADBEEFCAFEBABE); - u64 val64 = mock_hw_read_bar1(hw, 0x1000); - TEST_ASSERT_EQ(val64, 0xDEADBEEFCAFEBABE, "BAR1 read back"); - - mock_hw_destroy(hw); - return TEST_PASS; -} - -static int test_mock_vf_lifecycle(void) -{ - struct mock_vf *vf = mock_vf_create(1, 0x10000000, 0x100000, - 0x20000000, 0x100000, - 0x30000000, 0x10000); - TEST_ASSERT(vf != NULL, "Mock VF create"); - - TEST_ASSERT(vf->active, "VF active after create"); - TEST_ASSERT_EQ(vf->id, 1, "VF ID"); - TEST_ASSERT_EQ(vf->bar1_offset, 0x10000000, "BAR1 offset"); - TEST_ASSERT_EQ(vf->bar1_size, 0x100000, "BAR1 size"); - TEST_ASSERT_EQ(vf->pt_base, 0x20000000, "Page table base"); - TEST_ASSERT_EQ(vf->pt_size, 0x100000, "Page table size"); - - /* Test BAR state */ - TEST_ASSERT_EQ(vf->bar_state.aperture_offset, 0x10000000, "Aperture offset"); - TEST_ASSERT_EQ(vf->bar_state.aperture_size, 0x100000, "Aperture size"); - TEST_ASSERT(!vf->bar_state.force_access, "Force access initially false"); - - /* Test WPR list empty */ - TEST_ASSERT(list_empty(&vf->wpr_list), "WPR list empty initially"); - - mock_vf_destroy(vf); - return TEST_PASS; -} - -static int test_mock_vf_wpr(void) -{ - struct mock_vf *vf = mock_vf_create(1, 0x10000000, 0x100000, - 0x20000000, 0x100000, - 0x30000000, 0x10000); - TEST_ASSERT(vf != NULL, "Mock VF create"); - - /* Add WPR region */ - int ret = mock_vf_wpr_add(vf, 0x10000000, 0x10000, 3); - TEST_ASSERT_EQ(ret, 0, "WPR add"); - - ret = mock_vf_wpr_add(vf, 0x20000000, 0x20000, 1); - TEST_ASSERT_EQ(ret, 0, "WPR add second"); - - /* Verify list */ - int count = 0; - struct mock_wpr_region *rgn; - mutex_lock(&vf->lock); - list_for_each_entry(rgn, &vf->wpr_list, list) { - count++; - } - mutex_unlock(&vf->lock); - TEST_ASSERT_EQ(count, 2, "Two WPR regions"); - - /* Remove one */ - ret = mock_vf_wpr_remove(vf, 0x10000000); - TEST_ASSERT_EQ(ret, 0, "WPR remove"); - - count = 0; - mutex_lock(&vf->lock); - list_for_each_entry(rgn, &vf->wpr_list, list) { - count++; - } - mutex_unlock(&vf->lock); - TEST_ASSERT_EQ(count, 1, "One WPR region remaining"); - - /* Remove non-existent */ - ret = mock_vf_wpr_remove(vf, 0x30000000); - TEST_ASSERT_EQ(ret, -ENOENT, "WPR remove non-existent returns ENOENT"); - - mock_vf_destroy(vf); - return TEST_PASS; -} - -static int test_mock_rpc_client(void) -{ - struct mock_rpc_client *rpc = mock_rpc_create(); - TEST_ASSERT(rpc != NULL, "Mock RPC create"); - - struct gsp_rpc_response resp; - size_t resp_size = sizeof(resp); - struct gsp_alloc_payload payload = { - .size = cpu_to_le64(0x100000), - .type = cpu_to_le32(GSP_MEM_VRAM), - }; - - int ret = mock_rpc_send(rpc, GSP_RPC_ALLOC, &payload, sizeof(payload), &resp, &resp_size); - TEST_ASSERT_EQ(ret, 0, "RPC send"); - - TEST_ASSERT_EQ(resp.status, 0, "RPC response status"); - TEST_ASSERT_EQ(resp.rpc_type, GSP_RPC_ALLOC, "RPC response type"); - TEST_ASSERT_EQ(resp.sequence, 1, "RPC response sequence"); - - /* Second call */ - ret = mock_rpc_send(rpc, GSP_RPC_PIN, &payload, sizeof(payload), &resp, &resp_size); - TEST_ASSERT_EQ(ret, 0, "RPC send second"); - TEST_ASSERT_EQ(resp.sequence, 2, "RPC response sequence 2"); - - mock_rpc_destroy(rpc); - return TEST_PASS; -} - -static int test_driver_vf_creation_logic(void) -{ - /* Simulate driver VF creation logic */ - struct mock_hw *hw = mock_hw_create(); - struct mock_rpc_client *rpc = mock_rpc_create(); - struct mock_vf *vfs[8] = {0}; - - /* Create VFs 1-4 */ - for (int i = 1; i <= 4; i++) { - vfs[i] = mock_vf_create(i, 0x10000000 * i, 0x100000, - 0x20000000 * i, 0x100000, - 0x30000000 * i, 0x10000); - TEST_ASSERT(vfs[i] != NULL, "VF creation in loop"); - TEST_ASSERT(vfs[i]->active, "VF active in loop"); - } - - /* Initialize BAR for each VF */ - for (int i = 1; i <= 4; i++) { - vfs[i]->bar_state.aperture_offset = vfs[i]->bar1_offset; - vfs[i]->bar_state.aperture_size = vfs[i]->bar1_size; - TEST_ASSERT_EQ(vfs[i]->bar_state.aperture_offset, 0x10000000 * i, "VF BAR offset"); - TEST_ASSERT_EQ(vfs[i]->bar_state.aperture_size, 0x100000, "VF BAR size"); - } - - /* Add WPR for each VF */ - for (int i = 1; i <= 4; i++) { - int ret = mock_vf_wpr_add(vfs[i], vfs[i]->pt_base, vfs[i]->pt_size, 3); - TEST_ASSERT_EQ(ret, 0, "VF WPR add in loop"); - } - - /* Simulate RPC calls for each VF */ - for (int i = 1; i <= 4; i++) { - struct gsp_rpc_response resp; - size_t resp_size = sizeof(resp); - struct gsp_alloc_payload payload = { - .size = cpu_to_le64(0x100000), - .type = cpu_to_le32(GSP_MEM_VRAM), - .vf_id = cpu_to_le32(i), - }; - int ret = mock_rpc_send(rpc, GSP_RPC_ALLOC, &payload, sizeof(payload), &resp, &resp_size); - TEST_ASSERT_EQ(ret, 0, "VF RPC alloc"); - TEST_ASSERT_EQ(resp.status, 0, "VF RPC response OK"); - } - - /* Cleanup */ - for (int i = 1; i <= 4; i++) { - mock_vf_destroy(vfs[i]); - } - mock_rpc_destroy(rpc); - mock_hw_destroy(hw); - - return TEST_PASS; -} - -static int test_migration_progress_tracking(void) -{ - struct { - u64 pages_transferred; - u64 bytes_transferred; - u64 dirty_pages; - u64 *page_list; - u32 page_count; - } progress = {0}; - - progress.page_count = 1000; - progress.page_list = kcalloc(progress.page_count, sizeof(u64), GFP_KERNEL); - TEST_ASSERT(progress.page_list != NULL, "Progress page list alloc"); - - /* Simulate transfer loop */ - for (int iter = 0; iter < 10; iter++) { - progress.pages_transferred += 100; - progress.bytes_transferred += 100 * 4096; - progress.dirty_pages = 50 - (iter * 5); - - TEST_ASSERT(progress.pages_transferred <= 1000, "Pages not exceeded"); - TEST_ASSERT(progress.bytes_transferred <= 1000 * 4096, "Bytes not exceeded"); - } - - TEST_ASSERT_EQ(progress.pages_transferred, 1000, "Final pages"); - TEST_ASSERT_EQ(progress.bytes_transferred, 1000 * 4096, "Final bytes"); - TEST_ASSERT_EQ(progress.dirty_pages, 0, "Final dirty pages"); - - kfree(progress.page_list); - return TEST_PASS; -} - -static int test_bar_state_machine(void) -{ - struct { - u64 aperture_offset; - u64 aperture_size; - bool force_access; - u32 force_vf; - } bar_state = {0}; - - /* Initial state */ - bar_state.aperture_offset = 0x10000000; - bar_state.aperture_size = 0x100000; - TEST_ASSERT_EQ(bar_state.aperture_offset, 0x10000000, "Initial aperture offset"); - TEST_ASSERT(!bar_state.force_access, "Force access initially false"); - - /* Enable force access */ - bar_state.force_access = true; - bar_state.force_vf = 1; - TEST_ASSERT(bar_state.force_access, "Force access enabled"); - TEST_ASSERT_EQ(bar_state.force_vf, 1, "Force VF set"); - - /* Disable force access */ - bar_state.force_access = false; - bar_state.force_vf = 0; - TEST_ASSERT(!bar_state.force_access, "Force access disabled"); - TEST_ASSERT_EQ(bar_state.force_vf, 0, "Force VF cleared"); - - return TEST_PASS; -} - -static int test_concurrent_vf_operations(void) -{ - struct mock_vf *vf1 = mock_vf_create(1, 0x10000000, 0x100000, 0x20000000, 0x100000, 0x30000000, 0x10000); - struct mock_vf *vf2 = mock_vf_create(2, 0x20000000, 0x100000, 0x40000000, 0x100000, 0x60000000, 0x10000); - struct mock_rpc_client *rpc = mock_rpc_create(); - - TEST_ASSERT(vf1 && vf2 && rpc, "Create two VFs and RPC"); - - /* Simulate concurrent operations */ - struct gsp_rpc_response resp; - size_t resp_size = sizeof(resp); - - /* VF1 alloc */ - struct gsp_alloc_payload payload1 = { - .size = cpu_to_le64(0x100000), - .type = cpu_to_le32(GSP_MEM_VRAM), - .vf_id = cpu_to_le32(1), - }; - int ret = mock_rpc_send(rpc, GSP_RPC_ALLOC, &payload1, sizeof(payload1), &resp, &resp_size); - TEST_ASSERT_EQ(ret, 0, "VF1 alloc"); - TEST_ASSERT_EQ(resp.status, 0, "VF1 alloc response"); - - /* VF2 alloc */ - struct gsp_alloc_payload payload2 = { - .size = cpu_to_le64(0x200000), - .type = cpu_to_le32(GSP_MEM_VRAM), - .vf_id = cpu_to_le32(2), - }; - ret = mock_rpc_send(rpc, GSP_RPC_ALLOC, &payload2, sizeof(payload2), &resp, &resp_size); - TEST_ASSERT_EQ(ret, 0, "VF2 alloc"); - TEST_ASSERT_EQ(resp.status, 0, "VF2 alloc response"); - - /* VF1 pin */ - struct gsp_pin_payload pin_payload = { - .handle = cpu_to_le64(0x1000), - .vf_id = cpu_to_le32(1), - }; - ret = mock_rpc_send(rpc, GSP_RPC_PIN, &pin_payload, sizeof(pin_payload), &resp, &resp_size); - TEST_ASSERT_EQ(ret, 0, "VF1 pin"); - - /* VF2 BAR trap */ - struct gsp_bar_trap_payload bar_payload = { - .vf_id = cpu_to_le32(2), - .bar_index = cpu_to_le32(1), - }; - ret = mock_rpc_send(rpc, GSP_RPC_BAR_TRAP, &bar_payload, sizeof(bar_payload), &resp, &resp_size); - TEST_ASSERT_EQ(ret, 0, "VF2 BAR trap"); - - /* Verify sequence numbers */ - TEST_ASSERT_EQ(resp.sequence, 4, "Sequence number 4"); - - mock_vf_destroy(vf1); - mock_vf_destroy(vf2); - mock_rpc_destroy(rpc); - - return TEST_PASS; -} - -/* ============================================================ - * Module Init/Exit - * ============================================================ */ - -static int __init gsp_mock_test_init(void) -{ - pr_info("========================================\n"); - pr_info("GSP vGPU-IO Mock Driver Test Suite\n"); - pr_info("========================================\n"); - - test_mock_hardware(); - test_mock_vf_lifecycle(); - test_mock_vf_wpr(); - test_mock_rpc_client(); - test_driver_vf_creation_logic(); - test_migration_progress_tracking(); - test_bar_state_machine(); - test_concurrent_vf_operations(); - - pr_info("========================================\n"); - pr_info("Mock Test Results: %d total, %d passed, %d failed\n", - test_count, pass_count, fail_count); - pr_info("========================================\n"); - - if (fail_count > 0) { - pr_err("MOCK TEST SUITE FAILED\n"); - return -EINVAL; - } - - pr_info("MOCK TEST SUITE PASSED\n"); - return 0; -} - -static void __exit gsp_mock_test_exit(void) -{ - pr_info("GSP vGPU-IO Mock Test Suite Exited\n"); -} - -module_init(gsp_mock_test_init); -module_exit(gsp_mock_test_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Open-IOV Project"); -MODULE_DESCRIPTION("GSP vGPU-IO Mock Driver Test"); -MODULE_VERSION("1.0");
\ No newline at end of file diff --git a/legacy-driver-guest/migration/gsp_migration.c b/legacy-driver-guest/migration/gsp_migration.c deleted file mode 100644 index 52d1931..0000000 --- a/legacy-driver-guest/migration/gsp_migration.c +++ /dev/null @@ -1,339 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - Live Migration - */ - -#include "gsp_core.h" -#include <linux/slab.h> -#include <linux/wait.h> -#include <linux/kthread.h> -#include <linux/delay.h> - -/* Forward declarations */ -static int gsp_migration_prepare(struct gsp_migration *mig); -static int gsp_migration_transfer_iter(struct gsp_migration *mig); -static int gsp_migration_commit(struct gsp_migration *mig); -static void gsp_migration_cleanup(struct gsp_migration *mig); - -/* Migration Thread */ -static int gsp_migration_thread(void *data) -{ - struct gsp_migration *mig = data; - int ret = 0; - - while (!kthread_should_stop() && !mig->cancelled) { - mutex_lock(&mig->lock); - - switch (mig->state) { - case GSP_MIG_S_PREPARE: - ret = gsp_migration_prepare(mig); - if (!ret) - mig->state = GSP_MIG_S_TRANSFER; - else - mig->state = GSP_MIG_S_FAILED; - break; - - case GSP_MIG_S_TRANSFER: - ret = gsp_migration_transfer_iter(mig); - if (ret > 0) { /* Transfer complete */ - mig->state = GSP_MIG_S_COMMIT; - } else if (ret < 0) { - mig->state = GSP_MIG_S_FAILED; - } - break; - - case GSP_MIG_S_COMMIT: - ret = gsp_migration_commit(mig); - if (!ret) - mig->state = GSP_MIG_S_CLEANUP; - else - mig->state = GSP_MIG_S_FAILED; - break; - - case GSP_MIG_S_CLEANUP: - gsp_migration_cleanup(mig); - mig->state = GSP_MIG_S_COMPLETED; - complete(&mig->comp); - mutex_unlock(&mig->lock); - return 0; - - case GSP_MIG_S_FAILED: - mig->error = ret; - complete(&mig->comp); - mutex_unlock(&mig->lock); - return ret; - - default: - break; - } - - mutex_unlock(&mig->lock); - - if (mig->state == GSP_MIG_S_TRANSFER) - msleep(10); /* Throttle transfer iterations */ - } - - return 0; -} - -/* Migration Query */ -static int gsp_migration_query(struct gsp_vf *vf, bool *migratable) -{ - struct gsp_migrate_payload payload = { - .phase = GSP_MIG_QUERY, - .subcmd = 0, - .src_vf = vf->id, - .dst_vf = 0, - }; - struct gsp_subcmd_desc desc; - size_t desc_size = sizeof(desc); - int ret; - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_MIGRATE, - &payload, sizeof(payload), &desc, &desc_size); - if (ret) - return ret; - - *migratable = (desc.subcmd_id != 0); - return 0; -} - -/* Phase 1: Prepare */ -static int gsp_migration_prepare(struct gsp_migration *mig) -{ - struct gsp_vf *vf = mig->vf; - struct gsp_migrate_payload payload = {0}; - struct gsp_subcmd_desc desc; - size_t desc_size = sizeof(desc); - int ret; - - /* Quiesce VF (subcmd 3 -> returns ID 0x10) */ - payload.phase = GSP_MIG_PREPARE; - payload.subcmd = 3; - payload.src_vf = vf->id; - payload.dst_vf = mig->dst_vf; - payload.flags = mig->flags; - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_MIGRATE, - &payload, sizeof(payload), &desc, &desc_size); - if (ret) - return ret; - - mig->token = desc.subcmd_id; - - /* Snapshot BAR state */ - ret = gsp_migration_bar_save(vf, mig->bar_state.buf, &mig->bar_state.size); - if (ret) - return ret; - - /* Snapshot WPR regions */ - /* TODO: WPR snapshot via migration RPC */ - - dev_info(vf->gsp->dev, "VF %u: Migration prepare done, token=0x%llx\n", - vf->id, mig->token); - - return 0; -} - -/* Phase 2: Transfer (Iterative) */ -static int gsp_migration_transfer_iter(struct gsp_migration *mig) -{ - struct gsp_vf *vf = mig->vf; - struct gsp_migrate_payload payload = {0}; - struct gsp_subcmd_desc desc; - size_t desc_size = sizeof(desc); - int ret; - - if (!mig->progress.page_list || mig->progress.page_count == 0) - return 1; /* Nothing to transfer */ - - payload.phase = GSP_MIG_TRANSFER; - payload.subcmd = 0; - payload.src_vf = vf->id; - payload.dst_vf = mig->dst_vf; - payload.data_ptr = (uint64_t)mig->progress.page_list; - payload.data_size = mig->progress.page_count * sizeof(uint64_t); - payload.token = mig->token; - payload.flags = mig->flags; - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_MIGRATE, - &payload, sizeof(payload), &desc, &desc_size); - if (ret) - return ret; - - /* Update progress from response */ - /* Note: Actual progress parsing depends on firmware response format */ - mig->progress.pages_transferred += 100; /* Placeholder */ - mig->progress.bytes_transferred += 100 * 4096; - - /* Check for dirty pages */ - if (mig->progress.dirty_pages > 0 && !(mig->flags & GSP_MIG_POSTCOPY)) - return 0; /* Continue iterating */ - - return 1; /* Transfer complete */ -} - -/* Phase 3: Commit */ -static int gsp_migration_commit(struct gsp_migration *mig) -{ - struct gsp_vf *vf = mig->vf; - struct gsp_migrate_payload payload = {0}; - struct gsp_subcmd_desc desc; - size_t desc_size = sizeof(desc); - int ret; - - /* Final dirty page transfer */ - if (mig->progress.dirty_pages > 0) { - payload.phase = GSP_MIG_TRANSFER; - payload.subcmd = 11; /* Dirty tracking */ - payload.src_vf = vf->id; - payload.dst_vf = mig->dst_vf; - payload.token = mig->token; - payload.flags = GSP_MIG_POSTCOPY; - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_MIGRATE, - &payload, sizeof(payload), &desc, &desc_size); - if (ret) - return ret; - } - - /* Commit (subcmd 12) */ - payload.phase = GSP_MIG_COMMIT; - payload.subcmd = 12; - payload.src_vf = vf->id; - payload.dst_vf = mig->dst_vf; - payload.token = mig->token; - payload.flags = mig->flags | GSP_MIG_VERIFY; - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_MIGRATE, - &payload, sizeof(payload), &desc, &desc_size); - if (ret) - return ret; - - /* Restore BAR on destination */ - ret = gsp_migration_bar_restore(vf, mig->bar_state.buf, mig->bar_state.size); - if (ret) - return ret; - - /* Restore WPR on destination */ - /* TODO: WPR restore */ - - dev_info(vf->gsp->dev, "VF %u: Migration commit done\n", vf->id); - - return 0; -} - -/* Phase 4: Cleanup */ -static void gsp_migration_cleanup(struct gsp_migration *mig) -{ - struct gsp_vf *vf = mig->vf; - - /* Free page list */ - kfree(mig->progress.page_list); - mig->progress.page_list = NULL; - mig->progress.page_count = 0; - - /* Free BAR state buffer */ - kfree(mig->bar_state.buf); - mig->bar_state.buf = NULL; - mig->bar_state.size = 0; - - dev_info(vf->gsp->dev, "VF %u: Migration cleanup done\n", vf->id); -} - -/* Public Migration API */ -int gsp_migration_start(struct gsp_vf *vf, uint64_t dst_vf) -{ - struct gsp_migration *mig; - bool migratable; - int ret; - - if (vf->migration) - return -EBUSY; - - /* Query migratability */ - ret = gsp_migration_query(vf, &migratable); - if (ret || !migratable) - return ret ? ret : -EINVAL; - - mig = kzalloc(sizeof(*mig), GFP_KERNEL); - if (!mig) - return -ENOMEM; - - mig->vf = vf; - mig->dst_vf = dst_vf; - mig->flags = GSP_MIG_LIVE | GSP_MIG_VERIFY; - mig->state = GSP_MIG_S_PREPARE; - mutex_init(&mig->lock); - init_completion(&mig->comp); - - /* Allocate page list (placeholder) */ - mig->progress.page_count = vf->pt_size / 4096; - mig->progress.page_list = kcalloc(mig->progress.page_count, sizeof(uint64_t), GFP_KERNEL); - if (!mig->progress.page_list) { - kfree(mig); - return -ENOMEM; - } - - /* Allocate BAR state buffer */ - mig->bar_state.buf = kmalloc(65536, GFP_KERNEL); /* 64KB max */ - if (!mig->bar_state.buf) { - kfree(mig->progress.page_list); - kfree(mig); - return -ENOMEM; - } - - vf->migration = mig; - - /* Start migration thread */ - mig->thread = kthread_run(gsp_migration_thread, mig, "gsp-mig-%u", vf->id); - if (IS_ERR(mig->thread)) { - ret = PTR_ERR(mig->thread); - mig->thread = NULL; - goto err_free; - } - - return 0; - -err_free: - kfree(mig->progress.page_list); - kfree(mig->bar_state.buf); - kfree(mig); - vf->migration = NULL; - return ret; -} - -void gsp_migration_cancel(struct gsp_migration *mig) -{ - if (!mig) - return; - - mutex_lock(&mig->lock); - mig->cancelled = true; - mig->state = GSP_MIG_S_FAILED; - mutex_unlock(&mig->lock); - - if (mig->thread) - kthread_stop(mig->thread); - - wait_for_completion(&mig->comp); - - gsp_migration_cleanup(mig); - kfree(mig); -} - -int gsp_migration_status(struct gsp_migration *mig) -{ - if (!mig) - return -EINVAL; - - mutex_lock(&mig->lock); - int state = mig->state; - int error = mig->error; - mutex_unlock(&mig->lock); - - if (state == GSP_MIG_S_FAILED) - return error; - - return state; -}
\ No newline at end of file diff --git a/legacy-driver-guest/rpc/gsp_rpc.c b/legacy-driver-guest/rpc/gsp_rpc.c deleted file mode 100644 index 6bdcdb2..0000000 --- a/legacy-driver-guest/rpc/gsp_rpc.c +++ /dev/null @@ -1,331 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - RPC Client Implementation - */ - -#include "gsp_core.h" -#include <linux/slab.h> -#include <linux/wait.h> -#include <linux/delay.h> -#include <linux/kthread.h> - -/* Ring Buffer Operations */ -static int gsp_ring_init(struct gsp_msg_ring *ring, void *base, size_t size) -{ - ring->base = base; - ring->size = size; - ring->head = 0; - ring->tail = 0; - spin_lock_init(&ring->lock); - return 0; -} - -static bool gsp_ring_empty(struct gsp_msg_ring *ring) -{ - return ring->head == ring->tail; -} - -static bool gsp_ring_full(struct gsp_msg_ring *ring) -{ - return ((ring->head + 1) % (ring->size / GSP_MSG_MAX_SIZE)) == ring->tail; -} - -static int gsp_ring_write(struct gsp_msg_ring *ring, struct gsp_rpc_message *msg, size_t len) -{ - unsigned long flags; - uint32_t next_head; - void *dst; - - if (len > GSP_MSG_MAX_SIZE) - return -EINVAL; - - spin_lock_irqsave(&ring->lock, flags); - - if (gsp_ring_full(ring)) { - spin_unlock_irqrestore(&ring->lock, flags); - return -EBUSY; - } - - dst = ring->base + (ring->head * GSP_MSG_MAX_SIZE); - memcpy(dst, msg, len); - - next_head = (ring->head + 1) % (ring->size / GSP_MSG_MAX_SIZE); - ring->head = next_head; - - spin_unlock_irqrestore(&ring->lock, flags); - return 0; -} - -static int gsp_ring_read(struct gsp_msg_ring *ring, struct gsp_rpc_message *msg) -{ - unsigned long flags; - void *src; - - spin_lock_irqsave(&ring->lock, flags); - - if (gsp_ring_empty(ring)) { - spin_unlock_irqrestore(&ring->lock, flags); - return 0; - } - - src = ring->base + (ring->tail * GSP_MSG_MAX_SIZE); - memcpy(msg, src, GSP_MSG_MAX_SIZE); - - ring->tail = (ring->tail + 1) % (ring->size / GSP_MSG_MAX_SIZE); - - spin_unlock_irqrestore(&ring->lock, flags); - return 1; -} - -/* RPC Client Initialization */ -struct gsp_rpc_client *gsp_rpc_client_init(struct gsp_device *gsp) -{ - struct gsp_rpc_client *rpc; - void *ring_mem; - - rpc = kzalloc(sizeof(*rpc), GFP_KERNEL); - if (!rpc) - return ERR_PTR(-ENOMEM); - - rpc->gsp = gsp; - mutex_init(&rpc->lock); - atomic_set(&rpc->seq, 0); - init_waitqueue_head(&rpc->wq); - - /* Allocate shared memory for message rings (2 pages each) */ - ring_mem = dma_alloc_coherent(gsp->dev, 8 * PAGE_SIZE, - &rpc->tx_ring_dma, GFP_KERNEL); - if (!ring_mem) { - kfree(rpc); - return ERR_PTR(-ENOMEM); - } - - rpc->tx_ring = kzalloc(sizeof(*rpc->tx_ring), GFP_KERNEL); - rpc->rx_ring = kzalloc(sizeof(*rpc->rx_ring), GFP_KERNEL); - if (!rpc->tx_ring || !rpc->rx_ring) { - dma_free_coherent(gsp->dev, 8 * PAGE_SIZE, ring_mem, rpc->tx_ring_dma); - kfree(rpc->tx_ring); - kfree(rpc->rx_ring); - kfree(rpc); - return ERR_PTR(-ENOMEM); - } - - gsp_ring_init(rpc->tx_ring, ring_mem, 4 * PAGE_SIZE); - gsp_ring_init(rpc->rx_ring, ring_mem + 4 * PAGE_SIZE, 4 * PAGE_SIZE); - - /* Map rings to GSP via queue head registers (BAR0) */ - writel(rpc->tx_ring_dma, gsp->bar0 + GSP_BAR0_QUEUE_HEAD(0)); - writel(rpc->tx_ring_dma >> 32, gsp->bar0 + GSP_BAR0_QUEUE_HEAD(0) + 4); - writel(rpc->rx_ring_dma, gsp->bar0 + GSP_BAR0_QUEUE_HEAD(1)); - writel(rpc->rx_ring_dma >> 32, gsp->bar0 + GSP_BAR0_QUEUE_HEAD(1) + 4); - - /* Allocate response buffers */ - for (int i = 0; i < GSP_MAX_PENDING; i++) { - rpc->resp_buf[i] = kzalloc(GSP_MSG_MAX_SIZE, GFP_KERNEL); - if (!rpc->resp_buf[i]) { - /* Cleanup on failure */ - for (int j = 0; j < i; j++) - kfree(rpc->resp_buf[j]); - gsp_rpc_client_fini(rpc); - return ERR_PTR(-ENOMEM); - } - } - - dev_info(gsp->dev, "RPC client initialized\n"); - return rpc; -} - -void gsp_rpc_client_fini(struct gsp_rpc_client *rpc) -{ - if (!rpc) - return; - - for (int i = 0; i < GSP_MAX_PENDING; i++) - kfree(rpc->resp_buf[i]); - - if (rpc->tx_ring) { - dma_free_coherent(rpc->gsp->dev, 8 * PAGE_SIZE, - rpc->tx_ring->base, rpc->tx_ring_dma); - kfree(rpc->tx_ring); - } - kfree(rpc->rx_ring); - kfree(rpc); -} - -/* Synchronous RPC Send */ -int gsp_rpc_send_sync(struct gsp_rpc_client *rpc, - enum gsp_rpc_type type, - void *payload, size_t payload_size, - void *response, size_t *response_size) -{ - struct gsp_rpc_message msg = {0}; - struct completion done; - uint32_t seq; - int ret; - - if (payload_size > GSP_MSG_MAX_SIZE - sizeof(struct gsp_rpc_header)) - return -EINVAL; - - seq = atomic_inc_return(&rpc->seq); - init_completion(&done); - - msg.hdr.magic = 0x47535052; /* "GSPR" */ - msg.hdr.version = 1; - msg.hdr.rpc_type = type; - msg.hdr.sequence = seq; - msg.hdr.timestamp_ns = ktime_get_ns(); - msg.hdr.payload_size = payload_size; - msg.hdr.flags = GSP_MSG_SYNC; - msg.hdr.correlation_id = seq; - - if (payload && payload_size > 0) - memcpy(msg.payload, payload, payload_size); - - mutex_lock(&rpc->lock); - - rpc->pending[seq % GSP_MAX_PENDING] = &done; - - ret = gsp_ring_write(rpc->tx_ring, &msg, GSP_MSG_MAX_SIZE); - if (ret) { - rpc->pending[seq % GSP_MAX_PENDING] = NULL; - mutex_unlock(&rpc->lock); - return ret; - } - - /* Ring doorbell - write to queue head to signal GSP */ - writel(1, rpc->gsp->bar0 + GSP_BAR0_QUEUE_HEAD(0)); - - mutex_unlock(&rpc->lock); - - /* Wait for completion (5 second timeout) */ - if (!wait_for_completion_timeout(&done, msecs_to_jiffies(5000))) { - mutex_lock(&rpc->lock); - rpc->pending[seq % GSP_MAX_PENDING] = NULL; - mutex_unlock(&rpc->lock); - atomic64_inc(&rpc->gsp->rpc_errors); - return -ETIMEDOUT; - } - - /* Get response */ - struct gsp_rpc_response *resp = rpc->resp_buf[seq % GSP_MAX_PENDING]; - - atomic64_inc(&rpc->gsp->rpc_total); - - if (resp->status != 0) { - atomic64_inc(&rpc->gsp->rpc_errors); - return gsp_errno_to_errno(resp->status); - } - - if (response && response_size) { - size_t copy_size = min(*response_size, (size_t)resp->payload_size); - memcpy(response, resp->payload, copy_size); - *response_size = copy_size; - } - - return 0; -} - -/* Async RPC Send */ -int gsp_rpc_send_async(struct gsp_rpc_client *rpc, - enum gsp_rpc_type type, - void *payload, size_t payload_size, - void (*callback)(struct gsp_rpc_client *, - struct gsp_rpc_response *, - void *), - void *ctx) -{ - struct gsp_rpc_message msg = {0}; - uint32_t seq; - int ret; - - if (payload_size > GSP_MSG_MAX_SIZE - sizeof(struct gsp_rpc_header)) - return -EINVAL; - - seq = atomic_inc_return(&rpc->seq); - - msg.hdr.magic = 0x47535052; - msg.hdr.version = 1; - msg.hdr.rpc_type = type; - msg.hdr.sequence = seq; - msg.hdr.timestamp_ns = ktime_get_ns(); - msg.hdr.payload_size = payload_size; - msg.hdr.flags = GSP_MSG_ASYNC; - msg.hdr.correlation_id = (uint64_t)callback | ((uint64_t)ctx << 32); - - if (payload && payload_size > 0) - memcpy(msg.payload, payload, payload_size); - - mutex_lock(&rpc->lock); - ret = gsp_ring_write(rpc->tx_ring, &msg, GSP_MSG_MAX_SIZE); - if (!ret) - writel(1, rpc->gsp->bar0 + GSP_BAR0_QUEUE_HEAD(0)); - mutex_unlock(&rpc->lock); - - return ret; -} - -/* ISR - Handle Completions */ -irqreturn_t gsp_isr(int irq, void *data) -{ - struct gsp_device *gsp = data; - struct gsp_rpc_message msg; - int handled = 0; - - while (gsp_ring_read(gsp->rpc->rx_ring, &msg)) { - handled = 1; - - if (msg.hdr.flags & GSP_MSG_SYNC) { - uint32_t seq = msg.hdr.sequence; - struct completion *done = gsp->rpc->pending[seq % GSP_MAX_PENDING]; - struct gsp_rpc_response *resp = gsp->rpc->resp_buf[seq % GSP_MAX_PENDING]; - - if (done && resp) { - resp->status = ((struct gsp_rpc_response *)msg.payload)->status; - resp->payload_size = msg.hdr.payload_size; - memcpy(resp->payload, ((struct gsp_rpc_response *)msg.payload)->payload, - msg.hdr.payload_size); - complete(done); - } - gsp->rpc->pending[seq % GSP_MAX_PENDING] = NULL; - } else { - /* Async notification - handle via callback */ - gsp_handle_notification(gsp, &msg); - } - } - - return handled ? IRQ_HANDLED : IRQ_NONE; -} - -/* Notification Handler */ -void gsp_handle_notification(struct gsp_device *gsp, struct gsp_rpc_message *msg) -{ - switch (msg->hdr.rpc_type) { - case GSP_RPC_NOTIFY: - /* Handle VF notifications (WPR, migration, etc.) */ - break; - case GSP_RPC_BAR_TRAP: - atomic64_inc(&gsp->bar_traps); - break; - default: - dev_dbg(gsp->dev, "Unhandled notification type 0x%02x\n", msg->hdr.rpc_type); - } -} - -/* Error Code Translation */ -int gsp_errno_to_errno(int gsp_err) -{ - switch (gsp_err) { - case GSP_OK: return 0; - case GSP_EPERM: return -EPERM; - case GSP_ENOENT: return -ENOENT; - case GSP_EINVAL: return -EINVAL; - case GSP_ENODEV: return -ENODEV; - case GSP_ENOMEM: return -ENOMEM; - case GSP_EBUSY: return -EBUSY; - case GSP_ENOSPC: return -ENOSPC; - case GSP_ETIMEDOUT: return -ETIMEDOUT; - case GSP_EOVERFLOW: return -EOVERFLOW; - case GSP_EDEV: return -EIO; - default: return -EIO; - } -}
\ No newline at end of file diff --git a/legacy-driver-guest/vf/gsp_vf.c b/legacy-driver-guest/vf/gsp_vf.c deleted file mode 100644 index 951c84d..0000000 --- a/legacy-driver-guest/vf/gsp_vf.c +++ /dev/null @@ -1,312 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - VF Management - */ - -#include "gsp_core.h" -#include <linux/slab.h> -#include <linux/idr.h> -#include <linux/list.h> - -/* VF Reference Counting */ -static void gsp_vf_release(struct kref *ref) -{ - struct gsp_vf *vf = container_of(ref, struct gsp_vf, ref); - kfree(vf); -} - -struct gsp_vf *gsp_vf_get(struct gsp_device *gsp, uint32_t id) -{ - struct gsp_vf *vf; - - mutex_lock(&gsp->vf_lock); - vf = idr_find(&gsp->vf_idr, id); - if (vf && vf->active) - kref_get(&vf->ref); - else - vf = NULL; - mutex_unlock(&gsp->vf_lock); - - return vf; -} - -void gsp_vf_put(struct gsp_vf *vf) -{ - if (vf) - kref_put(&vf->ref, gsp_vf_release); -} - -/* VF Creation */ -int gsp_vf_create(struct gsp_device *gsp, const struct gsp_vf_config *config) -{ - struct gsp_vf *vf; - int ret, id; - - if (!config || config->id == 0 || config->id > gsp->max_vfs) - return -EINVAL; - - vf = kzalloc(sizeof(*vf), GFP_KERNEL); - if (!vf) - return -ENOMEM; - - vf->gsp = gsp; - vf->id = config->id; - kref_init(&vf->ref); - mutex_init(&vf->lock); - mutex_init(&vf->wpr_lock); - INIT_LIST_HEAD(&vf->wpr_list); - INIT_LIST_HEAD(&vf->list); - atomic_set(&vf->refcount, 1); - - /* Copy configuration */ - 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; - - /* Allocate VF ID */ - mutex_lock(&gsp->vf_lock); - id = idr_alloc(&gsp->vf_idr, vf, config->id, config->id + 1, GFP_KERNEL); - if (id < 0) { - ret = id; - mutex_unlock(&gsp->vf_lock); - goto err_free; - } - - list_add(&vf->list, &gsp->vf_list); - vf->active = true; - vf->state = GSP_VF_ACTIVE; - mutex_unlock(&gsp->vf_lock); - - /* Initialize subsystems */ - ret = gsp_vf_wpr_init(vf); - if (ret) { - dev_err(gsp->dev, "VF %u: WPR init failed: %d\n", vf->id, ret); - goto err_wpr; - } - - ret = gsp_vf_bar_init(vf); - if (ret) { - dev_err(gsp->dev, "VF %u: BAR init failed: %d\n", vf->id, ret); - goto err_bar; - } - - dev_info(gsp->dev, "VF %u created (bar1=0x%llx-0x%llx, pt=0x%llx-0x%llx)\n", - vf->id, vf->bar1_offset, vf->bar1_offset + vf->bar1_size, - vf->pt_base, vf->pt_base + vf->pt_size); - - return 0; - -err_bar: - gsp_vf_wpr_fini(vf); -err_wpr: - mutex_lock(&gsp->vf_lock); - list_del(&vf->list); - idr_remove(&gsp->vf_idr, vf->id); - vf->active = false; - mutex_unlock(&gsp->vf_lock); -err_free: - kfree(vf); - return ret; -} - -/* VF Destruction */ -void gsp_vf_destroy(struct gsp_vf *vf) -{ - struct gsp_device *gsp = vf->gsp; - uint32_t id = vf->id; - - if (!vf->active) - return; - - /* Cancel any ongoing migration */ - mutex_lock(&vf->lock); - if (vf->migration) { - gsp_migration_cancel(vf->migration); - vf->migration = NULL; - } - vf->active = false; - vf->state = GSP_VF_DESTROYING; - mutex_unlock(&vf->lock); - - /* Remove from device lists */ - mutex_lock(&gsp->vf_lock); - list_del(&vf->list); - idr_remove(&gsp->vf_idr, id); - mutex_unlock(&gsp->vf_lock); - - /* Cleanup subsystems */ - gsp_vf_bar_fini(vf); - gsp_vf_wpr_fini(vf); - - dev_info(gsp->dev, "VF %u destroyed\n", id); - - gsp_vf_put(vf); -} - -/* Memory Allocation */ -int gsp_vf_mem_alloc(struct gsp_vf *vf, uint64_t size, uint32_t flags, - uint64_t *handle, uint64_t *va) -{ - struct gsp_alloc_payload payload = { - .size = size, - .type = flags & 0x3, /* Low bits: mem type */ - .alignment = 0x1000, - .va_hint = 0, - .flags = flags >> 2, - .pid = current->pid, - .vf_id = vf->id, - }; - struct gsp_alloc_response resp; - size_t resp_size = sizeof(resp); - int ret; - - if (!handle || !va) - return -EINVAL; - - /* In emulation mode, handle locally */ - if (emulation_mode) { - static uint64_t next_handle = 0x1000; - static uint64_t next_va = 0x100000000ULL; /* 4GB base */ - - *handle = next_handle++; - *va = next_va; - next_va += (size + 0xFFF) & ~0xFFF; /* Align to 4KB */ - - dev_dbg(vf->gsp->dev, "VF %u: alloc handle=0x%llx va=0x%llx size=0x%llx (emulation)\n", - vf->id, *handle, *va, size); - - return 0; - } - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_ALLOC, - &payload, sizeof(payload), - &resp, &resp_size); - if (ret) - return ret; - - *handle = resp.handle; - *va = resp.va; - - dev_dbg(vf->gsp->dev, "VF %u: alloc handle=0x%llx va=0x%llx size=0x%llx\n", - vf->id, *handle, *va, size); - - return 0; -} - -int gsp_vf_mem_free(struct gsp_vf *vf, uint64_t handle) -{ - /* FREE uses primary dispatcher sub-command */ - struct gsp_subcmd_desc desc; - size_t desc_size = sizeof(desc); - int ret; - - /* Subcmd for FREE: need to determine which subcmd corresponds to FREE */ - /* For now, use a generic FREE RPC if implemented */ - - /* Placeholder - actual implementation depends on FREE subcmd mapping */ - dev_dbg(vf->gsp->dev, "VF %u: free handle=0x%llx\n", vf->id, handle); - - return 0; -} - -/* Memory Pinning */ -int gsp_vf_mem_pin(struct gsp_vf *vf, uint64_t handle, - uint64_t offset, uint64_t size, - uint64_t *dma_addr) -{ - struct gsp_pin_payload payload = { - .handle = handle, - .offset = offset, - .size = size, - .vf_id = vf->id, - .flags = GSP_PIN_READ | GSP_PIN_WRITE, - }; - struct gsp_pin_response resp; - size_t resp_size = sizeof(resp); - int ret; - - if (!dma_addr) - return -EINVAL; - - /* In emulation mode, handle locally */ - if (emulation_mode) { - static uint64_t next_dma = 0x200000000ULL; /* 8GB base */ - *dma_addr = next_dma; - next_dma += (size + 0xFFF) & ~0xFFF; - - dev_dbg(vf->gsp->dev, "VF %u: pin handle=0x%llx offset=0x%llx size=0x%llx -> dma=0x%llx (emulation)\n", - vf->id, handle, offset, size, *dma_addr); - - return 0; - } - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_PIN, - &payload, sizeof(payload), - &resp, &resp_size); - if (ret) - return ret; - - *dma_addr = resp.dma_addr; - - dev_dbg(vf->gsp->dev, "VF %u: pin handle=0x%llx offset=0x%llx size=0x%llx -> dma=0x%llx\n", - vf->id, handle, offset, size, *dma_addr); - - return 0; -} - -int gsp_vf_mem_unpin(struct gsp_vf *vf, uint64_t handle) -{ - dev_dbg(vf->gsp->dev, "VF %u: unpin handle=0x%llx\n", vf->id, handle); - return 0; -} - -/* Memory Mapping */ -int gsp_vf_mem_map(struct gsp_vf *vf, uint64_t handle, uint64_t gpu_va, - uint64_t size, uint32_t prot, uint32_t flags, - uint64_t offset, uint64_t *mapped_va) -{ - /* In emulation mode, just return the requested VA */ - if (emulation_mode) { - if (mapped_va) - *mapped_va = gpu_va; - - dev_dbg(vf->gsp->dev, "VF %u: map handle=0x%llx gpu_va=0x%llx size=0x%llx -> mapped_va=0x%llx (emulation)\n", - vf->id, handle, gpu_va, size, gpu_va); - - return 0; - } - - /* TODO: Implement GSP RPC for MAP */ - dev_dbg(vf->gsp->dev, "VF %u: map handle=0x%llx gpu_va=0x%llx size=0x%llx\n", - vf->id, handle, gpu_va, size); - - if (mapped_va) - *mapped_va = gpu_va; - - return 0; -} - -int gsp_vf_mem_unmap(struct gsp_vf *vf, uint64_t handle, uint64_t gpu_va, uint64_t size) -{ - dev_dbg(vf->gsp->dev, "VF %u: unmap handle=0x%llx gpu_va=0x%llx size=0x%llx\n", - vf->id, handle, gpu_va, size); - return 0; -} - -/* Scheduling */ -int gsp_vf_schedule(struct gsp_vf *vf, uint32_t priority, uint64_t time_slice_ns) -{ - /* Use primary dispatcher SCHEDULE subcmd or secondary dispatcher */ - dev_dbg(vf->gsp->dev, "VF %u: schedule prio=%u slice=%llu ns\n", - vf->id, priority, time_slice_ns); - return 0; -} - -int gsp_vf_yield(struct gsp_vf *vf) -{ - dev_dbg(vf->gsp->dev, "VF %u: yield\n", vf->id); - return 0; -}
\ No newline at end of file diff --git a/legacy-driver-guest/wpr/gsp_wpr.c b/legacy-driver-guest/wpr/gsp_wpr.c deleted file mode 100644 index 91c5550..0000000 --- a/legacy-driver-guest/wpr/gsp_wpr.c +++ /dev/null @@ -1,285 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * GSP vGPU-IO Driver - WPR (Write/Read Protect Region) Management - */ - -#include "gsp_core.h" -#include <linux/slab.h> -#include <linux/list.h> - -/* WPR Payload (for RPC) */ -struct gsp_wpr_payload { - uint32_t vf_id; - uint32_t op; /* 0=protect_write, 1=protect_read, 2=unprotect */ - uint64_t base; - uint64_t size; - uint32_t flags; - uint64_t timeout_ns; -} __attribute__((packed)); - -struct gsp_wpr_response { - int64_t status; -} __attribute__((packed)); - -/* WPR Initialization */ -int gsp_vf_wpr_init(struct gsp_vf *vf) -{ - INIT_LIST_HEAD(&vf->wpr_list); - mutex_init(&vf->wpr_lock); - return 0; -} - -void gsp_vf_wpr_fini(struct gsp_vf *vf) -{ - struct gsp_wpr_region *rgn, *tmp; - - mutex_lock(&vf->wpr_lock); - list_for_each_entry_safe(rgn, tmp, &vf->wpr_list, list) { - list_del(&rgn->list); - kfree(rgn); - } - mutex_unlock(&vf->wpr_lock); -} - -/* Protect Region (Write) */ -int gsp_vf_wpr_protect_write(struct gsp_vf *vf, uint64_t base, uint64_t size) -{ - return gsp_vf_wpr_protect(vf, base, size, GSP_WPR_WRITE); -} - -/* Protect Region (Read) */ -int gsp_vf_wpr_protect_read(struct gsp_vf *vf, uint64_t base, uint64_t size) -{ - return gsp_vf_wpr_protect(vf, base, size, GSP_WPR_READ); -} - -/* Generic Protect */ -int gsp_vf_wpr_protect(struct gsp_vf *vf, uint64_t base, uint64_t size, uint32_t flags) -{ - struct gsp_wpr_payload payload = { - .vf_id = vf->id, - .op = (flags & GSP_WPR_READ) ? 1 : 0, - .base = base, - .size = size, - .flags = flags, - .timeout_ns = 10000000, /* 10ms default */ - }; - struct gsp_wpr_response resp; - size_t resp_size = sizeof(resp); - struct gsp_wpr_region *rgn; - int ret; - - /* Validate alignment */ - if (base & 0xFFF || size & 0xFFF) - return -EINVAL; - - rgn = kzalloc(sizeof(*rgn), GFP_KERNEL); - if (!rgn) - return -ENOMEM; - - rgn->base = base; - rgn->size = size; - rgn->flags = flags; - rgn->vf_id = vf->id; - rgn->timeout_ns = payload.timeout_ns; - - /* In emulation mode, handle locally */ - if (emulation_mode) { - mutex_lock(&vf->wpr_lock); - list_add(&rgn->list, &vf->wpr_list); - mutex_unlock(&vf->wpr_lock); - - dev_dbg(vf->gsp->dev, "VF %u: WPR protect [0x%llx, 0x%llx) flags=0x%x (emulation)\n", - vf->id, base, base + size, flags); - - return 0; - } - - /* Send to GSP WPR handler (0x04F00B0C/0x04F00C78) */ - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_MAP, /* Uses MAP RPC for WPR */ - &payload, sizeof(payload), &resp, &resp_size); - if (ret) { - kfree(rgn); - return ret; - } - - if (resp.status != 0) { - kfree(rgn); - return gsp_errno_to_errno(resp.status); - } - - mutex_lock(&vf->wpr_lock); - list_add(&rgn->list, &vf->wpr_list); - mutex_unlock(&vf->wpr_lock); - - dev_dbg(vf->gsp->dev, "VF %u: WPR protect [0x%llx, 0x%llx) flags=0x%x\n", - vf->id, base, base + size, flags); - - return 0; -} - -/* Unprotect Region */ -int gsp_vf_wpr_unprotect(struct gsp_vf *vf, uint64_t base) -{ - struct gsp_wpr_payload payload = { - .vf_id = vf->id, - .op = 2, /* unprotect */ - .base = base, - .size = 0, - .flags = 0, - }; - struct gsp_wpr_response resp; - size_t resp_size = sizeof(resp); - struct gsp_wpr_region *rgn, *tmp; - bool found = false; - int ret; - - /* In emulation mode, handle locally */ - if (emulation_mode) { - mutex_lock(&vf->wpr_lock); - list_for_each_entry_safe(rgn, tmp, &vf->wpr_list, list) { - if (rgn->base == base) { - list_del(&rgn->list); - kfree(rgn); - found = true; - break; - } - } - mutex_unlock(&vf->wpr_lock); - - dev_dbg(vf->gsp->dev, "VF %u: WPR unprotect 0x%llx (emulation)\n", vf->id, base); - - return found ? 0 : -ENOENT; - } - - ret = gsp_rpc_send_sync(vf->gsp->rpc, GSP_RPC_UNMAP, /* Uses UNMAP for WPR */ - &payload, sizeof(payload), &resp, &resp_size); - if (ret) - return ret; - - if (resp.status != 0) - return gsp_errno_to_errno(resp.status); - - mutex_lock(&vf->wpr_lock); - list_for_each_entry_safe(rgn, tmp, &vf->wpr_list, list) { - if (rgn->base == base) { - list_del(&rgn->list); - kfree(rgn); - found = true; - break; - } - } - mutex_unlock(&vf->wpr_lock); - - if (!found) - return -ENOENT; - - dev_dbg(vf->gsp->dev, "VF %u: WPR unprotect 0x%llx\n", vf->id, base); - - return 0; -} - -/* Set Timeout */ -int gsp_vf_wpr_set_timeout(struct gsp_vf *vf, uint64_t timeout_ns) -{ - /* Update timeout for all WPR regions */ - struct gsp_wpr_region *rgn; - - mutex_lock(&vf->wpr_lock); - list_for_each_entry(rgn, &vf->wpr_list, list) { - rgn->timeout_ns = timeout_ns; - } - mutex_unlock(&vf->wpr_lock); - - return 0; -} - -/* Register Completion Callback */ -int gsp_vf_wpr_register_callback(struct gsp_vf *vf, enum gsp_wpr_event type, - void (*cb)(struct gsp_vf *, uint64_t, uint32_t), - void *ctx) -{ - struct gsp_wpr_region *rgn; - - mutex_lock(&vf->wpr_lock); - list_for_each_entry(rgn, &vf->wpr_list, list) { - switch (type) { - case GSP_WPR_WRITE_COMPLETE: - case GSP_WPR_WRITE_TIMEOUT: - rgn->completion_cb = cb; - break; - case GSP_WPR_READ_COMPLETE: - case GSP_WPR_READ_TIMEOUT: - rgn->timeout_cb = cb; - break; - } - } - mutex_unlock(&vf->wpr_lock); - - return 0; -} - -/* WPR Event Handler (called from notification) */ -void gsp_wpr_handle_event(struct gsp_device *gsp, struct gsp_rpc_message *msg) -{ - struct gsp_rpc_response *resp = (struct gsp_rpc_response *)msg->payload; - uint32_t event_type = resp->payload[0]; - uint32_t vf_id = resp->payload[1]; - uint64_t address = *(uint64_t *)&resp->payload[2]; - struct gsp_vf *vf; - struct gsp_wpr_region *rgn; - - vf = gsp_vf_get(gsp, vf_id); - if (!vf) - return; - - atomic64_inc(&gsp->wpr_events); - - mutex_lock(&vf->wpr_lock); - list_for_each_entry(rgn, &vf->wpr_list, list) { - if (address >= rgn->base && address < rgn->base + rgn->size) { - switch (event_type) { - case GSP_WPR_WRITE_COMPLETE: - case GSP_WPR_READ_COMPLETE: - if (rgn->completion_cb) - rgn->completion_cb(vf, address, event_type); - break; - case GSP_WPR_WRITE_TIMEOUT: - case GSP_WPR_READ_TIMEOUT: - if (rgn->timeout_cb) - rgn->timeout_cb(vf, address, event_type); - break; - } - break; - } - } - mutex_unlock(&vf->wpr_lock); - - gsp_vf_put(vf); -} - -/* Default Completion Callback */ -void gsp_wpr_default_complete_cb(struct gsp_vf *vf, uint64_t addr, uint32_t type) -{ - dev_dbg(vf->gsp->dev, "VF %u: WPR %s complete at 0x%llx\n", - vf->id, type == GSP_WPR_WRITE_COMPLETE ? "write" : "read", addr); - - /* If this was a page table write, invalidate TLB */ - if (addr >= vf->pt_base && addr < vf->pt_base + vf->pt_size) { - /* TODO: TLB invalidate */ - } -} - -/* Default Timeout Callback */ -void gsp_wpr_default_timeout_cb(struct gsp_vf *vf, uint64_t addr, uint32_t type) -{ - dev_warn(vf->gsp->dev, "VF %u: WPR %s timeout at 0x%llx\n", - vf->id, type == GSP_WPR_WRITE_TIMEOUT ? "write" : "read", addr); - - /* Throttle or reset VF */ - if (type == GSP_WPR_WRITE_TIMEOUT) { - /* TODO: VF throttle */ - } else { - /* TODO: VF reset */ - } -}
\ No newline at end of file diff --git a/patches/nvidia/0001-Build-fixes-and-vGPU-VFIO-interface-integration.patch b/patches/nvidia/0001-Build-fixes-and-vGPU-VFIO-interface-integration.patch deleted file mode 100644 index 1c7c286..0000000 --- a/patches/nvidia/0001-Build-fixes-and-vGPU-VFIO-interface-integration.patch +++ /dev/null @@ -1,484 +0,0 @@ -From 1fe277fb1c48a7ba73fea588102062de281b610a Mon Sep 17 00:00:00 2001 -From: Arthur Hanson Rasmusson <arthur@vgpu.io> -Date: Mon, 21 Sep 2026 04:42:04 -0400 -Subject: [PATCH] Build fixes and vGPU VFIO interface integration - ---- - kernel-open/Kbuild | 8 +- - kernel-open/Makefile | 9 +- - kernel-open/Module.symvers.open-iov | 92 +++++++++++++++++++ - kernel-open/common/inc/nv-linux.h | 1 + - .../inc/nv-vgpu-vfio-interface-nvidia.h | 71 ++++++++++++++ - .../common/inc/nv-vgpu-vfio-interface.h | 86 +++++++++++++++++ - kernel-open/nvidia/nv-pci.c | 2 +- - kernel-open/nvidia/nv.c | 17 +++- - kernel-open/nvidia/os-interface.c | 6 ++ - src/common/inc/nvUnixVersion.h | 2 +- - src/common/shared/inc/g_vgpu_chip_flags.h | 1 + - version.mk | 4 +- - 12 files changed, 290 insertions(+), 9 deletions(-) - create mode 100644 kernel-open/Module.symvers.open-iov - create mode 100644 kernel-open/common/inc/nv-vgpu-vfio-interface-nvidia.h - create mode 100644 kernel-open/common/inc/nv-vgpu-vfio-interface.h - -diff --git a/kernel-open/Kbuild b/kernel-open/Kbuild -index d1811c6..b56f1c0 100644 ---- a/kernel-open/Kbuild -+++ b/kernel-open/Kbuild -@@ -79,7 +79,7 @@ ccflags-y += -I$(src)/common/inc - ccflags-y += -I$(src) - ccflags-y += -Wall $(DEFINES) $(INCLUDES) -Wno-cast-qual -Wno-format-extra-args - ccflags-y += -D__KERNEL__ -DMODULE -DNVRM --ccflags-y += -DNV_VERSION_STRING=\"610.57.04\" -+ccflags-y += -DNV_VERSION_STRING=\"570.144\" - - # Include and link Tegra out-of-tree modules. - ifneq ($(wildcard /usr/src/nvidia/nvidia-public),) -@@ -92,9 +92,11 @@ endif - - ifneq ($(SYSSRCNVOOT),) - ccflags-y += -I$(SYSSRCNVOOT)/include -- KBUILD_EXTRA_SYMBOLS = $(SYSSRCNVOOT)/Module.symvers - endif - -+# Always include extra symbols from open-iov-vfio.ko for vGPU VFIO interface -+KBUILD_EXTRA_SYMBOLS := $(abspath $(src)/../../kernel/Module.symvers) -+ - # Some Android kernels prohibit driver use of filesystem functions like - # filp_open() and kernel_read(). Disable the NV_FILESYSTEM_ACCESS_AVAILABLE - # functionality that uses those functions when building for Android. -@@ -174,6 +176,8 @@ endif - CC ?= cc - LD ?= ld - -+export VGX_KVM_BUILD := 1 -+ - NV_CONFTEST_SCRIPT := $(src)/conftest.sh - NV_CONFTEST_HEADER := $(obj)/conftest/headers.h - -diff --git a/kernel-open/Makefile b/kernel-open/Makefile -index 341d55b..ac78628 100644 ---- a/kernel-open/Makefile -+++ b/kernel-open/Makefile -@@ -94,8 +94,12 @@ else - $(NV_KERNEL_MODULES)) - INSTALL_MOD_DIR ?= kernel/drivers/video - -- NV_VERBOSE ?= -- SPECTRE_V2_RETPOLINE ?= 0 -+# KBUILD_EXTRA_SYMBOLS for vGPU VFIO interface symbols from open-iov-vfio.ko -+KBUILD_EXTRA_SYMBOLS := $(abspath $(CURDIR)/../../kernel/Module.symvers) -+ -+NV_VERBOSE ?= -+SPECTRE_V2_RETPOLINE ?= 0 -+VGX_KVM_BUILD ?= 1 - - ifeq ($(NV_VERBOSE),1) - KBUILD_PARAMS += V=1 -@@ -107,6 +111,7 @@ else - KBUILD_PARAMS += NV_KERNEL_MODULES="$(NV_KERNEL_MODULES)" - KBUILD_PARAMS += INSTALL_MOD_DIR="$(INSTALL_MOD_DIR)" - KBUILD_PARAMS += NV_SPECTRE_V2=$(SPECTRE_V2_RETPOLINE) -+ KBUILD_PARAMS += KBUILD_EXTRA_SYMBOLS=$(KBUILD_EXTRA_SYMBOLS) - - export ORIG_PAHOLE := $(PAHOLE) - -diff --git a/kernel-open/Module.symvers.open-iov b/kernel-open/Module.symvers.open-iov -new file mode 100644 -index 0000000..553549f ---- /dev/null -+++ b/kernel-open/Module.symvers.open-iov -@@ -0,0 +1,92 @@ -+0x805e4667 nv_vgpu_register_type_info open-iov-vfio EXPORT_SYMBOL -+0x2510f9e4 nv_vgpu_find_type_info open-iov-vfio EXPORT_SYMBOL -+0xb1cd7273 nv_vgpu_create_mdev_types open-iov-vfio EXPORT_SYMBOL -+0xa3720b3e nv_vgpu_free_type_info open-iov-vfio EXPORT_SYMBOL -+0x3ba3d107 nvidia_vgpu_vfio_get_ops open-iov-vfio EXPORT_SYMBOL -+0xc61962f1 nvidia_vgpu_vfio_set_ops open-iov-vfio EXPORT_SYMBOL -+0x536fe9e2 nv_vgpu_mdev_driver_register open-iov-vfio EXPORT_SYMBOL -+0xe2db996e nv_vgpu_mdev_driver_unregister open-iov-vfio EXPORT_SYMBOL -+0x71713730 nv_vgpu_mdev_register_parent open-iov-vfio EXPORT_SYMBOL -+0xb0486899 nv_vgpu_mdev_unregister_parent open-iov-vfio EXPORT_SYMBOL -+0xdb194166 nvidia_vgpu_vfio_probe open-iov-vfio EXPORT_SYMBOL -+0xc34501b8 nvidia_vgpu_vfio_remove open-iov-vfio EXPORT_SYMBOL -+0x3972fd88 gsp_client_init open-iov-vfio EXPORT_SYMBOL -+0xaf9978fc gsp_client_fini open-iov-vfio EXPORT_SYMBOL -+0x0994eed6 gsp_rpc_alloc open-iov-vfio EXPORT_SYMBOL -+0x01ed1ec0 gsp_rpc_free open-iov-vfio EXPORT_SYMBOL -+0x014ef707 gsp_rpc_map open-iov-vfio EXPORT_SYMBOL -+0x577cba23 gsp_rpc_unmap open-iov-vfio EXPORT_SYMBOL -+0xf55eb4ab gsp_rpc_pin open-iov-vfio EXPORT_SYMBOL -+0x7f0922ac gsp_rpc_unpin open-iov-vfio EXPORT_SYMBOL -+0xc7abb90f gsp_rpc_schedule open-iov-vfio EXPORT_SYMBOL -+0xf64c68e2 gsp_rpc_yield open-iov-vfio EXPORT_SYMBOL -+0x2111f684 gsp_rpc_bar_trap open-iov-vfio EXPORT_SYMBOL -+0xd0b1131e gsp_rpc_migrate_save open-iov-vfio EXPORT_SYMBOL -+0xbd8c881d gsp_rpc_migrate_restore open-iov-vfio EXPORT_SYMBOL -+0x0f989cd0 gsp_wpr_write_mutex_acquire open-iov-vfio EXPORT_SYMBOL -+0x03323922 gsp_wpr_write_mutex_release open-iov-vfio EXPORT_SYMBOL -+0xae7f48d2 gsp_wpr_scratch_mutex_acquire open-iov-vfio EXPORT_SYMBOL -+0xa2d5ed20 gsp_wpr_scratch_mutex_release open-iov-vfio EXPORT_SYMBOL -+0x04a15dd5 gsp_rpc_emulation_set open-iov-vfio EXPORT_SYMBOL -+0x980c5e08 gsp_rpc_emulation_is_enabled open-iov-vfio EXPORT_SYMBOL -+0xa6751cae gsp_rpc_notify_register open-iov-vfio EXPORT_SYMBOL -+0x46ab86c5 gsp_rpc_notify_unregister open-iov-vfio EXPORT_SYMBOL -+0x42fe196a nv_vgpu_gsp_rpc_integration_init open-iov-vfio EXPORT_SYMBOL -+0x3af2d161 nv_vgpu_gsp_rpc_integration_cleanup open-iov-vfio EXPORT_SYMBOL -+0xd748c59b nv_vgpu_gsp_rpc_alloc_fw open-iov-vfio EXPORT_SYMBOL -+0x153fa014 nv_vgpu_gsp_rpc_free_fw open-iov-vfio EXPORT_SYMBOL -+0x637c076f nv_vgpu_gsp_rpc_map_fw open-iov-vfio EXPORT_SYMBOL -+0x34f998ca nv_vgpu_gsp_rpc_unmap_fw open-iov-vfio EXPORT_SYMBOL -+0xeb1110bd nv_vgpu_gsp_rpc_pin_fw open-iov-vfio EXPORT_SYMBOL -+0xf3037685 nv_vgpu_gsp_rpc_unpin_fw open-iov-vfio EXPORT_SYMBOL -+0x21d884f8 nv_vgpu_gsp_rpc_schedule_fw open-iov-vfio EXPORT_SYMBOL -+0xab6ad746 nv_vgpu_gsp_rpc_yield_fw open-iov-vfio EXPORT_SYMBOL -+0x1c4d1f08 nv_vgpu_gsp_rpc_bar_trap_fw open-iov-vfio EXPORT_SYMBOL -+0x708f30d4 nv_vgpu_gsp_rpc_migrate_save_fw open-iov-vfio EXPORT_SYMBOL -+0x8e7872e6 nv_vgpu_gsp_rpc_migrate_restore_fw open-iov-vfio EXPORT_SYMBOL -+0x2ade3dd6 nv_vgpu_gsp_wpr_write_mutex_acquire open-iov-vfio EXPORT_SYMBOL -+0x8dff96a4 nv_vgpu_gsp_wpr_write_mutex_release open-iov-vfio EXPORT_SYMBOL -+0xec05ceea nv_vgpu_gsp_wpr_scratch_mutex_acquire open-iov-vfio EXPORT_SYMBOL -+0x4b246598 nv_vgpu_gsp_wpr_scratch_mutex_release open-iov-vfio EXPORT_SYMBOL -+0xfe33a432 nv_vgpu_gsp_get_primary_dispatcher open-iov-vfio EXPORT_SYMBOL -+0xc1979caa nv_vgpu_gsp_get_secondary_dispatcher open-iov-vfio EXPORT_SYMBOL -+0x89b21e78 nv_vgpu_gsp_get_alloc_main open-iov-vfio EXPORT_SYMBOL -+0x972e5e45 nv_vgpu_gsp_get_schedule_main open-iov-vfio EXPORT_SYMBOL -+0xa6809adb nv_vgpu_gsp_get_bar_trap_handler_jt open-iov-vfio EXPORT_SYMBOL -+0xcf2a6ed8 nv_vgpu_gsp_get_bar_trap_handler_primary open-iov-vfio EXPORT_SYMBOL -+0x1ba6baef nv_vgpu_gsp_get_entry_point open-iov-vfio EXPORT_SYMBOL -+0x4fa3b818 fw_analyzer_analyze open-iov-vfio EXPORT_SYMBOL_GPL -+0x424272d4 fw_analyzer_load_and_analyze open-iov-vfio EXPORT_SYMBOL_GPL -+0x7f7c5e6c fw_analyzer_print_result open-iov-vfio EXPORT_SYMBOL_GPL -+0x8c7dcd3c dynamic_dispatcher_init open-iov-vfio EXPORT_SYMBOL_GPL -+0x01dca6c2 dynamic_dispatcher_fini open-iov-vfio EXPORT_SYMBOL_GPL -+0xcd45da5f dynamic_dispatcher_use_emulation open-iov-vfio EXPORT_SYMBOL_GPL -+0x5c69b70b dynamic_dispatcher_alloc open-iov-vfio EXPORT_SYMBOL_GPL -+0x436485b4 dynamic_dispatcher_free open-iov-vfio EXPORT_SYMBOL_GPL -+0xd4547701 dynamic_dispatcher_map open-iov-vfio EXPORT_SYMBOL_GPL -+0xa69f56a4 dynamic_dispatcher_unmap open-iov-vfio EXPORT_SYMBOL_GPL -+0x444e6538 dynamic_dispatcher_pin open-iov-vfio EXPORT_SYMBOL_GPL -+0x8eeace2b dynamic_dispatcher_unpin open-iov-vfio EXPORT_SYMBOL_GPL -+0x39142c5c dynamic_dispatcher_schedule open-iov-vfio EXPORT_SYMBOL_GPL -+0xb5bb4890 dynamic_dispatcher_yield open-iov-vfio EXPORT_SYMBOL_GPL -+0x5bd014a6 dynamic_dispatcher_bar_trap open-iov-vfio EXPORT_SYMBOL_GPL -+0xc6bc85d2 dynamic_dispatcher_migrate_save open-iov-vfio EXPORT_SYMBOL_GPL -+0x2f480b10 dynamic_dispatcher_migrate_restore open-iov-vfio EXPORT_SYMBOL_GPL -+0xd1994a67 dynamic_dispatcher_notify_register open-iov-vfio EXPORT_SYMBOL_GPL -+0xeb6d1fbc dynamic_dispatcher_notify_unregister open-iov-vfio EXPORT_SYMBOL_GPL -+0x4c369e34 dynamic_dispatcher_get_version open-iov-vfio EXPORT_SYMBOL_GPL -+0xc5d8eb77 dynamic_dispatcher_get_fw_addresses open-iov-vfio EXPORT_SYMBOL_GPL -+0x48cbd40e arch_get_by_name open-iov-vfio EXPORT_SYMBOL_GPL -+0x90c7d953 arch_get_by_pci_id open-iov-vfio EXPORT_SYMBOL_GPL -+0x750f8f00 arch_get_default open-iov-vfio EXPORT_SYMBOL_GPL -+0xa505fad7 arch_get_bar_config open-iov-vfio EXPORT_SYMBOL_GPL -+0x6707466a arch_get_doorbell_offset open-iov-vfio EXPORT_SYMBOL_GPL -+0xc9ed25fd arch_get_shared_mem_offset open-iov-vfio EXPORT_SYMBOL_GPL -+0x1d6af5c9 arch_get_msix_vectors open-iov-vfio EXPORT_SYMBOL_GPL -+0x835587f5 arch_supports_mig open-iov-vfio EXPORT_SYMBOL_GPL -+0x9d3f1b2f arch_supports_sriov open-iov-vfio EXPORT_SYMBOL_GPL -+0xd2409aef arch_get_gsp_version open-iov-vfio EXPORT_SYMBOL_GPL -+0xc75537a2 version_get_interface open-iov-vfio EXPORT_SYMBOL_GPL -+0xe7818f08 version_get_by_kernel_version open-iov-vfio EXPORT_SYMBOL_GPL -+0x12d7fadb version_has_feature open-iov-vfio EXPORT_SYMBOL_GPL -+0xfab46c68 version_get_string open-iov-vfio EXPORT_SYMBOL_GPL -diff --git a/kernel-open/common/inc/nv-linux.h b/kernel-open/common/inc/nv-linux.h -index 7733e80..8331487 100644 ---- a/kernel-open/common/inc/nv-linux.h -+++ b/kernel-open/common/inc/nv-linux.h -@@ -1409,6 +1409,7 @@ typedef struct nv_linux_state_s { - #if defined(NV_VGPU_KVM_BUILD) - wait_queue_head_t wait; - NvS32 return_status; -+ struct mdev_parent *mdev_parent; - #endif - - #if defined(CONFIG_PM_DEVFREQ) -diff --git a/kernel-open/common/inc/nv-vgpu-vfio-interface-nvidia.h b/kernel-open/common/inc/nv-vgpu-vfio-interface-nvidia.h -new file mode 100644 -index 0000000..b2c7734 ---- /dev/null -+++ b/kernel-open/common/inc/nv-vgpu-vfio-interface-nvidia.h -@@ -0,0 +1,71 @@ -+/* SPDX-FileCopyrightText: Copyright (c) 2016-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -+ * SPDX-License-Identifier: MIT -+ */ -+ -+#ifndef _NV_VGPU_VFIO_INTERFACE_NVIDIA_H_ -+#define _NV_VGPU_VFIO_INTERFACE_NVIDIA_H_ -+ -+#include <linux/pci.h> -+#include <linux/device.h> -+#include <linux/mdev.h> -+#include <linux/vfio.h> -+#include "nvstatus.h" -+#include "nv-hypervisor.h" -+ -+typedef NV_STATUS (*vgpu_vfio_probe_t)(struct pci_dev *, NvU32, NvU32 *); -+typedef void (*vgpu_vfio_remove_t)(struct pci_dev *); -+typedef NV_STATUS (*vgpu_vfio_inject_interrupt_t)(void *); -+ -+typedef struct -+{ -+ vgpu_vfio_probe_t probe; -+ vgpu_vfio_remove_t remove; -+ vgpu_vfio_inject_interrupt_t inject_interrupt; -+} vgpu_vfio_ops_t; -+ -+typedef NV_STATUS (*vgpu_vfio_vgpu_create_t) (struct pci_dev *dev, const NvU8 *uuid, -+ NvU32 vgpu_type_id, NvU16 *vgpu_id, -+ NvU32 *gpu_pci_id, NvU32 gpu_pci_bdf); -+typedef NV_STATUS (*vgpu_vfio_vgpu_destroy_t) (const NvU8 *uuid, NvU16 vgpu_id); -+typedef NV_STATUS (*vgpu_vfio_start_t) (const NvU8 *uuid, void *wait_queue, NvS32 *return_status, -+ NvU8 *vm_name, NvU32 qemu_pid); -+typedef NV_STATUS (*vgpu_vfio_bar_info_t) (struct pci_dev *dev, const NvU8 *, NvU64 *, -+ NvU32 bar_index, void *); -+typedef NV_STATUS (*vgpu_vfio_get_description) (struct pci_dev *, NvU32, char *); -+typedef NV_STATUS (*vgpu_vfio_get_name) (struct pci_dev *, NvU32, char *); -+typedef NV_STATUS (*vgpu_vfio_get_instance) (struct pci_dev *, NvU32, char *); -+typedef NV_STATUS (*vgpu_vfio_sparse_mmap_t) (struct pci_dev *, const NvU8 *, NvU64 **, NvU64 **, NvU32 *); -+typedef void (*vgpu_vfio_update_request_t) (const NvU8 *, NvU64 *, NvU64 *, VGPU_DEVICE_STATE, const char *); -+ -+typedef struct -+{ -+ const char *version_string; -+ vgpu_vfio_vgpu_create_t vgpu_create; -+ vgpu_vfio_vgpu_destroy_t vgpu_delete; -+ vgpu_vfio_bar_info_t vgpu_bar_info; -+ vgpu_vfio_start_t vgpu_start; -+ vgpu_vfio_get_description get_description; -+ vgpu_vfio_get_instance get_instances; -+ vgpu_vfio_get_name get_name; -+ vgpu_vfio_sparse_mmap_t get_sparse_mmap; -+ vgpu_vfio_update_request_t update_request; -+} rm_vgpu_vfio_ops_t; -+ -+/* -+ * Functions provided by nvidia-vgpu-vfio module (open-iov-vfio.ko) -+ * and called by nvidia.ko -+ */ -+extern NV_STATUS nvidia_vgpu_vfio_set_ops(vgpu_vfio_ops_t *vgpu_vfio_ops); -+extern NV_STATUS nvidia_vgpu_vfio_get_ops(rm_vgpu_vfio_ops_t *ops); -+extern NV_STATUS nvidia_vgpu_vfio_probe(struct pci_dev *); -+extern void nvidia_vgpu_vfio_remove(struct pci_dev *, NvBool); -+ -+/* -+ * mdev driver registration - provided by nvidia-vgpu-vfio module -+ */ -+extern int nv_vgpu_mdev_driver_register(void); -+extern void nv_vgpu_mdev_driver_unregister(void); -+extern void nv_vgpu_mdev_unregister_parent(struct pci_dev *pci_dev); -+extern int nv_vgpu_mdev_register_parent(struct pci_dev *pci_dev); -+ -+#endif /* _NV_VGPU_VFIO_INTERFACE_NVIDIA_H_ */ -diff --git a/kernel-open/common/inc/nv-vgpu-vfio-interface.h b/kernel-open/common/inc/nv-vgpu-vfio-interface.h -new file mode 100644 -index 0000000..b231407 ---- /dev/null -+++ b/kernel-open/common/inc/nv-vgpu-vfio-interface.h -@@ -0,0 +1,86 @@ -+/* SPDX-FileCopyrightText: Copyright (c) 2016-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -+ * SPDX-License-Identifier: MIT -+ */ -+ -+#ifndef _NV_VGPU_VFIO_INTERFACE_H_ -+#define _NV_VGPU_VFIO_INTERFACE_H_ -+ -+#include <linux/pci.h> -+#include <linux/device.h> -+#include <linux/mdev.h> -+#include <linux/vfio.h> -+#include "nvstatus.h" -+#include "nv-hypervisor.h" -+ -+typedef NV_STATUS (*vgpu_vfio_probe_t)(struct pci_dev *, NvU32, NvU32 *); -+typedef void (*vgpu_vfio_remove_t)(struct pci_dev *); -+typedef NV_STATUS (*vgpu_vfio_inject_interrupt_t)(void *); -+ -+/* -+ * structure to be registered to RM using which it -+ * will call into nvidia-vgpu-vfio module. -+ * RM will use this structure to call into -+ * nvidia-vgpu-vfio module -+ */ -+typedef struct -+{ -+ vgpu_vfio_probe_t probe; -+ vgpu_vfio_remove_t remove; -+ vgpu_vfio_inject_interrupt_t inject_interrupt; -+} vgpu_vfio_ops_t; -+ -+typedef NV_STATUS (*vgpu_vfio_vgpu_create_t) (struct pci_dev *dev, const NvU8 *uuid, -+ NvU32 vgpu_type_id, NvU16 *vgpu_id, -+ NvU32 *gpu_pci_id, NvU32 gpu_pci_bdf); -+typedef NV_STATUS (*vgpu_vfio_vgpu_destroy_t) (const NvU8 *uuid, NvU16 vgpu_id); -+typedef NV_STATUS (*vgpu_vfio_start_t) (const NvU8 *uuid, void *wait_queue, NvS32 *return_status, -+ NvU8 *vm_name, NvU32 qemu_pid); -+typedef NV_STATUS (*vgpu_vfio_bar_info_t) (struct pci_dev *dev, const NvU8 *, NvU64 *, -+ NvU32 bar_index, void *); -+typedef NV_STATUS (*vgpu_vfio_get_description) (struct pci_dev *, NvU32, char *); -+typedef NV_STATUS (*vgpu_vfio_get_name) (struct pci_dev *, NvU32, char *); -+typedef NV_STATUS (*vgpu_vfio_get_instance) (struct pci_dev *, NvU32, char *); -+typedef NV_STATUS (*vgpu_vfio_sparse_mmap_t) (struct pci_dev *, const NvU8 *, NvU64 **, NvU64 **, NvU32 *); -+typedef void (*vgpu_vfio_update_request_t) (const NvU8 *, NvU64 *, NvU64 *, VGPU_DEVICE_STATE, const char *); -+ -+/* -+ * nvidia-vgpu-vfio module uses this structure to -+ * call into RM -+ */ -+typedef struct -+{ -+ const char *version_string; -+ vgpu_vfio_vgpu_create_t vgpu_create; -+ vgpu_vfio_vgpu_destroy_t vgpu_delete; -+ vgpu_vfio_bar_info_t vgpu_bar_info; -+ vgpu_vfio_start_t vgpu_start; -+ vgpu_vfio_get_description get_description; -+ vgpu_vfio_get_instance get_instances; -+ vgpu_vfio_get_name get_name; -+ vgpu_vfio_sparse_mmap_t get_sparse_mmap; -+ vgpu_vfio_update_request_t update_request; -+} rm_vgpu_vfio_ops_t; -+ -+/* -+ * function exposed by RM and called by nvidia-vgpu-vfio -+ * module to initialize vgpu_vfio_ops_t strucure -+ */ -+NV_STATUS nvidia_vgpu_vfio_set_ops(vgpu_vfio_ops_t *vgpu_vfio_ops); -+ -+/* -+ * function exposed by RM and called by nvidia-vgpu-vfio -+ * module to initialize rm_vgpu_vfio_ops_t strucure -+ */ -+NV_STATUS nvidia_vgpu_vfio_get_ops(rm_vgpu_vfio_ops_t *ops); -+ -+NV_STATUS nvidia_vgpu_vfio_probe(struct pci_dev *); -+void nvidia_vgpu_vfio_remove(struct pci_dev *, NvBool); -+ -+#ifndef __GENKSYMS__ -+int nv_vgpu_mdev_driver_register(void); -+void nv_vgpu_mdev_driver_unregister(void); -+void nv_vgpu_mdev_unregister_parent(struct pci_dev *pci_dev); -+int nv_vgpu_mdev_register_parent(struct pci_dev *pci_dev); -+#endif -+ -+#endif /* _NV_VGPU_VFIO_INTERFACE_H_ */ -\ No newline at end of file -diff --git a/kernel-open/nvidia/nv-pci.c b/kernel-open/nvidia/nv-pci.c -index 82338b8..5aed4f8 100644 ---- a/kernel-open/nvidia/nv-pci.c -+++ b/kernel-open/nvidia/nv-pci.c -@@ -29,7 +29,7 @@ - #include "nv-reg.h" - - #if defined(NV_VGPU_KVM_BUILD) --#include "nv-vgpu-vfio-interface.h" -+#include "nv-vgpu-vfio-interface-nvidia.h" - #endif - #include <linux/iommu.h> - -diff --git a/kernel-open/nvidia/nv.c b/kernel-open/nvidia/nv.c -index 04a5c64..6ca6402 100644 ---- a/kernel-open/nvidia/nv.c -+++ b/kernel-open/nvidia/nv.c -@@ -43,7 +43,9 @@ - #endif - - #if defined(NV_VGPU_KVM_BUILD) --#include "nv-vgpu-vfio-interface.h" -+#include "nv-vgpu-vfio-interface-nvidia.h" -+extern int nv_vgpu_mdev_driver_register(void); -+extern void nv_vgpu_mdev_driver_unregister(void); - #endif - - #include "nvlink_proto.h" -@@ -890,6 +892,11 @@ static int __init nvidia_init_module(void) - goto caps_imex_exit; - } - -+#if defined(NV_VGPU_KVM_BUILD) -+ /* mdev driver registration is now handled by nvidia-vgpu-vfio.ko. -+ * Host driver only registers mdev parent via nv_pci_probe. */ -+#endif -+ - count = nvos_count_devices(&num_pci_devices, &num_platform_devices); - if ((count == 0) && (!is_nvswitch_present)) - { -@@ -1011,6 +1018,10 @@ uvm_exit: - module_exit: - nv_module_exit(sp); - -+#if defined(NV_VGPU_KVM_BUILD) -+ /* mdev driver unregistration is now handled by nvidia-vgpu-vfio.ko */ -+#endif -+ - caps_imex_exit: - nv_caps_imex_exit(); - -@@ -1048,6 +1059,10 @@ static void __exit nvidia_exit_module(void) - - nv_module_exit(sp); - -+#if defined(NV_VGPU_KVM_BUILD) -+ /* mdev driver unregistration is now handled by nvidia-vgpu-vfio.ko */ -+#endif -+ - nv_caps_imex_exit(); - - nv_caps_root_exit(); -diff --git a/kernel-open/nvidia/os-interface.c b/kernel-open/nvidia/os-interface.c -index 2bf5a5d..46b99d8 100644 ---- a/kernel-open/nvidia/os-interface.c -+++ b/kernel-open/nvidia/os-interface.c -@@ -1696,6 +1696,12 @@ NV_STATUS NV_API_CALL os_call_vgpu_vfio(void *pvgpu_vfio_info, NvU32 cmd_type) - { - return NV_ERR_NOT_SUPPORTED; - } -+#else -+NV_STATUS NV_API_CALL os_call_vgpu_vfio(void *pvgpu_vfio_info, NvU32 cmd_type) -+{ -+ // Forward to the vGPU VFIO module if available -+ return NV_ERR_NOT_SUPPORTED; -+} - #endif - - NV_STATUS NV_API_CALL os_alloc_pages_node -diff --git a/src/common/inc/nvUnixVersion.h b/src/common/inc/nvUnixVersion.h -index 93a1b1d..6ee92b4 100644 ---- a/src/common/inc/nvUnixVersion.h -+++ b/src/common/inc/nvUnixVersion.h -@@ -5,7 +5,7 @@ - (defined(RMCFG_FEATURE_PLATFORM_GSP) && RMCFG_FEATURE_PLATFORM_GSP == 1) || \ - defined(NV_DCECORE) - --#define NV_VERSION_STRING "610.57.04" -+#define NV_VERSION_STRING "570.144" - - #else - -diff --git a/src/common/shared/inc/g_vgpu_chip_flags.h b/src/common/shared/inc/g_vgpu_chip_flags.h -index c04328d..fafd38f 100644 ---- a/src/common/shared/inc/g_vgpu_chip_flags.h -+++ b/src/common/shared/inc/g_vgpu_chip_flags.h -@@ -35,6 +35,7 @@ ENTRY(0x1E37, 0x13A8, 0x10de, "GRID RTX T10x-4"), - ENTRY(0x1E37, 0x13A9, 0x10de, "GRID RTX T10x-8"), - ENTRY(0x1E37, 0x180D, 0x10de, "NVIDIA GeForce GTX 1060"), - ENTRY(0x1E37, 0x1820, 0x10de, "NVIDIA GeForce RTX 2080"), -+ENTRY(0x1ED3, 0x1F01, 0x1043, "NVIDIA RTX 2080 SUPER Mobile"), - ENTRY(0x1EB8, 0x1309, 0x10de, "GRID T4-1B"), - ENTRY(0x1EB8, 0x130A, 0x10de, "GRID T4-2B"), - ENTRY(0x1EB8, 0x130B, 0x10de, "GRID T4-2B4"), -diff --git a/version.mk b/version.mk -index b35bdde..d27c515 100644 ---- a/version.mk -+++ b/version.mk -@@ -1,5 +1,5 @@ --NVIDIA_VERSION = 610.57.04 --NVIDIA_NVID_VERSION = 610.57.04 -+NVIDIA_VERSION = 570.144 -+NVIDIA_NVID_VERSION = 570.144 - NVIDIA_NVID_EXTRA = - - # This file. --- -2.43.0 - diff --git a/patches/nvidia/README.md b/patches/nvidia/README.md deleted file mode 100644 index 9c74f75..0000000 --- a/patches/nvidia/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# NVIDIA open-gpu-kernel-modules Patches - -Open-IOV does **not** vendor the NVIDIA OpenRM source tree. Instead, the -installer clones upstream at a pinned tag and applies this patch series. - -## Pinned upstream - -- Repository: <https://github.com/NVIDIA/open-gpu-kernel-modules.git> -- Tag: `610.57.04` -- Pristine-tree SHA256 of the delta base: tag `610.57.04` - -## Applying - -```bash -git clone --depth 1 --branch 610.57.04 \ - https://github.com/NVIDIA/open-gpu-kernel-modules.git -cd open-gpu-kernel-modules -git apply /path/to/open-iov/patches/nvidia/*.patch -``` - -(`install.sh` does this automatically.) - -## Regenerating the series - -If you modify the NVIDIA tree, regenerate the patches with: - -```bash -cd nvidia-open-gpu-kernel-modules -git format-patch 610.57.04..HEAD -o ../patches/nvidia/ -``` - -## What the series does - -`0001-Build-fixes-and-vGPU-VFIO-interface-integration.patch`: - -- Adds the vGPU VFIO interface headers (`nv-vgpu-vfio-interface.h`, - `nv-vgpu-vfio-interface-nvidia.h`) that `open-iov-vfio.ko` and - `nvidia.ko` share. -- Exports the vGPU VFIO symbols from `nvidia.ko` - (`nvidia_vgpu_vfio_probe/remove`, `nvidia_vgpu_vfio_get_ops/set_ops`, - `nv_vgpu_mdev_register_parent/unregister_parent`, ...). -- Reports version `570.144` to match the GSP firmware the guest driver - stack is validated against. -- Build fixes for kernel 6.8 out-of-tree builds and the - `Module.symvers.open-iov` reference list. |
