diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-23 01:26:25 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-23 01:26:25 -0400 |
| commit | 5367ffa2108fd9204d98f1cb23bb718a9143a25d (patch) | |
| tree | 53ad60ad65302ea0f307da9c40a9bae12cf77f83 | |
| parent | 841da7540f4397b0cac5f47537d2a39aca9ec3cf (diff) | |
| download | open-iov-archive/pre-squash.tar.gz open-iov-archive/pre-squash.zip | |
kernel: serve CE caps + CE->PCE masks (unblocks UVM channel manager)archive/pre-squash
kceGetDeviceCaps (kernel_ce.c) copies the caps the client hands to UVM from
NV2080_CTRL_CMD_CE_GET_PHYSICAL_CAPS (0x20802a07), which reaches GSP-RM and
was answered with zeros. With capsTbl = {0,0} no CE had the SYSMEM bit, so
UVM's channel manager found no usable CE and UVM_REGISTER_GPU failed with
NV_ERR_NOT_SUPPORTED ("Failed to initialize the channel manager",
uvm_gpu.c:1574 - visible with uvm_debug_prints=1).
New handlers:
- CE_GET_PHYSICAL_CAPS (0x20802a07): {ceEngineType, capsTbl[2]} with
SYSMEM_READ|SYSMEM_WRITE|SYSMEM|P2P|BL_GT_64K (0xEC) for COPY0..COPY4,
NOT_SUPPORTED otherwise (matches subdeviceCtrlCmdCeGetCaps_IMPL).
- CE_GET_ALL_CAPS (0x20802a0a) / CE_GET_ALL_PHYSICAL_CAPS (0x20802a0b):
capsTbl[64][2] + present bitmap with the five CEs.
- CE_GET_CE_PCE_MASK (0x20802a02): pceMask = BIT(ceIdx) (one PCE per LCE).
Verified in-guest progress: UVM now gets past the channel manager and
creates channels; the register path's new blocker is the first channel
push (channel_init, uvm_channel.c:2535) whose semaphore release the
emulated GPU must complete ("Tracker entry ... stuck waiting for 90s",
sema VA 0x121000000 on channel 1:3 CE 0).
| -rw-r--r-- | kernel/gsp_rm_emulation.c | 126 | ||||
| -rw-r--r-- | kernel/gsp_rm_tu104.h | 21 | ||||
| -rw-r--r-- | tools/guest-diag/guest_engines.c | 34 | ||||
| -rwxr-xr-x | tools/guest-diag/launch_qemu_rootport.run.sh | 2 |
4 files changed, 181 insertions, 2 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index c2b306a..e5c79f1 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -1065,6 +1065,111 @@ static void gsp_rm_handle_ce_get_fault_method_buffer_size( } /* + * CE_GET_PHYSICAL_CAPS (0x20802a07) and friends + * + * kceGetDeviceCaps (kernel_ce.c) fills the CE caps the client hands to UVM + * from NV2080_CTRL_CMD_CE_GET_PHYSICAL_CAPS, which reaches GSP-RM. UVM's + * channel manager rejects any CE without the SYSMEM cap for its + * CPU_TO_GPU/GPU_TO_CPU channels ("Failed to initialize the channel manager: + * NV_ERR_NOT_SUPPORTED" in uvm_gpu.c) -- with the previous zeroed reply every + * CE was unusable and UVM_REGISTER_GPU failed with 0x56. + * + * params: { ceEngineType(4), capsTbl[2] } (NV2080_CTRL_CE_GET_CAPS_V2_PARAMS + * layout). Turing LCEs are sysmem-capable, P2P-capable and not GRCE. + */ +static void gsp_rm_handle_ce_physical_caps(struct gsp_emu_context *ctx, + const u8 *req_params, u32 req_size, + u32 *out_status, u8 *out_params, + u32 *out_params_size) +{ + u32 ce_type = 0; + + if (req_size >= 4) + memcpy(&ce_type, req_params, 4); + + memset(out_params, 0, 8); + memcpy(out_params + 0, &ce_type, 4); + + if (ce_type >= TU104_ENGINE_TYPE_COPY0 && + ce_type < TU104_ENGINE_TYPE_COPY0 + TU104_NUM_CES) { + out_params[4] = TU104_CE_CAPS0; + out_params[5] = TU104_CE_CAPS1; + } else { + *out_status = 0x56; /* NV_ERR_NOT_SUPPORTED */ + *out_params_size = req_size; + nv_vgpu_info(ctx->vgpu, "GSPRM: CE_GET_PHYSICAL_CAPS type=0x%x -> NOT_SUPPORTED", + ce_type); + return; + } + + *out_params_size = req_size ? req_size : 8; + *out_status = 0; + + nv_vgpu_info(ctx->vgpu, "GSPRM: CE_GET_PHYSICAL_CAPS type=0x%x -> caps=%02x %02x", + ce_type, out_params[4], out_params[5]); +} + +/* + * CE_GET_ALL_PHYSICAL_CAPS (0x20802a0b) / CE_GET_ALL_CAPS (0x20802a0a) + * + * params: NvU8 capsTbl[64][2] + NvU64 present (136 bytes). Report the five + * Turing CEs as present with the same caps as the per-CE query. + */ +static void gsp_rm_handle_ce_all_caps(struct gsp_emu_context *ctx, + u32 *out_status, u8 *out_params, + u32 *out_params_size) +{ + u64 present = 0; + u32 i; + + memset(out_params, 0, 136); + for (i = 0; i < TU104_NUM_CES; i++) { + out_params[i * 2 + 0] = TU104_CE_CAPS0; + out_params[i * 2 + 1] = TU104_CE_CAPS1; + present |= 1ULL << i; + } + memcpy(out_params + 128, &present, 8); + + *out_params_size = 136; + *out_status = 0; + + nv_vgpu_info(ctx->vgpu, "GSPRM: CE_GET_ALL(_PHYSICAL)_CAPS -> %u CEs present=0x%llx", + TU104_NUM_CES, present); +} + +/* + * CE_GET_CE_PCE_MASK (0x20802a02) + * + * params: { ceEngineType(4), pceMask(4) }. Each Turing LCE has its own PCE, + * so every CE maps to exactly one PCE bit. UVM's queryCopyEngines stores this + * in UvmGpuCopyEngineCaps.cePceMask. + */ +static void gsp_rm_handle_ce_pce_mask(struct gsp_emu_context *ctx, + const u8 *req_params, u32 req_size, + u32 *out_status, u8 *out_params, + u32 *out_params_size) +{ + u32 ce_type = 0, mask = 0; + + if (req_size >= 4) + memcpy(&ce_type, req_params, 4); + + if (ce_type >= TU104_ENGINE_TYPE_COPY0 && + ce_type < TU104_ENGINE_TYPE_COPY0 + TU104_NUM_CES) + mask = 1u << (ce_type - TU104_ENGINE_TYPE_COPY0); + + memset(out_params, 0, 8); + memcpy(out_params + 0, &ce_type, 4); + memcpy(out_params + 4, &mask, 4); + + *out_params_size = req_size ? req_size : 8; + *out_status = 0; + + nv_vgpu_info(ctx->vgpu, "GSPRM: CE_GET_CE_PCE_MASK type=0x%x -> 0x%x", + ce_type, mask); +} + +/* * INTERNAL_GMMU_GET_STATIC_INFO (0x20800a59) * * The guest asks GSP-RM (us) for the GMMU static info; kgmmu. pStaticInfo-> @@ -1582,6 +1687,27 @@ static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx, reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); break; + case TU104_CTRL_CE_GET_PHYSICAL_CAPS: + gsp_rm_handle_ce_physical_caps(ctx, + req_data + GSP_RM_CTRL_HDR_SIZE, req.paramsSize, + &out_status, + reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); + break; + + case TU104_CTRL_CE_GET_CE_PCE_MASK: + gsp_rm_handle_ce_pce_mask(ctx, + req_data + GSP_RM_CTRL_HDR_SIZE, req.paramsSize, + &out_status, + reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); + break; + + case TU104_CTRL_CE_GET_ALL_CAPS: + case TU104_CTRL_CE_GET_ALL_PHYSICAL_CAPS: + gsp_rm_handle_ce_all_caps(ctx, + &out_status, + reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size); + break; + case TU104_CTRL_INTERNAL_GMMU_GET_STATIC_INFO: gsp_rm_handle_gmmu_get_static_info(ctx, sequence, &out_status, diff --git a/kernel/gsp_rm_tu104.h b/kernel/gsp_rm_tu104.h index ab97307..9fd0443 100644 --- a/kernel/gsp_rm_tu104.h +++ b/kernel/gsp_rm_tu104.h @@ -700,6 +700,27 @@ static const struct tu104_internal_device_info tu104_internal_device_table[] = { #define TU104_CTRL_INTERNAL_DISPLAY_GET_IP_VERSION 0x20800a4b #define TU104_CTRL_I2C_TRANSACTION 0x402c0105 #define TU104_CTRL_CE_GET_FAULT_METHOD_BUFFER_SIZE 0x20802a08 +#define TU104_CTRL_CE_GET_PHYSICAL_CAPS 0x20802a07 +#define TU104_CTRL_CE_GET_ALL_PHYSICAL_CAPS 0x20802a0b +#define TU104_CTRL_CE_GET_ALL_CAPS 0x20802a0a +#define TU104_CTRL_CE_GET_CE_PCE_MASK 0x20802a02 + +/* CE capability bits (NV2080_CTRL_CE_CAPS_*, ctrl2080ce.h: byte:bit) */ +#define TU104_CE_CAPS0_SYSMEM_READ 0x04 +#define TU104_CE_CAPS0_SYSMEM_WRITE 0x08 +#define TU104_CE_CAPS0_SYSMEM 0x20 +#define TU104_CE_CAPS0_P2P 0x40 +#define TU104_CE_CAPS0_BL_GT_64K 0x80 +#define TU104_CE_CAPS0 (TU104_CE_CAPS0_SYSMEM_READ | \ + TU104_CE_CAPS0_SYSMEM_WRITE | \ + TU104_CE_CAPS0_SYSMEM | \ + TU104_CE_CAPS0_P2P | \ + TU104_CE_CAPS0_BL_GT_64K) +#define TU104_CE_CAPS1 0x00 + +/* ENGINE_TYPE_COPY0 = 0x9, COPY(i) = COPY0 + i (cl2080_notification.h) */ +#define TU104_ENGINE_TYPE_COPY0 0x00000009 +#define TU104_NUM_CES 5 #define TU104_CTRL_INTERNAL_GMMU_GET_STATIC_INFO 0x20800a59 #define TU104_CTRL_STATIC_KGR_GET_GLOBAL_SM_ORDER 0x20800a22 #define TU104_CTRL_STATIC_KGR_GET_INFO 0x20800a2a diff --git a/tools/guest-diag/guest_engines.c b/tools/guest-diag/guest_engines.c index 066eec6..10209e2 100644 --- a/tools/guest-diag/guest_engines.c +++ b/tools/guest-diag/guest_engines.c @@ -11,6 +11,7 @@ #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> +#include <stdlib.h> typedef uint32_t NvU32; typedef uint32_t NvHandle; @@ -20,6 +21,7 @@ typedef uint64_t NvP64; #define NV_ESC_RM_ALLOC 0x2B #define NV_ESC_RM_CONTROL 0x2A #define NV01_ROOT 0x0 +#define NV01_ROOT_CLIENT 0x41 #define NV01_DEVICE_0 0x80 #define NV20_SUBDEVICE_0 0x2080 @@ -97,7 +99,7 @@ int main(void) fd = open("/dev/nvidiactl", O_RDWR | O_CLOEXEC); if (fd < 0) { perror("open nvidiactl"); return 1; } - st = rm_alloc(0, 0, NV01_ROOT, &hClient); + st = rm_alloc(0, 0, getenv("RC") ? NV01_ROOT_CLIENT : NV01_ROOT, &hClient); printf("alloc client: st=0x%x hClient=0x%x\n", st, hClient); st = rm_alloc64(hClient, hClient, NV01_DEVICE_0, &hDevice); @@ -156,5 +158,35 @@ int main(void) printf(" CE_GET_CAPS_V2(type=0x%x): st=0x%x caps=%02x %02x\n", t, st, cc.caps[0], cc.caps[1]); } } + if (hSubdevice) { + struct { + NvU32 engineData[16]; + NvU32 pbdmaIds[2]; + NvU32 pbdmaFaultIds[2]; + NvU32 numPbdmas; + char engineName[16]; + } e[32]; + struct { + NvU32 baseIndex, numEntries, bMore; + typeof(e) entries; + } t; + int i, j; + NvU32 base = 0; + memset(&t, 0, sizeof(t)); + do { + t.baseIndex = base; + st = rm_control(hClient, hSubdevice, 0x20801112, &t, sizeof(t)); + if (st) { printf("FIFO_GET_DEVICE_INFO_TABLE: st=0x%x\n", st); break; } + for (i = 0; i < (int)t.numEntries; i++) { + printf(" [%2u] %-8s numPbdmas=%u pbdmaIds=[%u,%u] engineData=[", + base + i, t.entries[i].engineName, t.entries[i].numPbdmas, + t.entries[i].pbdmaIds[0], t.entries[i].pbdmaIds[1]); + for (j = 0; j < 16; j++) + printf("%s%u", j ? "," : "", t.entries[i].engineData[j]); + printf("]\n"); + } + base += t.numEntries; + } while (t.bMore); + } return 0; } diff --git a/tools/guest-diag/launch_qemu_rootport.run.sh b/tools/guest-diag/launch_qemu_rootport.run.sh index 69663f7..2a7ae63 100755 --- a/tools/guest-diag/launch_qemu_rootport.run.sh +++ b/tools/guest-diag/launch_qemu_rootport.run.sh @@ -1,2 +1,2 @@ #!/bin/bash -exec /bin/qemu-system-x86_64 -D /home/rmcore/.local/libvf.io/logs/qemu/e726ba0b-204f-4ec9-91da-983ed7f41d06-session.txt -no-hpet -mem-prealloc -qmp unix:/tmp/qemu-qmp.sock,server,nowait -chardev socket,path=/tmp/qemu-guest-agent.sock,server=on,wait=off,id=qga0 -device virtio-serial-pci -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 -serial file:/tmp/vgpu-guest-serial.log -gdb tcp::1234 -display none -device ivshmem-plain,id=shmem0,memdev=ivshmem_kvmfr -object memory-backend-file,id=ivshmem_kvmfr,mem-path=/dev/shm/kvmfr-e726ba0b-204f-4ec9-91da-983ed7f41d06,size=128M,share=yes -device ivshmem-plain,id=shmem1,memdev=ivshmem_kvmsr -object memory-backend-file,id=ivshmem_kvmsr,mem-path=/dev/shm/kvmsr-e726ba0b-204f-4ec9-91da-983ed7f41d06,size=2M,share=yes -uuid e726ba0b-204f-4ec9-91da-983ed7f41d06 -machine pc-q35-4.2,accel=kvm,usb=off,vmport=off,dump-guest-core=off -cpu host,ss=on,vmx=on,pcid=on,hypervisor=on,arat=on,tsc-adjust=on,umip=on,md-clear=on,stibp=on,arch-capabilities=on,ssbd=on,xsaveopt=on,pdpe1gb=on,ibpb=on,amd-stibp=on,amd-ssbd=on,skip-l1dfl-vmentry=on,pschange-mc-no=on,hv-vapic,hv_time,hv-spinlocks=0x1fff,hv-vendor-id=null,kvm=on,topoext=on -rtc clock=host,base=localtime -m 4096 -smp cores=4,threads=1,sockets=1 -hda /home/rmcore/.local/libvf.io/kernel/linux.qcow2 --enable-kvm -device pcie-root-port,id=rp0,chassis=1,slot=30,bus=pcie.0 -device vfio-pci,id=hostdev0,bus=rp0,sysfsdev=/sys/bus/mdev/devices/b2e19ccf-87bb-4761-b634-9a8e8d218c89,display=off -device rtl8139,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 -net user -net nic -device vhost-vsock-pci,guest-cid=50718 -qmp unix:/tmp/sockets/e726ba0b-204f-4ec9-91da-983ed7f41d06/main.sock,server,nowait -qmp unix:/tmp/sockets/e726ba0b-204f-4ec9-91da-983ed7f41d06/master.sock,server,nowait +exec /bin/qemu-system-x86_64 -D /home/rmcore/.local/libvf.io/logs/qemu/e726ba0b-204f-4ec9-91da-983ed7f41d06-session.txt -no-hpet -mem-prealloc -qmp unix:/tmp/qemu-qmp.sock,server,nowait -chardev socket,path=/tmp/qemu-guest-agent.sock,server=on,wait=off,id=qga0 -device virtio-serial-pci -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 -serial file:/tmp/vgpu-guest-serial.log -gdb tcp::1234 -display none -device ivshmem-plain,id=shmem0,memdev=ivshmem_kvmfr -object memory-backend-file,id=ivshmem_kvmfr,mem-path=/dev/shm/kvmfr-e726ba0b-204f-4ec9-91da-983ed7f41d06,size=128M,share=yes -device ivshmem-plain,id=shmem1,memdev=ivshmem_kvmsr -object memory-backend-file,id=ivshmem_kvmsr,mem-path=/dev/shm/kvmsr-e726ba0b-204f-4ec9-91da-983ed7f41d06,size=2M,share=yes -uuid e726ba0b-204f-4ec9-91da-983ed7f41d06 -machine pc-q35-4.2,accel=kvm,usb=off,vmport=off,dump-guest-core=off -cpu host,ss=on,vmx=on,pcid=on,hypervisor=on,arat=on,tsc-adjust=on,umip=on,md-clear=on,stibp=on,arch-capabilities=on,ssbd=on,xsaveopt=on,pdpe1gb=on,ibpb=on,amd-stibp=on,amd-ssbd=on,skip-l1dfl-vmentry=on,pschange-mc-no=on,hv-vapic,hv_time,hv-spinlocks=0x1fff,hv-vendor-id=null,kvm=on,topoext=on -rtc clock=host,base=localtime -m 4096 -smp cores=4,threads=1,sockets=1 -hda /home/rmcore/.local/libvf.io/kernel/linux.qcow2 --enable-kvm -device pcie-root-port,id=rp0,chassis=1,slot=30,bus=pcie.0 -device vfio-pci,id=hostdev0,bus=rp0,sysfsdev=/sys/bus/mdev/devices/8421beba-9e66-4718-bd78-c8ed24b72ef8,display=off -device rtl8139,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 -net user -net nic -device vhost-vsock-pci,guest-cid=50718 -qmp unix:/tmp/sockets/e726ba0b-204f-4ec9-91da-983ed7f41d06/main.sock,server,nowait -qmp unix:/tmp/sockets/e726ba0b-204f-4ec9-91da-983ed7f41d06/master.sock,server,nowait |
