summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/bar_emulation.c135
-rw-r--r--kernel/gsp_emulation.h13
-rw-r--r--kernel/include/bar_emulation.h22
-rw-r--r--kernel/main.c9
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 */