summaryrefslogtreecommitdiffstats
path: root/kernel/bar_emulation.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-13 19:11:39 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-13 19:11:39 -0400
commit8e64754d9980d2423f1907ae184ec46e63e5ff7e (patch)
treeb81c8e89fa699a5f0010640e30c5acfbab818474 /kernel/bar_emulation.c
parent4b745a1c2c0534a1850b6efe6710536b2225c3f4 (diff)
downloadopen-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/bar_emulation.c')
-rw-r--r--kernel/bar_emulation.c135
1 files changed, 135 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++) {