From 8e64754d9980d2423f1907ae184ec46e63e5ff7e Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Sun, 13 Sep 2026 19:11:39 -0400 Subject: 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) --- kernel/bar_emulation.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) (limited to 'kernel/bar_emulation.c') 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 #include #include +#include #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++) { -- cgit v1.2.3