diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-13 19:11:39 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-13 19:11:39 -0400 |
| commit | 8e64754d9980d2423f1907ae184ec46e63e5ff7e (patch) | |
| tree | b81c8e89fa699a5f0010640e30c5acfbab818474 /kernel | |
| parent | 4b745a1c2c0534a1850b6efe6710536b2225c3f4 (diff) | |
| download | open-iov-8e64754d9980d2423f1907ae184ec46e63e5ff7e.tar.gz open-iov-8e64754d9980d2423f1907ae184ec46e63e5ff7e.zip | |
Phase 2: PCI Config Space & BAR Enhancements
- Enhanced PCI config space write handlers in main.c:
- Added MSI-X Message Control (0x72-0x73) write support
- Added MSI-X Table Offset/BIR (0x74-0x77) write support
- Added MSI-X PBA Offset/BIR (0x78-0x7B) write support
- Enhanced BAR emulation in bar_emulation.c:
- Added MSI-X Table emulation (32 entries at BAR0+0x2000)
- Added MSI-X PBA emulation (64-bit at BAR0+0x3000)
- Added nv_vgpu_msix_set_pending/clear_pending for interrupt injection
- Integrated with GSP emulation constants from gsp_emulation.h
- Updated bar_emulation.h with MSI-X struct definitions and function declarations
- Added GSP emulation constants to gsp_emulation.h (MSIX offsets, polling params)
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/bar_emulation.c | 135 | ||||
| -rw-r--r-- | kernel/gsp_emulation.h | 13 | ||||
| -rw-r--r-- | kernel/include/bar_emulation.h | 22 | ||||
| -rw-r--r-- | kernel/main.c | 9 |
4 files changed, 179 insertions, 0 deletions
diff --git a/kernel/bar_emulation.c b/kernel/bar_emulation.c index 17904fe..009f0e2 100644 --- a/kernel/bar_emulation.c +++ b/kernel/bar_emulation.c @@ -5,13 +5,21 @@ #include <linux/pci.h> #include <linux/mm.h> #include <linux/highmem.h> +#include <linux/eventfd.h> #include "nvidia-vgpu-vfio.h" #include "bar_emulation.h" #include "gsp_comm.h" +#include "gsp_emulation.h" #define NV_VGPU_BAR0_TRAP_REGIONS 64 +/* MSI-X Table entry size (16 bytes: addr_lo, addr_hi, data, vector_control) */ +#define NV_VGPU_MSIX_ENTRY_SIZE 16 +#define NV_VGPU_MSIX_TABLE_ENTRIES 32 +#define NV_VGPU_MSIX_TABLE_SIZE (NV_VGPU_MSIX_ENTRY_SIZE * NV_VGPU_MSIX_TABLE_ENTRIES) +#define NV_VGPU_MSIX_PBA_SIZE 8 /* 64 bits for 32 vectors */ + static const struct { u32 offset; u32 size; @@ -62,6 +70,107 @@ static const struct { { 0x1F0000, 0x10000, "MISC" }, }; +static void nv_vgpu_msix_init(struct nv_vgpu_bar_emul_ctx *ctx) +{ + memset(ctx->msix_table, 0, sizeof(ctx->msix_table)); + ctx->msix_pba = 0; + spin_lock_init(&ctx->msix_lock); + ctx->msix_enabled = false; +} + +static void nv_vgpu_msix_write_table(struct nv_vgpu_bar_emul_ctx *ctx, + u32 offset, u64 val, u32 size) +{ + u32 entry_idx = offset / NV_VGPU_MSIX_ENTRY_SIZE; + u32 entry_offset = offset % NV_VGPU_MSIX_ENTRY_SIZE; + + if (entry_idx >= NV_VGPU_MSIX_TABLE_ENTRIES) + return; + + spin_lock(&ctx->msix_lock); + + switch (entry_offset) { + case 0x0: /* Message Address Low */ + ctx->msix_table[entry_idx].addr = (ctx->msix_table[entry_idx].addr & 0xFFFFFFFF00000000ULL) | val; + break; + case 0x4: /* Message Address High */ + ctx->msix_table[entry_idx].addr = (ctx->msix_table[entry_idx].addr & 0x00000000FFFFFFFFULL) | (val << 32); + break; + case 0x8: /* Message Data */ + ctx->msix_table[entry_idx].data = (u32)val; + break; + case 0xC: /* Vector Control */ + ctx->msix_table[entry_idx].vector_control = (u32)val; + break; + } + + spin_unlock(&ctx->msix_lock); +} + +static u64 nv_vgpu_msix_read_table(struct nv_vgpu_bar_emul_ctx *ctx, + u32 offset, u32 size) +{ + u32 entry_idx = offset / NV_VGPU_MSIX_ENTRY_SIZE; + u32 entry_offset = offset % NV_VGPU_MSIX_ENTRY_SIZE; + u64 val = 0; + + if (entry_idx >= NV_VGPU_MSIX_TABLE_ENTRIES) + return 0; + + spin_lock(&ctx->msix_lock); + + switch (entry_offset) { + case 0x0: /* Message Address Low */ + val = ctx->msix_table[entry_idx].addr & 0xFFFFFFFF; + break; + case 0x4: /* Message Address High */ + val = (ctx->msix_table[entry_idx].addr >> 32) & 0xFFFFFFFF; + break; + case 0x8: /* Message Data */ + val = ctx->msix_table[entry_idx].data; + break; + case 0xC: /* Vector Control */ + val = ctx->msix_table[entry_idx].vector_control; + break; + } + + spin_unlock(&ctx->msix_lock); + return val; +} + +static u64 nv_vgpu_msix_read_pba(struct nv_vgpu_bar_emul_ctx *ctx, u32 size) +{ + u64 val; + spin_lock(&ctx->msix_lock); + val = ctx->msix_pba; + spin_unlock(&ctx->msix_lock); + return val; +} + +void nv_vgpu_msix_set_pending(struct nv_vgpu_device *vgpu, int vector) +{ + struct nv_vgpu_bar_emul_ctx *ctx = vgpu->bar_emul_ctx; + + if (!ctx || vector < 0 || vector >= NV_VGPU_MSIX_TABLE_ENTRIES) + return; + + spin_lock(&ctx->msix_lock); + ctx->msix_pba |= (1ULL << vector); + spin_unlock(&ctx->msix_lock); +} + +void nv_vgpu_msix_clear_pending(struct nv_vgpu_device *vgpu, int vector) +{ + struct nv_vgpu_bar_emul_ctx *ctx = vgpu->bar_emul_ctx; + + if (!ctx || vector < 0 || vector >= NV_VGPU_MSIX_TABLE_ENTRIES) + return; + + spin_lock(&ctx->msix_lock); + ctx->msix_pba &= ~(1ULL << vector); + spin_unlock(&ctx->msix_lock); +} + int nv_vgpu_bar_emul_init(struct nv_vgpu_device *vgpu) { struct nv_vgpu_bar_emul_ctx *ctx; @@ -90,6 +199,9 @@ int nv_vgpu_bar_emul_init(struct nv_vgpu_device *vgpu) ctx->trap_count++; } + /* Initialize MSI-X emulation */ + nv_vgpu_msix_init(ctx); + vgpu->bar_emul_ctx = ctx; return 0; @@ -180,6 +292,21 @@ int nv_vgpu_bar_emul_read(struct nv_vgpu_device *vgpu, int bar_idx, if (!ctx || bar_idx != 0 || offset >= ctx->bar0_shadow_size) return -EINVAL; + /* Handle MSI-X Table reads (at BAR0+0x2000) */ + if (offset >= GSP_EMU_MSIX_TABLE_OFFSET && + offset < GSP_EMU_MSIX_TABLE_OFFSET + NV_VGPU_MSIX_TABLE_SIZE) { + u32 msix_offset = offset - GSP_EMU_MSIX_TABLE_OFFSET; + *val64 = nv_vgpu_msix_read_table(ctx, msix_offset, size); + return 0; + } + + /* Handle MSI-X PBA reads (at BAR0+0x3000) */ + if (offset >= GSP_EMU_MSIX_PBA_OFFSET && + offset < GSP_EMU_MSIX_PBA_OFFSET + NV_VGPU_MSIX_PBA_SIZE) { + *val64 = nv_vgpu_msix_read_pba(ctx, size); + return 0; + } + spin_lock_irqsave(&ctx->shadow_lock, flags); switch (size) { @@ -211,6 +338,14 @@ int nv_vgpu_bar_emul_write(struct nv_vgpu_device *vgpu, int bar_idx, if (!ctx || bar_idx != 0 || offset >= ctx->bar0_shadow_size) return -EINVAL; + /* Handle MSI-X Table writes (at BAR0+0x2000) */ + if (offset >= GSP_EMU_MSIX_TABLE_OFFSET && + offset < GSP_EMU_MSIX_TABLE_OFFSET + NV_VGPU_MSIX_TABLE_SIZE) { + u32 msix_offset = offset - GSP_EMU_MSIX_TABLE_OFFSET; + nv_vgpu_msix_write_table(ctx, msix_offset, *val64, size); + return 0; + } + spin_lock_irqsave(&ctx->shadow_lock, flags); for (i = 0; i < ctx->trap_count; i++) { diff --git a/kernel/gsp_emulation.h b/kernel/gsp_emulation.h index c4ceb7a..f703ae6 100644 --- a/kernel/gsp_emulation.h +++ b/kernel/gsp_emulation.h @@ -22,6 +22,19 @@ #include "memory.h" /* ============================================================ + * GSP Emulation Constants + * ============================================================ */ + +#define GSP_EMU_DOORBELL_OFFSET 0x110C00 +#define GSP_EMU_SHARED_MEM_OFFSET 0x1000 +#define GSP_EMU_SHARED_MEM_SIZE 4096 +#define GSP_EMU_MSIX_TABLE_OFFSET 0x2000 +#define GSP_EMU_MSIX_PBA_OFFSET 0x3000 +#define GSP_EMU_POLL_BUSY_US 100 +#define GSP_EMU_POLL_SLEEP_MIN_US 50 +#define GSP_EMU_POLL_SLEEP_MAX_US 100 + +/* ============================================================ * GSP Emulation Context * ============================================================ */ diff --git a/kernel/include/bar_emulation.h b/kernel/include/bar_emulation.h index 759fa25..326e70e 100644 --- a/kernel/include/bar_emulation.h +++ b/kernel/include/bar_emulation.h @@ -3,12 +3,30 @@ #include "nvidia-vgpu-vfio.h" +/* MSI-X Table entry size (16 bytes: addr_lo, addr_hi, data, vector_control) */ +#define NV_VGPU_MSIX_ENTRY_SIZE 16 +#define NV_VGPU_MSIX_TABLE_ENTRIES 32 +#define NV_VGPU_MSIX_TABLE_SIZE (NV_VGPU_MSIX_ENTRY_SIZE * NV_VGPU_MSIX_TABLE_ENTRIES) +#define NV_VGPU_MSIX_PBA_SIZE 8 /* 64 bits for 32 vectors */ + +struct nv_vgpu_msix_entry { + u64 addr; + u32 data; + u32 vector_control; +}; + struct nv_vgpu_bar_emul_ctx { struct nv_vgpu_device *vgpu; void *bar0_shadow; size_t bar0_shadow_size; spinlock_t shadow_lock; + /* MSI-X emulation */ + struct nv_vgpu_msix_entry msix_table[NV_VGPU_MSIX_TABLE_ENTRIES]; + u64 msix_pba; /* Pending Bit Array */ + spinlock_t msix_lock; + bool msix_enabled; + struct { u32 offset; u32 value; @@ -34,6 +52,10 @@ int nv_vgpu_bar_emul_write(struct nv_vgpu_device *vgpu, int bar_idx, int nv_vgpu_bar_emul_handle_fault(struct nv_vgpu_device *vgpu, unsigned long addr, bool write); +/* MSI-X emulation */ +void nv_vgpu_msix_set_pending(struct nv_vgpu_device *vgpu, int vector); +void nv_vgpu_msix_clear_pending(struct nv_vgpu_device *vgpu, int vector); + static inline u32 nv_vgpu_read_reg(void __iomem *base, u32 offset) { return readl(base + offset); diff --git a/kernel/main.c b/kernel/main.c index efe5082..a277356 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -823,6 +823,15 @@ static ssize_t nv_vgpu_config_write(struct nv_vgpu_device *vgpu, const char __us case 0x5c: case 0x5d: /* MSI Message Data */ vgpu->pci_config[pos] = val; break; + case 0x72: case 0x73: /* MSI-X Message Control */ + vgpu->pci_config[pos] = val; + break; + case 0x74: case 0x75: case 0x76: case 0x77: /* MSI-X Table Offset/BIR */ + vgpu->pci_config[pos] = val; + break; + case 0x78: case 0x79: case 0x7a: case 0x7b: /* MSI-X PBA Offset/BIR */ + vgpu->pci_config[pos] = val; + break; case 0x88: case 0x89: /* Device Control */ case 0x90: case 0x91: /* Link Control */ case 0x98: case 0x99: /* Slot Control */ |
