diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-21 19:28:01 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-21 19:28:01 -0400 |
| commit | 8ddb13c9d96be05b859056788740330b5653e72b (patch) | |
| tree | 611b1f2913bf350120273d504f1bfc3808f9a220 /kernel | |
| parent | 6b686f70d8ff3e6340e8307c95847cd1eed4f2ae (diff) | |
| download | open-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.c | 170 | ||||
| -rw-r--r-- | kernel/gsp_rm_tu104.h | 11 |
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 { |
