summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 19:28:01 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-21 19:28:01 -0400
commit8ddb13c9d96be05b859056788740330b5653e72b (patch)
tree611b1f2913bf350120273d504f1bfc3808f9a220 /kernel
parent6b686f70d8ff3e6340e8307c95847cd1eed4f2ae (diff)
downloadopen-iov-8ddb13c9d96be05b859056788740330b5653e72b.tar.gz
open-iov-8ddb13c9d96be05b859056788740330b5653e72b.zip
kernel: GSP-RM handlers - NUM_CHANNELS/PCI_BAR_INFO/DISP_STATIC_INFO/DISP_IP_VERSION/I2C
- FIFO_GET_NUM_CHANNELS(0x20800a61)=64/runlist: zero tripped NV_ASSERT(numChannels>0), kdisp clientChannelTable alloc failed. - BUS_GET_PCI_BAR_INFO(0x20801803): report BAR0=16MB/BAR1=256MB/ BAR2=1MB instmem window@BAR0+0x700000/BAR3=32MB (was all zeros). - DISPLAY_GET_STATIC_INFO(0x20800a01): heads=1, numDispChannels=1 (36B wire layout; zero -> clientChannelTable[0] alloc failed). - DISPLAY_GET_IP_VERSION(0x20800a4b)=0x04000000 (Turing DISP v04.00; driver passes uninitialized input - must return a real version). - I2C_TRANSACTION(0x402c0105): echo request params + NOT_SUPPORTED. Variable-length FINN-serialized params: zeroed reply fails DeserializeUp and the calling ioctl never completes (nvidia-smi hang). - Default unknown-cmd policy back to zeroed params (echo is dangerous for queries with uninitialized input structs). Milestone: guest RmInitAdapter completed, /dev/nvidia0 created.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_rm_emulation.c170
-rw-r--r--kernel/gsp_rm_tu104.h11
2 files changed, 180 insertions, 1 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c
index 1ed63ab..4ce65ba 100644
--- a/kernel/gsp_rm_emulation.c
+++ b/kernel/gsp_rm_emulation.c
@@ -830,6 +830,132 @@ static void gsp_rm_handle_user_register_access_map(struct gsp_emu_context *ctx,
nv_vgpu_info(ctx->vgpu, "GSPRM: USER_REGISTER_ACCESS_MAP -> empty map");
}
+/*
+ * INTERNAL_FIFO_GET_NUM_CHANNELS (0x20800a61)
+ *
+ * The guest asks GSP-RM how many channels each runlist supports
+ * (kfifoRunlistQueryNumChannels). Returning 0 trips the driver's
+ * NV_ASSERT(numChannels > 0) and kdisp can't allocate its
+ * clientChannelTable. Report the consumer-Turing standard 64.
+ */
+static void gsp_rm_handle_fifo_get_num_channels(struct gsp_emu_context *ctx,
+ u32 sequence,
+ u32 *out_status,
+ u8 *out_params,
+ u32 *out_params_size)
+{
+ u32 val32;
+
+ /* params: runlistId(4, in) + numChannels(4, out) */
+ val32 = TU104_FIFO_NUM_CHANNELS_PER_RUNLIST;
+ memcpy(out_params + 4, &val32, 4);
+
+ *out_params_size = 8;
+ *out_status = 0;
+
+ nv_vgpu_info(ctx->vgpu, "GSPRM: FIFO_GET_NUM_CHANNELS -> %u", val32);
+}
+
+/*
+ * BUS_GET_PCI_BAR_INFO (0x20801803)
+ *
+ * The guest caches pciBarSizes[] from this call (kern_bus.c). Reporting
+ * zeros leaves BAR1/BAR2 aperture lengths at 0. Report our emulated BAR
+ * layout; index 2 is the instance-memory window convention
+ * (BAR0+0x700000, 1MB - gpuPhysInstAddr fallback when PCI BAR2 is absent).
+ */
+static void gsp_rm_handle_bus_get_pci_bar_info(struct gsp_emu_context *ctx,
+ u32 sequence,
+ u32 *out_status,
+ u8 *out_params,
+ u32 *out_params_size)
+{
+ struct nv_vgpu_device *vgpu = ctx->vgpu;
+ u32 count = 4;
+ u32 i;
+ u64 sizes[4];
+ u64 offsets[4];
+
+ sizes[0] = vgpu->bars[0].size; offsets[0] = vgpu->bars[0].gpa;
+ sizes[1] = vgpu->bars[1].size; offsets[1] = vgpu->bars[1].gpa;
+ sizes[2] = 0x100000; offsets[2] = vgpu->bars[0].gpa + 0x700000;
+ sizes[3] = vgpu->bars[3].size; offsets[3] = vgpu->bars[3].gpa;
+
+ memset(out_params, 0, 8 + 8 * 24);
+ memcpy(out_params + 0, &count, 4);
+
+ for (i = 0; i < count; i++) {
+ u8 *e = out_params + 8 + i * 24;
+ u32 flags = 0;
+ u32 barSizeMB = (u32)(sizes[i] >> 20);
+
+ memcpy(e + 0, &flags, 4);
+ memcpy(e + 4, &barSizeMB, 4);
+ memcpy(e + 8, &sizes[i], 8);
+ memcpy(e + 16, &offsets[i], 8);
+ }
+
+ *out_params_size = 8 + count * 24;
+ *out_status = 0;
+
+ nv_vgpu_info(ctx->vgpu, "GSPRM: BUS_GET_PCI_BAR_INFO -> %u BARs (BAR1=%uMB)",
+ count, (u32)(sizes[1] >> 20));
+}
+
+/*
+ * INTERNAL_DISPLAY_GET_STATIC_INFO (0x20800a01)
+ *
+ * kdispStateInitLocked caches numHeads/numDispChannels from this call and
+ * allocates clientChannelTable[numDispChannels] - a zero reply makes the
+ * allocation fail and kills RmInitNvDevice. The driver's wire struct is
+ * 36 bytes (observed paramsSize): feHwSysCap(0) windowPresentMask(4)
+ * bFbRemapperEnabled(8) numHeads(12) i2cPort(16) internalDispActiveMask(20)
+ * embeddedDisplayPortMask(24) muxSupported(28) numDispChannels(32).
+ * Report a minimal headless display: 1 head, 1 (core) channel.
+ */
+static void gsp_rm_handle_display_get_static_info(struct gsp_emu_context *ctx,
+ u32 sequence,
+ u32 *out_status,
+ u8 *out_params,
+ u32 *out_params_size)
+{
+ u32 val32;
+
+ memset(out_params, 0, 36);
+
+ val32 = 1; /* numHeads */
+ memcpy(out_params + 12, &val32, 4);
+ val32 = 1; /* numDispChannels (core channel) */
+ memcpy(out_params + 32, &val32, 4);
+
+ *out_params_size = 36;
+ *out_status = 0;
+
+ nv_vgpu_info(ctx->vgpu, "GSPRM: DISPLAY_GET_STATIC_INFO -> heads=1 dispChannels=1");
+}
+
+/*
+ * INTERNAL_DISPLAY_GET_IP_VERSION (0x20800a4b)
+ *
+ * kdispStatePreInitLocked passes an UNINITIALIZED ctrlParams and feeds the
+ * reply straight into gpuInitDispIpHal - it must be a real IP version.
+ * Turing display is DISP v04.00 (DispIpHal halspec idx 10).
+ */
+static void gsp_rm_handle_display_get_ip_version(struct gsp_emu_context *ctx,
+ u32 sequence,
+ u32 *out_status,
+ u8 *out_params,
+ u32 *out_params_size)
+{
+ u32 val32 = TU104_DISPLAY_IP_VERSION;
+
+ memcpy(out_params, &val32, 4);
+ *out_params_size = 4;
+ *out_status = 0;
+
+ nv_vgpu_info(ctx->vgpu, "GSPRM: DISPLAY_GET_IP_VERSION -> 0x%x", val32);
+}
+
static void gsp_rm_handle_rm_control(struct gsp_emu_context *ctx,
const u8 *elem, u32 sequence)
{
@@ -888,13 +1014,55 @@ 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_INTERNAL_FIFO_GET_NUM_CHANNELS:
+ gsp_rm_handle_fifo_get_num_channels(ctx, sequence,
+ &out_status,
+ reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size);
+ break;
+
+ case TU104_CTRL_BUS_GET_PCI_BAR_INFO:
+ gsp_rm_handle_bus_get_pci_bar_info(ctx, sequence,
+ &out_status,
+ reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size);
+ break;
+
+ case TU104_CTRL_INTERNAL_DISPLAY_GET_STATIC_INFO:
+ gsp_rm_handle_display_get_static_info(ctx, sequence,
+ &out_status,
+ reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size);
+ break;
+
+ case TU104_CTRL_INTERNAL_DISPLAY_GET_IP_VERSION:
+ gsp_rm_handle_display_get_ip_version(ctx, sequence,
+ &out_status,
+ reply + GSP_RM_CTRL_HDR_SIZE, &out_params_size);
+ break;
+
default:
- /* Unknown control command - return success with zeroed params */
+ /* Unknown control command - return success with zeroed params.
+ * Do NOT echo the request: pure queries pass uninitialized
+ * stack structs as input (e.g. DISPLAY_GET_IP_VERSION), so an
+ * echo hands the driver its own stack garbage as the answer. */
nv_vgpu_info(ctx->vgpu, "GSPRM: RM_CONTROL unknown cmd=0x%x -> generic SUCCESS",
req.cmd);
out_status = 0;
out_params_size = req.paramsSize;
break;
+
+ case TU104_CTRL_I2C_TRANSACTION:
+ /* I2C transactions have variable-length FINN-serialized
+ * params: an all-zero reply fails the driver's DeserializeUp
+ * and the calling ioctl never completes (nvidia-smi hang).
+ * Echo the request's serialized params (valid stream) and
+ * report NOT_SUPPORTED - headless vGPU has no DDC/I2C bus. */
+ nv_vgpu_info(ctx->vgpu, "GSPRM: I2C_TRANSACTION -> NOT_SUPPORTED (echo)");
+ out_status = 0x56; /* NV_ERR_NOT_SUPPORTED */
+ out_params_size = req.paramsSize;
+ if (req.paramsSize &&
+ req.paramsSize + GSP_RM_CTRL_HDR_SIZE <= GSPRM_MAX_SINGLE_ELEM_DATA)
+ memcpy(reply + GSP_RM_CTRL_HDR_SIZE,
+ req_data + GSP_RM_CTRL_HDR_SIZE, req.paramsSize);
+ break;
}
/* Build the reply header */
diff --git a/kernel/gsp_rm_tu104.h b/kernel/gsp_rm_tu104.h
index dc08b1d..ddd735f 100644
--- a/kernel/gsp_rm_tu104.h
+++ b/kernel/gsp_rm_tu104.h
@@ -677,6 +677,17 @@ static const struct tu104_internal_device_info tu104_internal_device_table[] = {
#define TU104_CTRL_FIFO_GET_DEVICE_INFO_TABLE 0x20801112
#define TU104_CTRL_INTERNAL_INTR_GET_KERNEL_TABLE 0x20800a5c
#define TU104_CTRL_GPU_GET_CONSTRUCTED_FALCON_INFO 0x208001b0
+#define TU104_CTRL_INTERNAL_FIFO_GET_NUM_CHANNELS 0x20800a61
+#define TU104_CTRL_BUS_GET_PCI_BAR_INFO 0x20801803
+#define TU104_CTRL_INTERNAL_DISPLAY_GET_STATIC_INFO 0x20800a01
+#define TU104_CTRL_INTERNAL_DISPLAY_GET_IP_VERSION 0x20800a4b
+#define TU104_CTRL_I2C_TRANSACTION 0x402c0105
+
+/* Turing display IP version (DISP v04.00 per DispIpHal halspec) */
+#define TU104_DISPLAY_IP_VERSION 0x04000000
+
+/* Channels per runlist reported to the guest (consumer Turing convention) */
+#define TU104_FIFO_NUM_CHANNELS_PER_RUNLIST 64
/* FB region info params: numFBRegions(4) + 16 × 48B entries = 772 → aligned 776 */
struct tu104_fb_region {