summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 00:04:14 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 00:04:14 -0400
commit7d6c789a469de154ee6d26a7fb9161ef7279a34a (patch)
tree08daeca568f6e22267617bd8f86c5e4d58d3482d /kernel
parent1ed5d98cbb2273e75674d050fb48e3c3422a3877 (diff)
downloadopen-iov-7d6c789a469de154ee6d26a7fb9161ef7279a34a.tar.gz
open-iov-7d6c789a469de154ee6d26a7fb9161ef7279a34a.zip
kernel: real TU104 config-space layout (PCIe cap at 0x78) + CUDA/UVM tracing
Move the emulated PCIe capability to config offset 0x78 and shift MSI to 0x48 / MSI-X to 0x68, matching the real TU104 (host lspci: PM 0x60, MSI 0x68, Express 0x78). This matters because the driver's NV_PCFG mirror (BAR0+0x88000, size 0x1000) is read as PCI config space: osDevReadReg032 -> vgpuDevReadReg032 intercepts [NV_PCFG, +0x30) (or the full 0x1000 for SRIOV) and forwards to osPciReadDword, so NV_XVE_LINK_CAPABILITIES (0x84) must be the PCIe Link Capabilities register, i.e. cap+0x0C with the cap at 0x78. Link Caps = Gen3 x16 (0x103), Link Status = 0x0103. Also set MCFG-visible caps: the guest now reports MSI [48], MSI-X [68], Express [78] exactly like the host GPU. Fixing the capability chain: the first attempt set the PCIe cap's NEXT to 0x0C, which broke enumeration (device 00:06.0 disappeared from the guest) - NEXT must terminate at 0. Unknown still open: QEMU presents type=0x92 (Root Complex Integrated Endpoint) and zeroes 0x84-0x8B in its config cache (never read from us, not refreshed by writes), and poisoning all BAR0 mirror windows with 0x103 does not change the driver's "Unknown PCIe speed" - so the value comes from the VGPU_STATIC_INFO branch (pVSI->pcieGpuLinkCaps, IS_VIRTUAL true via hypervisor detection) rather than any register read. Debug helpers added (temporary): CFGWR config-write log, PCFG change watch, PCIe-cap print at init.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bar_emulation.c16
-rw-r--r--kernel/main.c162
2 files changed, 119 insertions, 59 deletions
diff --git a/kernel/bar_emulation.c b/kernel/bar_emulation.c
index 3448b8c..1229a77 100644
--- a/kernel/bar_emulation.c
+++ b/kernel/bar_emulation.c
@@ -309,6 +309,22 @@ int nv_vgpu_bar_emul_init(struct nv_vgpu_device *vgpu)
*(u32 *)((u8 *)ctx->bar0_shadow + 0xC08084) = 0x00000103;
*(u32 *)((u8 *)ctx->bar0_shadow + 0xC08088) = 0x01030000;
+ /* TEMP EXPERIMENT: poison the candidate mirror windows with the
+ * Gen3 x16 link-caps value in every dword, to locate where the
+ * driver's gpuReadBusConfigReg(0x84) actually lands. Ranges are
+ * chosen to avoid real emulated registers (the CPU intr tree starts
+ * at 0xB81000). */
+ {
+ u32 off;
+
+ for (off = 0x88000; off < 0x89000; off += 4)
+ *(u32 *)((u8 *)ctx->bar0_shadow + off) = 0x00000103;
+ for (off = 0xB80000; off < 0xB80F00; off += 4)
+ *(u32 *)((u8 *)ctx->bar0_shadow + off) = 0x00000103;
+ for (off = 0xC08000; off < 0xC08F00; off += 4)
+ *(u32 *)((u8 *)ctx->bar0_shadow + off) = 0x00000103;
+ }
+
/*
* Serve a valid VBIOS at the PROM window (BAR0+0x300000).
*
diff --git a/kernel/main.c b/kernel/main.c
index 209942b..451fa55 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -744,6 +744,12 @@ static ssize_t nv_vgpu_vfio_dev_write(struct vfio_device *vdev, const char __use
if (pos >= 0x70000000000ULL && pos < 0x70000000000ULL + 4096) {
loff_t cfg_pos = pos - 0x70000000000ULL;
ssize_t ret;
+ u8 wbuf[8];
+
+ if (count <= sizeof(wbuf) && !copy_from_user(wbuf, buf, count))
+ nv_vgpu_info(vgpu, "CFGWR off=0x%llx count=%zu data=%*phN",
+ (unsigned long long)cfg_pos, count,
+ (int)count, wbuf);
ret = nv_vgpu_config_write(vgpu, buf, count, &cfg_pos);
if (ret > 0)
@@ -1670,7 +1676,7 @@ static int nv_vgpu_config_space_init(struct nv_vgpu_device *vgpu, struct pci_dev
/* Power Management Capability (0x40) */
cfg[0x40] = 0x01; /* Capability ID: Power Management */
- cfg[0x41] = 0x50; /* Next capability: MSI at 0x50 */
+ cfg[0x41] = 0x48; /* Next capability: MSI at 0x48 */
cfg[0x42] = 0x03; /* PME support from D0, D3hot, D3cold */
cfg[0x43] = 0x00;
cfg[0x44] = 0x00; /* PM Control/Status */
@@ -1678,74 +1684,110 @@ static int nv_vgpu_config_space_init(struct nv_vgpu_device *vgpu, struct pci_dev
cfg[0x46] = 0x00;
cfg[0x47] = 0x00;
- /* MSI Capability (0x50) */
- cfg[0x50] = 0x05; /* Capability ID: MSI */
- cfg[0x51] = 0x70; /* Next capability: MSI-X at 0x70 */
- cfg[0x52] = 0x80; /* 64-bit capable, 1 vector */
+ /* MSI Capability (0x48) */
+ cfg[0x48] = 0x05; /* Capability ID: MSI */
+ cfg[0x49] = 0x68; /* Next capability: MSI-X at 0x68 */
+ cfg[0x4a] = 0x80; /* 64-bit capable, 1 vector */
+ cfg[0x4b] = 0x00;
+ cfg[0x4c] = 0x00; /* Message Address (low) - set by guest */
+ cfg[0x4d] = 0x00;
+ cfg[0x4e] = 0x00;
+ cfg[0x4f] = 0x00;
+ cfg[0x50] = 0x00; /* Message Address (high) - 64-bit */
+ cfg[0x51] = 0x00;
+ cfg[0x52] = 0x00;
cfg[0x53] = 0x00;
- cfg[0x54] = 0x00; /* Message Address (low) - set by guest */
+ cfg[0x54] = 0x01; /* Message Data - set by guest */
cfg[0x55] = 0x00;
- cfg[0x56] = 0x00;
- cfg[0x57] = 0x00;
- cfg[0x58] = 0x00; /* Message Address (high) - 64-bit */
- cfg[0x59] = 0x00;
- cfg[0x5a] = 0x00;
- cfg[0x5b] = 0x00;
- cfg[0x5c] = 0x01; /* Message Data - set by guest */
- cfg[0x5d] = 0x00;
-
- /* MSI-X Capability (0x70) */
- cfg[0x70] = 0x11; /* Capability ID: MSI-X */
- cfg[0x71] = 0x80; /* Next capability: PCI Express at 0x80 */
- cfg[0x72] = 0x1f; /* Table size = 31 (32 vectors), 64-bit */
+
+ /* MSI-X Capability (0x68) - real TU104 puts the PCIe capability at
+ * 0x78, so the MSI-X cap lives at 0x68 (0x68-0x73). This matters:
+ * the driver's NV_PCFG mirror (BAR0+0x88000, mirror size 0x1000)
+ * is intercepted by vgpuDevReadReg032, which forwards a BAR0 read
+ * at 0x88000+off to PCI config space offset `off`
+ * (kbifGetPciConfigSpacePriMirror_GM107 = NV_PCFG = 0x88000). The
+ * driver reads NV_XVE_LINK_CAPABILITIES = 0x84 expecting the PCIe
+ * Link Capabilities register there, which is only true when the
+ * PCIe capability base is 0x78 (cap+0x0C = 0x84). */
+ cfg[0x68] = 0x11; /* Capability ID: MSI-X */
+ cfg[0x69] = 0x78; /* Next capability: PCI Express at 0x78 */
+ cfg[0x6a] = 0x1f; /* Table size = 31 (32 vectors), 64-bit */
+ cfg[0x6b] = 0x00;
+ /* Table Offset/BIR (0x6c) - Table at BAR0 offset 0x2000 */
+ cfg[0x6c] = 0x00;
+ cfg[0x6d] = 0x20;
+ cfg[0x6e] = 0x00;
+ cfg[0x6f] = 0x00;
+ /* PBA Offset/BIR (0x70) - PBA at BAR0 offset 0x3000 */
+ cfg[0x70] = 0x00;
+ cfg[0x71] = 0x30;
+ cfg[0x72] = 0x00;
cfg[0x73] = 0x00;
- /* Table Offset/BIR (0x74) - Table at BAR0 offset 0x2000 */
- cfg[0x74] = 0x00;
- cfg[0x75] = 0x20;
- cfg[0x76] = 0x00;
- cfg[0x77] = 0x00;
- /* PBA Offset/BIR (0x78) - PBA at BAR0 offset 0x3000 */
- cfg[0x78] = 0x00;
- cfg[0x79] = 0x30;
- cfg[0x7a] = 0x00;
- cfg[0x7b] = 0x00;
- /* PCI Express Capability (0x80) */
- cfg[0x80] = 0x10; /* Capability ID: PCI Express */
- cfg[0x81] = 0x00; /* Next capability: None */
- cfg[0x82] = 0x02; /* Device type: PCIe Endpoint, version 2 */
+ /* PCI Express Capability (0x78) - matches the real TU104 layout:
+ * cap+0x00 0x78 cap header, cap+0x04 0x7C Device Capabilities,
+ * cap+0x08 0x80 Device Control/Status,
+ * cap+0x0C 0x84 Link Capabilities <- NV_XVE_LINK_CAPABILITIES
+ * cap+0x10 0x88 Link Control/Status <- NV_XVE_LINK_CONTROL_STATUS
+ * Gen3 x16 (MAX_SPEED 3 = 8 GT/s, MAX_WIDTH 0x10 = x16), so UVM's
+ * getPCIELinkRateMBps -> calculatePCIELinkRateMBps succeeds. */
+ cfg[0x78] = 0x10; /* Capability ID: PCI Express */
+ cfg[0x79] = 0x00; /* Next capability: None (end of list) */
+ cfg[0x7a] = 0x02; /* Device type: PCIe Endpoint, version 2 */
+ cfg[0x7b] = 0x00;
+ cfg[0x7c] = 0x00; /* Device Capabilities */
+ cfg[0x7d] = 0x00;
+ cfg[0x7e] = 0x00;
+ cfg[0x7f] = 0x00;
+ cfg[0x80] = 0x00; /* Device Control */
+ cfg[0x81] = 0x00;
+ cfg[0x82] = 0x10; /* Device Status */
cfg[0x83] = 0x00;
- cfg[0x84] = 0x00; /* Device Capabilities */
- cfg[0x85] = 0x00;
+ cfg[0x84] = 0x03; /* Link Capabilities: MAX_SPEED 3:0 = 3 (8 GT/s) */
+ cfg[0x85] = 0x01; /* ... MAX_WIDTH 9:4 = 0x10 (x16) -> 0x103 */
cfg[0x86] = 0x00;
cfg[0x87] = 0x00;
- cfg[0x88] = 0x00; /* Device Control */
+ cfg[0x88] = 0x00; /* Link Control */
cfg[0x89] = 0x00;
- cfg[0x8a] = 0x10; /* Device Status */
- cfg[0x8b] = 0x00;
- cfg[0x8c] = 0x03; /* Link Capabilities: MAX_SPEED 3:0 = 3 (8 GT/s) */
- cfg[0x8d] = 0x01; /* ... MAX_WIDTH 9:4 = 0x10 (x16) -> 0x103 */
+ cfg[0x8a] = 0x03; /* Link Status: speed 3:0 = 3 (Gen3) */
+ cfg[0x8b] = 0x01; /* ... width 9:4 = 0x10 (x16) */
+ cfg[0x8c] = 0x00; /* Slot Capabilities */
+ cfg[0x8d] = 0x00;
cfg[0x8e] = 0x00;
cfg[0x8f] = 0x00;
- cfg[0x90] = 0x00; /* Link Control */
+ cfg[0x90] = 0x00; /* Slot Control */
cfg[0x91] = 0x00;
- cfg[0x92] = 0x03; /* Link Status: speed 3:0 = 3 (Gen3) */
- cfg[0x93] = 0x01; /* ... width 9:4 = 0x10 (x16) */
- cfg[0x94] = 0x00; /* Slot Capabilities */
+ cfg[0x92] = 0x00; /* Slot Status */
+ cfg[0x93] = 0x00;
+ cfg[0x94] = 0x00; /* Root Capabilities */
cfg[0x95] = 0x00;
- cfg[0x96] = 0x00;
+ cfg[0x96] = 0x00; /* Root Control */
cfg[0x97] = 0x00;
- cfg[0x98] = 0x00; /* Slot Control */
+ cfg[0x98] = 0x00; /* Root Status */
cfg[0x99] = 0x00;
- cfg[0x9a] = 0x00; /* Slot Status */
+ cfg[0x9a] = 0x00;
cfg[0x9b] = 0x00;
- cfg[0x9c] = 0x00; /* Root Capabilities */
+ cfg[0x9c] = 0x00; /* Device Capabilities 2 */
cfg[0x9d] = 0x00;
- cfg[0x9e] = 0x00; /* Root Control */
+ cfg[0x9e] = 0x00;
cfg[0x9f] = 0x00;
+ cfg[0xa0] = 0x00; /* Device Control 2 */
+ cfg[0xa1] = 0x00;
+ cfg[0xa2] = 0x00;
+ cfg[0xa3] = 0x00;
+ cfg[0xa4] = 0x00; /* Link Control 2 */
+ cfg[0xa5] = 0x00;
+ cfg[0xa6] = 0x00; /* Link Status 2 */
+ cfg[0xa7] = 0x00;
vgpu->config_space_dirty = false;
nv_vgpu_info(vgpu, "PCI config space initialized (vendor=0x%04x, device=0x%04x, subsys_vendor=0x%04x, subsys_device=0x%04x)", vendor_id, device_id, subsys_vendor, subsys_device);
+ nv_vgpu_info(vgpu, "PCIe cap: base=0x%02x hdr=%02x%02x%02x%02x devcap=%02x%02x%02x%02x devctl=%02x%02x linkcap=%02x%02x%02x%02x linkctl=%02x%02x linksta=%02x%02x",
+ cfg[0x78], cfg[0x78], cfg[0x79], cfg[0x7a], cfg[0x7b],
+ cfg[0x7c], cfg[0x7d], cfg[0x7e], cfg[0x7f],
+ cfg[0x80], cfg[0x81],
+ cfg[0x84], cfg[0x85], cfg[0x86], cfg[0x87],
+ cfg[0x88], cfg[0x89], cfg[0x8a], cfg[0x8b]);
return 0;
}
@@ -1797,24 +1839,26 @@ static ssize_t nv_vgpu_config_write(struct nv_vgpu_device *vgpu, const char __us
case 0x3c: /* Interrupt line */
vgpu->pci_config[pos] = val;
break;
- case 0x54: case 0x55: case 0x56: case 0x57: /* MSI Message Address Low */
- case 0x58: case 0x59: case 0x5a: case 0x5b: /* MSI Message Address High */
- case 0x5c: case 0x5d: /* MSI Message Data */
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* MSI Message Address Low */
+ case 0x50: case 0x51: case 0x52: case 0x53: /* MSI Message Address High */
+ case 0x54: case 0x55: /* MSI Message Data */
vgpu->pci_config[pos] = val;
break;
- case 0x72: case 0x73: /* MSI-X Message Control */
+ case 0x6a: case 0x6b: /* MSI-X Message Control */
vgpu->pci_config[pos] = val;
break;
- case 0x74: case 0x75: case 0x76: case 0x77: /* MSI-X Table Offset/BIR */
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f: /* MSI-X Table Offset/BIR */
vgpu->pci_config[pos] = val;
break;
- case 0x78: case 0x79: case 0x7a: case 0x7b: /* MSI-X PBA Offset/BIR */
+ case 0x70: case 0x71: case 0x72: case 0x73: /* 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 */
- case 0x9e: case 0x9f: /* Root Control */
+ case 0x80: case 0x81: /* Device Control */
+ case 0x88: case 0x89: /* Link Control */
+ case 0x90: case 0x91: /* Slot Control */
+ case 0x96: case 0x97: /* Root Control */
+ case 0xa0: case 0xa1: /* Device Control 2 */
+ case 0xa4: case 0xa5: /* Link Control 2 */
vgpu->pci_config[pos] = val;
break;
default: