summaryrefslogtreecommitdiffstats
path: root/kernel/bar_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bar_init.c')
-rw-r--r--kernel/bar_init.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/kernel/bar_init.c b/kernel/bar_init.c
index 9926e2b..5e4b0a0 100644
--- a/kernel/bar_init.c
+++ b/kernel/bar_init.c
@@ -5,6 +5,7 @@
#include "nvidia-vgpu-vfio.h"
#include "bar_emulation.h"
+#include "gsp_phys_gpu.h"
#include "irq.h"
int nv_vgpu_bar_init(struct nv_vgpu_device *vgpu)
@@ -75,12 +76,34 @@ int nv_vgpu_bar_init(struct nv_vgpu_device *vgpu)
if (bar_addr && bar_size) {
vgpu->bars[2].gpa = bar_addr;
vgpu->bars[2].size = bar_size;
- vgpu->bars[2].vaddr = ioremap_wc(bar_addr, bar_size);
- if (!vgpu->bars[2].vaddr) {
- nv_vgpu_err(vgpu, "Failed to map BAR2");
- return -ENOMEM;
+ /*
+ * Emulation-only mode (gsp_phys_gpu=0): the host nvidia driver
+ * owns the physical GPU. Never ioremap the real BAR2 nor expose
+ * its PFNs to the guest - guest BAR2 MMIO against a device the
+ * distribution driver owns is the suspected trigger of the Xid
+ * 140 uncorrectable-ECC incident (2026-10-03). Back the region
+ * with a private host-RAM shadow instead, exactly like BAR1/BAR3.
+ * Claim/backend mode keeps the real mapping.
+ */
+ if (gsp_phys_gpu_enabled()) {
+ vgpu->bars[2].vaddr = ioremap_wc(bar_addr, bar_size);
+ if (!vgpu->bars[2].vaddr) {
+ nv_vgpu_err(vgpu, "Failed to map BAR2");
+ return -ENOMEM;
+ }
+ nv_vgpu_info(vgpu, "BAR2: gpa=0x%llx, size=0x%llx, vaddr=%p (real, claim mode)",
+ bar_addr, bar_size, vgpu->bars[2].vaddr);
+ } else {
+ vgpu->bars[2].vaddr = vzalloc(bar_size);
+ vgpu->bars[2].emulated = true;
+ if (!vgpu->bars[2].vaddr) {
+ nv_vgpu_err(vgpu, "Failed to allocate emulated BAR2 (%llu bytes)",
+ (unsigned long long)bar_size);
+ return -ENOMEM;
+ }
+ nv_vgpu_info(vgpu, "BAR2: gpa=0x%llx, size=0x%llx, emulated shadow=%p",
+ bar_addr, bar_size, vgpu->bars[2].vaddr);
}
- nv_vgpu_info(vgpu, "BAR2: gpa=0x%llx, size=0x%llx, vaddr=%p", bar_addr, bar_size, vgpu->bars[2].vaddr);
}
bar_addr = pci_resource_start(pdev, 3);
@@ -142,9 +165,17 @@ void nv_vgpu_bar_cleanup(struct nv_vgpu_device *vgpu)
vgpu->bars[3].vaddr = NULL;
}
+ /* Free the emulated BAR2 shadow (emulation-only mode) */
+ if (vgpu->bars[2].emulated && vgpu->bars[2].vaddr) {
+ vfree(vgpu->bars[2].vaddr);
+ vgpu->bars[2].vaddr = NULL;
+ }
+
for (i = 0; i < NV_VGPU_MAX_REGIONS; i++) {
if (i == 1 || i == 3)
continue; /* shadow buffers already freed above */
+ if (i == 2 && vgpu->bars[2].emulated)
+ continue; /* shadow buffer already freed above */
if (vgpu->bars[i].vaddr) {
iounmap(vgpu->bars[i].vaddr);
vgpu->bars[i].vaddr = NULL;