diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-23 14:03:27 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-23 14:03:27 -0400 |
| commit | 2a59dcb768541b759ada9cd6f24986e2c234bd37 (patch) | |
| tree | 862bedd8078b64871e34ece655d627dc7ba3dccd /kernel/gsp_rm_emulation.c | |
| parent | fade84f8b5b781d29daad40699d07928dedea550 (diff) | |
| download | open-iov-2a59dcb768541b759ada9cd6f24986e2c234bd37.tar.gz open-iov-2a59dcb768541b759ada9cd6f24986e2c234bd37.zip | |
kernel: track channels and execute host-class pushed work
The guest's CUDA stack was stuck inside context creation because the work it
submits is never executed by the emulated GPU. Two forms of pushed work were
missing, and the completion path had grown far too slow to be useful:
- Channel tracking: on a channel allocation parse the GPFIFO GPU VA and entry
count, the USERD address/aperture and the instance block, hand them to the
progress service and drop them again when the channel is freed.
- Host-class (C46F) semaphore releases: pushes on a compute channel signal
progress with a five-dword method run (SEM_ADDR_LO/HI, PAYLOAD_LO/HI,
EXECUTE) rather than the copy-engine group the service already understood,
so those releases were never applied. Decode both forms.
- Emulated vidmem: channel blocks (USERD/instance) and some client semaphores
live in the emulated frame buffer, whose VAs are a window over the BAR1
backing rather than guest RAM; access them through the right aperture.
- Latency: the service's full-RAM sweep took seconds per pass, so guests'
progress waits took whole seconds and the driver tore its own setup back
down in the meantime. Sweep guest RAM in bounded, chunked windows on every
pass, remember the pages pushes are actually found in and revisit those
first, and keep the VA->PA map complete (dedup, sort, binary search) so
semaphores resolve reliably.
Also add a vidmem poke parameter for bringing up and debugging emulated
frame-buffer state.
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
| -rw-r--r-- | kernel/gsp_rm_emulation.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/kernel/gsp_rm_emulation.c b/kernel/gsp_rm_emulation.c index 44de6c0..a21cf28 100644 --- a/kernel/gsp_rm_emulation.c +++ b/kernel/gsp_rm_emulation.c @@ -15,6 +15,7 @@ #include "gsp_emulation.h" #include "gsp_rm_emulation.h" #include "gsp_rm_tu104.h" +#include "gsp_sema_service.h" /* ============================================================ * Guest-memory access ("virtual DMA" on behalf of the device) @@ -1925,6 +1926,57 @@ static void gsp_rm_handle_copy_server_pdes(struct gsp_emu_context *ctx, static bool gsp_rm_alloc_interesting(u32 class_id); /* + * Channel (GPFIFO) classes across generations. Their allocation parameters + * carry the GPFIFO GPU VA/entry count and the guest-physical USERD/instance + * blocks, which is what the emulated-GPU progress service needs to run the + * work the guest submits on the channel. + */ +static bool gsp_rm_is_channel_class(u32 class_id) +{ + switch (class_id) { + case 0x906f: /* MAXWELL_CHANNEL_GPFIFO_A */ + case 0xa06f: /* KEPLER_CHANNEL_GPFIFO_A */ + case 0xb06f: /* PASCAL_CHANNEL_GPFIFO_A */ + case 0xc06f: /* VOLTA_CHANNEL_GPFIFO_A */ + case 0xc46f: /* TURING_CHANNEL_GPFIFO_A */ + return true; + default: + return false; + } +} + +/* NV_CHANNEL_ALLOC_PARAMS offsets (alloc/alloc_channel.h) */ +#define GSPRM_CHAN_GPFIFO_OFFSET 8 +#define GSPRM_CHAN_GPFIFO_ENTRIES 16 +#define GSPRM_CHAN_ENGINE_TYPE 128 +#define GSPRM_CHAN_INSTANCE_MEM 144 +#define GSPRM_CHAN_USERD_MEM 168 +#define GSPRM_CHAN_MEM_APERTURE 16 /* offset of addressSpace in the desc */ +#define GSPRM_CHAN_NOTIFIER_MEM 248 + +static void gsp_rm_register_channel(struct gsp_emu_context *ctx, u32 h_object, + const u8 *params, u32 params_size) +{ + struct sema_channel_desc desc; + + if (params_size < GSPRM_CHAN_NOTIFIER_MEM + 8) + return; + + memset(&desc, 0, sizeof(desc)); + desc.h_object = h_object; + memcpy(&desc.gpfifo_va, params + GSPRM_CHAN_GPFIFO_OFFSET, 8); + memcpy(&desc.gpfifo_entries, params + GSPRM_CHAN_GPFIFO_ENTRIES, 4); + memcpy(&desc.engine_type, params + GSPRM_CHAN_ENGINE_TYPE, 4); + memcpy(&desc.instance_pa, params + GSPRM_CHAN_INSTANCE_MEM, 8); + memcpy(&desc.userd_pa, params + GSPRM_CHAN_USERD_MEM, 8); + memcpy(&desc.userd_as, params + GSPRM_CHAN_USERD_MEM + + GSPRM_CHAN_MEM_APERTURE, 4); + memcpy(&desc.notifier_pa, params + GSPRM_CHAN_NOTIFIER_MEM, 8); + + gsp_sema_service_channel_add(&desc); +} + +/* * GSP_RM_ALLOC (103) - rpc_gsp_rm_alloc_v03_00 (32 byte header) followed by * the class-specific allocation parameters. * @@ -1981,6 +2033,11 @@ static void gsp_rm_handle_rm_alloc(struct gsp_emu_context *ctx, } } + /* Channels: hand the progress service everything it needs to run the + * work submitted on this channel (GPFIFO ring + USERD). */ + if (gsp_rm_is_channel_class(class_id)) + gsp_rm_register_channel(ctx, ho, params, params_size); + /* Echo the fixed alloc header + as many param bytes as are contiguous * in the first queue element. */ echo_len = min(params_size, @@ -2244,6 +2301,8 @@ static void gsp_rm_handle_free(struct gsp_emu_context *ctx, const u8 *elem, memcpy(&hObjOld, params + 8, 4); memset(params + 12, 0, 4); /* status = NV_OK */ + gsp_sema_service_channel_del(hObjOld); + nv_vgpu_info(ctx->vgpu, "GSPRM: FREE hObjOld=0x%x seq=%u cmd_read=%u stat_write=%u", hObjOld, sequence, rm->cmd_read, rm->stat_write); |
