summaryrefslogtreecommitdiffstats
path: root/tools/rmq/kmod
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 18:01:55 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 18:01:55 -0400
commit6aadb593750736f239fd54a0ccef4b3834c08fc4 (patch)
tree5b3d39d82a09cdfd3ca8022cd9c0f83040f23229 /tools/rmq/kmod
parentc8249854284c3e8181587b96e3c5b4177d705e0c (diff)
downloadopen-iov-6aadb593750736f239fd54a0ccef4b3834c08fc4.tar.gz
open-iov-6aadb593750736f239fd54a0ccef4b3834c08fc4.zip
kernel: GSP-RM msgq emulation + TU104 hardware tables (GET_GSP_STATIC_INFO, GSP_RM_CONTROL)
Implements the GSP-RM reply content layer for the msgq RPC channel: - kernel/gsp_rm_emulation.c/h: GSP-RM msgq emulation engine - Queue chain discovery (libos args → RMARGS → GSP_ARGUMENTS_CACHED) - Status queue link + GSP_INIT_DONE emission - Command queue polling + RPC dispatch - SET_GUEST_SYSTEM_INFO version negotiation (VGX 41.12) - GET_GSP_STATIC_INFO(65) with 1656-byte GspStaticConfigInfo - GSP_RM_CONTROL(76) sub-command dispatch: - FIFO_GET_DEVICE_INFO_TABLE (0x20801112) - INTERNAL_INTR_GET_KERNEL_TABLE (0x20800a5c) - GPU_GET_CONSTRUCTED_FALCON_INFO (0x208001b0) - INTERNAL_GET_DEVICE_INFO_TABLE (0x20800a40) - kernel/gsp_rm_tu104.h: TU104 hardware tables - 12-entry FIFO engine table (GR0, CE0-4, NVDEC0-1, NVENC0, SEC2, NVJPG, SW) - 8-entry interrupt table (from intr_phys_tu102.c) - 1-entry constructed falcon table (FBFLCN) - 11-entry internal device info table - GspStaticConfigInfo layout (1656 bytes, ABI-verified offsets) - Data from NVIDIA driver material (ext-tree) + hwref/turing/tu104 - tools/rmq/: Userspace RM API client (oracle for ground-truth tables) KNOWN ISSUE: gsp_rm_send crashes (fortify_panic) on multi-element messages when reply data exceeds one 4096-byte queue element. Affects cmd 0x20800a41 (paramsSize=8204). Multi-element splitting is the next fix.
Diffstat (limited to 'tools/rmq/kmod')
-rw-r--r--tools/rmq/kmod/Makefile7
-rw-r--r--tools/rmq/kmod/wpr2_reset_kmod.c90
2 files changed, 97 insertions, 0 deletions
diff --git a/tools/rmq/kmod/Makefile b/tools/rmq/kmod/Makefile
new file mode 100644
index 0000000..2fde4ef
--- /dev/null
+++ b/tools/rmq/kmod/Makefile
@@ -0,0 +1,7 @@
+obj-m += wpr2_reset_kmod.o
+
+all:
+ make -C /lib/modules/$(shell uname -r)/build M=$(CURDIR) modules
+
+clean:
+ make -C /lib/modules/$(shell uname -r)/build M=$(CURDIR) clean
diff --git a/tools/rmq/kmod/wpr2_reset_kmod.c b/tools/rmq/kmod/wpr2_reset_kmod.c
new file mode 100644
index 0000000..523fac7
--- /dev/null
+++ b/tools/rmq/kmod/wpr2_reset_kmod.c
@@ -0,0 +1,90 @@
+/* wpr2_reset_kmod - kernel module that clears GPU WPR2 registers via BAR0 ioremap.
+ *
+ * When nvidia.ko is unloaded without a clean GSP teardown, GSP firmware stays
+ * resident in WPR2 (a write-protected FB region described by
+ * PFB_PRI_MMU_WPR2_ADDR_LO/HI). Every subsequent RmInitAdapter then fails with
+ * "unexpected WPR2 already up" and FLR does not help (GSP survives warm resets).
+ *
+ * This module ioremaps GPU BAR0 and pokes WPR2_ADDR_LO/HI to zero so the next
+ * driver load takes the normal (clean) GSP boot path. Equivalent to the effect
+ * of FWSEC-SB + Booter Unload teardown, minus running the ucodes.
+ *
+ * Usage: sudo insmod wpr2_reset_kmod.ko [pci_bdf=0000:01:00.0]
+ * result printed via pr_info (check dmesg)
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#define NV_PFB_PRI_MMU_WPR2_ADDR_LO 0x1fa824
+#define NV_PFB_PRI_MMU_WPR2_ADDR_HI 0x1fa828
+
+static char *pci_bdf = "0000:01:00.0";
+module_param(pci_bdf, charp, 0444);
+MODULE_PARM_DESC(pci_bdf, "PCI BDF of the GPU (default 0000:01:00.0)");
+
+static int __init wpr2_reset_init(void)
+{
+ struct pci_dev *pdev = NULL;
+ unsigned int bus, dev, fn;
+ void __iomem *bar0;
+ u32 lo_before, hi_before, lo_after, hi_after;
+
+ if (sscanf(pci_bdf, "0000:%x:%x.%u", &bus, &dev, &fn) != 3) {
+ pr_err("wpr2_reset: bad pci_bdf %s\n", pci_bdf);
+ return -EINVAL;
+ }
+ pdev = pci_get_domain_bus_and_slot(0, bus, PCI_DEVFN(dev, fn));
+ if (!pdev) {
+ pr_err("wpr2_reset: device %s not found\n", pci_bdf);
+ return -ENODEV;
+ }
+ if (!pci_resource_start(pdev, 0)) {
+ pr_err("wpr2_reset: BAR0 not assigned\n");
+ pci_dev_put(pdev);
+ return -ENODEV;
+ }
+
+ if (pci_enable_device(pdev)) {
+ pr_err("wpr2_reset: pci_enable_device failed\n");
+ pci_dev_put(pdev);
+ return -EIO;
+ }
+ pci_set_master(pdev);
+ bar0 = ioremap_wc(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!bar0) {
+ pr_err("wpr2_reset: ioremap failed\n");
+ pci_dev_put(pdev);
+ return -ENOMEM;
+ }
+
+ lo_before = readl(bar0 + NV_PFB_PRI_MMU_WPR2_ADDR_LO);
+ hi_before = readl(bar0 + NV_PFB_PRI_MMU_WPR2_ADDR_HI);
+ pr_info("wpr2_reset: before LO=0x%08x HI=0x%08x\n", lo_before, hi_before);
+
+ writel(0, bar0 + NV_PFB_PRI_MMU_WPR2_ADDR_LO);
+ writel(0, bar0 + NV_PFB_PRI_MMU_WPR2_ADDR_HI);
+
+ lo_after = readl(bar0 + NV_PFB_PRI_MMU_WPR2_ADDR_LO);
+ hi_after = readl(bar0 + NV_PFB_PRI_MMU_WPR2_ADDR_HI);
+ pr_info("wpr2_reset: after LO=0x%08x HI=0x%08x\n", lo_after, hi_after);
+
+ if (hi_after == 0)
+ pr_info("wpr2_reset: WPR2 cleared, clean GSP boot now possible\n");
+ else
+ pr_info("wpr2_reset: write dropped (PLM?) - WPR2 still up\n");
+
+ iounmap(bar0);
+ pci_dev_put(pdev);
+ return hi_after ? -EINVAL : 0;
+}
+
+static void __exit wpr2_reset_exit(void)
+{
+ pr_info("wpr2_reset: unloaded\n");
+}
+
+module_init(wpr2_reset_init);
+module_exit(wpr2_reset_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Clear GPU WPR2 registers to unstick GSP boot");