summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_rm_emulation.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_rm_emulation.c')
-rw-r--r--kernel/gsp_rm_emulation.c59
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);