summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 01:26:25 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-23 01:26:25 -0400
commit5367ffa2108fd9204d98f1cb23bb718a9143a25d (patch)
tree53ad60ad65302ea0f307da9c40a9bae12cf77f83 /kernel
parent841da7540f4397b0cac5f47537d2a39aca9ec3cf (diff)
downloadopen-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).
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_rm_emulation.c126
-rw-r--r--kernel/gsp_rm_tu104.h21
2 files changed, 147 insertions, 0 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