summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_emulation.h
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_emulation.h')
-rw-r--r--kernel/gsp_emulation.h206
1 files changed, 206 insertions, 0 deletions
diff --git a/kernel/gsp_emulation.h b/kernel/gsp_emulation.h
new file mode 100644
index 0000000..9a8f241
--- /dev/null
+++ b/kernel/gsp_emulation.h
@@ -0,0 +1,206 @@
+/*
+ * GSP Emulation Engine for Host-Side GSP Emulation
+ * Replaces guest-side GSP communication with host kernel emulation
+ */
+
+#ifndef _GSP_EMULATION_H_
+#define _GSP_EMULATION_H_
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <linux/eventfd.h>
+
+#include "nvidia-vgpu-vfio.h"
+#include "gsp_rpc_client.h"
+#include "bar_emulation.h"
+#include "irq.h"
+#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 falcon boot-watch: registers polled for change logging so the guest's
+ * physical GSP boot sequence is visible on the host (guest BAR0 access is
+ * mmap-based and otherwise invisible). Offsets are BAR0-relative, GSP falcon
+ * block at 0x110000. */
+#define GSP_EMU_FALCON_WATCH_COUNT 20
+
+/* BAR0 shadow offsets used by the guest's physical GSP boot */
+#define GSP_EMU_REG_GSP_CPUCTL 0x110100 /* bit1 STARTCPU, bit4 HALTED */
+#define GSP_EMU_REG_GSP_ENGINE 0x1103c0 /* bit0 RESET */
+#define GSP_EMU_REG_GSP_MAILBOX0 0x110040
+#define GSP_EMU_REG_GSP_MAILBOX1 0x110044
+#define GSP_EMU_REG_VBIOS_SCRATCH_0E 0x001438 /* FRTS err code (0=NONE) */
+#define GSP_EMU_REG_WPR2_ADDR_LO 0x1fa824
+#define GSP_EMU_REG_WPR2_ADDR_HI 0x1fa828
+#define GSP_EMU_REG_RISCV_STATUS 0x111240 /* bit0 ACTIVE (NV_PRISCV_RISCV
+ CORE_SWITCH_RISCV_STATUS=0x240 at
+ GSP riscvRegisterBase =
+ NV_FALCON2_GSP_BASE=0x111000) */
+
+/* SEC2 falcon (Booter Load/Unload runs here, not on the GSP falcon) */
+#define GSP_EMU_REG_SEC2_CPUCTL 0x840100
+#define GSP_EMU_REG_SEC2_MAILBOX0 0x840040
+#define GSP_EMU_REG_SEC2_ENGINE 0x8403c0
+
+/* Base of the virtual-function register window (NV_VIRTUAL_FUNCTION_FULL_PHYS_
+ * OFFSET). The client RM reaches per-VF registers through GPU_VREG_* =
+ * BAR0 + sriovState.virtualRegPhysOffset + offset; for a non-SRIOV virtual GPU
+ * that offset is 0xB80000, and 0 for a VF, hence the plain + windowed aliases
+ * below. */
+#define GSP_EMU_REG_FULL_PHYS_OFFSET 0xB80000
+
+/* NV_VIRTUAL_FUNCTION_PRIV_MMU_INVALIDATE: driver sets TRIGGER(bit31) to
+ * start a TLB invalidate, then polls for bit31==0 (done). We auto-clear it.
+ * The client RM reaches it through the GPU_VREG_* window (BAR0 + 0xB80000 +
+ * 0x30B0) and the physical path pokes the plain 0x30B0 alias, so watch both. */
+#define GSP_EMU_REG_MMU_INVALIDATE 0x0030b0
+#define GSP_EMU_MMU_INVALIDATE_TRIGGER (1U << 31)
+#define GSP_EMU_REG_MMU_INVALIDATE_WIN (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x0030b0)
+
+/* L2 cache-op completion registers (NV_UFLUSH_*): the driver writes PENDING
+ * (bit 0) to issue FB flush / L2 invalidate / L2 clean+dirty flush and then
+ * spins in kmemsysDoCacheOp_GM107 until the polled bits read back 0. On real
+ * hardware the L2 clears them when the operation completes; the emulated L2
+ * completes instantly, so auto-clear any pending bits.
+ *
+ * On Turing the sysmem/peermem invalidate registers are reached through the
+ * virtual-register window (GPU_VREG_*: BAR0 + sriovState.virtualRegPhysOffset
+ * + NV_VIRTUAL_FUNCTION_PRIV_L2_*); the offset is 0xB80000 for a non-SRIOV
+ * virtual GPU and 0 for a VF, so watch both the plain and windowed aliases. */
+#define GSP_EMU_REG_UFLUSH_BASE 0x070000
+#define GSP_EMU_REG_UFLUSH_FB_FLUSH (GSP_EMU_REG_UFLUSH_BASE + 0x00)
+#define GSP_EMU_REG_UFLUSH_L2_SYSMEM_INV (GSP_EMU_REG_UFLUSH_BASE + 0x04)
+#define GSP_EMU_REG_UFLUSH_L2_PEERMEM_INV (GSP_EMU_REG_UFLUSH_BASE + 0x08)
+#define GSP_EMU_REG_UFLUSH_L2_CLEAN_COMPTAGS (GSP_EMU_REG_UFLUSH_BASE + 0x0c)
+#define GSP_EMU_REG_UFLUSH_L2_FLUSH_DIRTY (GSP_EMU_REG_UFLUSH_BASE + 0x10)
+#define GSP_EMU_REG_UFLUSH_L2_WAIT_SYS_READS (GSP_EMU_REG_UFLUSH_BASE + 0x14)
+
+/* NV_VIRTUAL_FUNCTION_PRIV_L2_{SYSMEM,PEERMEM}_INVALIDATE (dev_vm.h) */
+#define GSP_EMU_REG_VF_L2_SYSMEM_INV 0x000f00
+#define GSP_EMU_REG_VF_L2_PEERMEM_INV 0x000f04
+
+/* NV_PFALCON_FALCON_DEBUGINFO (GSP falcon BAR0+0x110094): holds the CrashCat
+ * wayfinder-L0 descriptor. If its low 16 bits == 0xdead (NV_CRASHCAT_SIGNATURE),
+ * the driver's kgspHealthCheck reads crashcat reports from garbage and loops
+ * forever in nv_open_q (which then can't poll RPCs -> fn-10 FREE timeouts).
+ * Force it to 0 (invalid wayfinder -> crashcatEngineGetNextCrashReport
+ * returns NULL) so the health check always passes. */
+#define GSP_EMU_REG_FALCON_DEBUGINFO 0x110094
+
+/* CPU interrupt tree (Turing, physical-GPU path): the driver accesses the
+ * VF window registers at virtualRegPhysOffset = NV_VIRTUAL_FUNCTION_FULL_PHYS_OFFSET
+ * (0xB80000) + offset.
+ * LEAF_TRIGGER 0xB80000+0x1640 - write a vector to fire its software interrupt
+ * LEAF[i] 0xB80000+0x1000+i*4 - per-32-vector pending bits
+ * TOP[i] 0xB81600+i*4 - per-32-subtree pending bits
+ * _osVerifyInterrupts (osVerifySystemEnvironment) fires a doorbell software
+ * interrupt and waits for its ISR; if we don't set the pending state and
+ * inject MSI-X, the ISR never runs and RmInitAdapter bails. */
+#define GSP_EMU_REG_CPU_INTR_LEAF_TRIGGER (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1640)
+#define GSP_EMU_REG_CPU_INTR_LEAF_BASE (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1000)
+#define GSP_EMU_REG_CPU_INTR_TOP_BASE (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x1600)
+
+/* Windowed aliases of the VF L2 invalidate registers (GPU_VREG_* path). */
+#define GSP_EMU_REG_VF_L2_SYSMEM_INV_WIN (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x000f00)
+#define GSP_EMU_REG_VF_L2_PEERMEM_INV_WIN (GSP_EMU_REG_FULL_PHYS_OFFSET + 0x000f04)
+
+#define GSP_EMU_CPUCTL_STARTCPU 0x2
+#define GSP_EMU_CPUCTL_HALTED 0x10
+
+/* ============================================================
+ * GSP Emulation Context
+ * ============================================================ */
+
+struct gsp_emu_context {
+ struct nv_vgpu_device *vgpu;
+ struct task_struct *thread;
+ struct completion thread_stopped;
+ void __iomem *bar0_vaddr;
+ void __iomem *doorbell_reg;
+ void __iomem *shared_mem;
+ struct gsp_client *rpc_client;
+ spinlock_t lock;
+ bool running;
+ bool initialized;
+ bool stopping;
+
+ /* Shared memory for RPC communication (4KB at BAR0+0x1000) */
+ void *shared_mem_virt;
+ dma_addr_t shared_mem_dma;
+ size_t shared_mem_size;
+
+ /* Statistics */
+ u64 processed_rpcs;
+ u64 failed_rpcs;
+ u64 total_latency_ns;
+
+ /* MSI-X injection */
+ struct eventfd_ctx *msix_trigger[NV_VGPU_MAX_IRQS];
+
+ /* Falcon boot-watch: last-sampled values for change detection */
+ u32 falcon_watch_last[GSP_EMU_FALCON_WATCH_COUNT];
+ bool falcon_watch_valid;
+
+ /* Physical GSP boot emulation state (gsp_emu_poll_boot) */
+ u32 boot_stage; /* enum gsp_emu_boot_stage */
+ u32 flcn_kick_count; /* STARTCPU kicks seen since last ENGINE reset */
+ u32 wpr2_addr_lo; /* WPR2_ADDR_LO value to report after FWSEC */
+
+ /* GSP-RM msgq emulation (physical path, guest-sysmem queues) */
+ struct gsp_rm_emu *rm_emu;
+
+ /* PRAMIN window translation state (BAR0 window -> emulated vidmem) */
+ u32 bar0_window_base; /* last-seen NV_PBUS_BAR0_WINDOW BASE (page) */
+ u32 bar0_window_target; /* last-seen TARGET (0=vidmem, 2/3=sysmem) */
+ bool bar0_window_valid; /* base/target captured at least once */
+};
+
+/* Shadow accessors shared with gsp_rm_emulation.c */
+static inline void gsp_emu_shadow_write32(struct gsp_emu_context *ctx,
+ u32 offset, u32 val)
+{
+ writel(val, ctx->bar0_vaddr + offset);
+}
+
+static inline u32 gsp_emu_shadow_read32(struct gsp_emu_context *ctx, u32 offset)
+{
+ return readl(ctx->bar0_vaddr + offset);
+}
+
+/* ============================================================
+ * Public API
+ * ============================================================ */
+
+int gsp_emu_init(struct nv_vgpu_device *vgpu);
+void gsp_emu_cleanup(struct nv_vgpu_device *vgpu);
+
+/* Clear emulated GSP boot state (WPR2/RISCV/stages/RM queues) on
+ * ENGINE reset or detected GSP death (stale msgq). */
+void gsp_emu_clear_boot_state(struct gsp_emu_context *ctx, const char *reason);
+int gsp_emu_process_rpc(struct gsp_emu_context *ctx);
+void gsp_emu_inject_completion_interrupt(struct gsp_emu_context *ctx, u32 seq_id);
+
+/* ============================================================
+ * Debug/Statistics
+ * ============================================================ */
+
+void gsp_emu_get_stats(struct gsp_emu_context *ctx,
+ u64 *processed, u64 *failed, u64 *total_latency_ns);
+
+#endif /* _GSP_EMULATION_H_ */ \ No newline at end of file