From 7d6c789a469de154ee6d26a7fb9161ef7279a34a Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Wed, 23 Sep 2026 00:04:14 -0400 Subject: 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. --- kernel/main.c | 162 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 59 deletions(-) (limited to 'kernel/main.c') 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: -- cgit v1.2.3