@@ -42,4 +42,10 @@ union nvif_chan_event_args {
__u8 type;
} v0;
};
+
+#define NVIF_CHAN_MTHD_SET_ZCULL_CTXSW_BUFFER 0x00000000
+
+struct nvif_chan_mthd_set_zcull_ctxsw_buffer {
+ u64 addr;
+};
#endif
@@ -9,6 +9,7 @@ struct nvkm_gr {
};
u64 nvkm_gr_units(struct nvkm_gr *);
+int nvkm_gr_set_zcull_ctxsw_buffer(struct nvkm_gr *gr, struct nvkm_chan *chan, u64 addr);
int nvkm_gr_tlb_flush(struct nvkm_gr *);
int nvkm_gr_ctxsw_pause(struct nvkm_device *);
int nvkm_gr_ctxsw_resume(struct nvkm_device *);
@@ -26,6 +26,11 @@
* DEALINGS IN THE SOFTWARE.
*/
+/* valid zcullMode values */
+#define NV2080_CTRL_CTXSW_ZCULL_MODE_GLOBAL (0x00000000U)
+#define NV2080_CTRL_CTXSW_ZCULL_MODE_NO_CTXSW (0x00000001U)
+#define NV2080_CTRL_CTXSW_ZCULL_MODE_SEPARATE_BUFFER (0x00000002U)
+
/**
* NV2080_CTRL_CMD_GR_GET_ZCULL_INFO
*
@@ -95,6 +100,54 @@ typedef struct NV2080_CTRL_GR_GET_ZCULL_INFO_PARAMS {
NvU32 subregionHeightAlignPixels;
} NV2080_CTRL_GR_GET_ZCULL_INFO_PARAMS;
+
+/*
+ * NV2080_CTRL_CMD_GR_CTXSW_ZCULL_BIND
+ *
+ * This command is used to set the zcull context switch mode and virtual address
+ * for the specified channel. A value of NV_ERR_NOT_SUPPORTED is
+ * returned if the target channel does not support zcull context switch mode
+ * changes.
+ *
+ * hClient
+ * This parameter specifies the client handle of
+ * that owns the zcull context buffer. This field must match
+ * the hClient used in the control call for non-kernel clients.
+ * hChannel
+ * This parameter specifies the channel handle of
+ * the channel that is to have its zcull context switch mode changed.
+ * vMemPtr
+ * This parameter specifies the 64 bit virtual address
+ * for the allocated zcull context buffer.
+ * zcullMode
+ * This parameter specifies the new zcull context switch mode.
+ * Legal values for this parameter include:
+ * NV2080_CTRL_GR_SET_CTXSW_ZCULL_MODE_GLOBAL
+ * This mode is the normal zcull operation where it is not
+ * context switched and there is one set of globally shared
+ * zcull memory and tables. This mode is only supported as
+ * long as all channels use this mode.
+ * NV2080_CTRL_GR_SET_CTXSW_ZCULL_MODE_NO_CTXSW
+ * This mode causes the zcull tables to be reset on a context
+ * switch, but the zcull buffer will not be saved/restored.
+ * NV2080_CTRL_GR_SET_CTXSW_ZCULL_MODE_SEPARATE_BUFFER
+ * This mode will cause the zcull buffers and tables to be
+ * saved/restored on context switches. If a share channel
+ * ID is given (shareChID), then the 2 channels will share
+ * the zcull context buffers.
+ */
+#define NV2080_CTRL_CMD_GR_CTXSW_ZCULL_BIND (0x20801208U) /* finn: Evaluated from "(FINN_NV20_SUBDEVICE_0_GR_INTERFACE_ID << 8) | NV2080_CTRL_GR_CTXSW_ZCULL_BIND_PARAMS_MESSAGE_ID" */
+
+#define NV2080_CTRL_GR_CTXSW_ZCULL_BIND_PARAMS_MESSAGE_ID (0x8U)
+
+typedef struct NV2080_CTRL_GR_CTXSW_ZCULL_BIND_PARAMS {
+ NvHandle hClient;
+ NvHandle hChannel;
+ NV_DECLARE_ALIGNED(NvU64 vMemPtr, 8);
+ NvU32 zcullMode;
+} NV2080_CTRL_GR_CTXSW_ZCULL_BIND_PARAMS;
+/* valid zcullMode values same as above NV2080_CTRL_CTXSW_ZCULL_MODE */
+
typedef enum NV2080_CTRL_CMD_GR_CTXSW_PREEMPTION_BIND_BUFFERS {
NV2080_CTRL_CMD_GR_CTXSW_PREEMPTION_BIND_BUFFERS_MAIN = 0,
NV2080_CTRL_CMD_GR_CTXSW_PREEMPTION_BIND_BUFFERS_SPILL = 1,
@@ -27,6 +27,7 @@
#include <nvif/ioctl.h>
#include <nvif/class.h>
#include <nvif/cl0002.h>
+#include <nvif/if0020.h>
#include <nvif/unpack.h>
#include "nouveau_drv.h"
@@ -348,6 +349,51 @@ nouveau_abi16_ioctl_get_zcull_info(ABI16_IOCTL_ARGS)
}
}
+int
+nouveau_abi16_ioctl_set_zcull_ctxsw_buffer(ABI16_IOCTL_ARGS)
+{
+ struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
+ struct nouveau_abi16_chan *chan16;
+ struct nouveau_channel *chan = NULL;
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct nvkm_device *device = drm->nvkm;
+ struct drm_nouveau_set_zcull_ctxsw_buffer *req = data;
+ int ret = 0;
+
+ if (unlikely(!device->has_zcull_info))
+ return nouveau_abi16_put(abi16, -ENODEV);
+
+ if (unlikely(req->pad))
+ return nouveau_abi16_put(abi16, -EINVAL);
+
+ if (unlikely(!abi16))
+ return nouveau_abi16_put(abi16, -ENOMEM);
+
+ /* abi16 locks already */
+ list_for_each_entry(chan16, &abi16->channels, head) {
+ if (chan16->chan->chid == req->channel) {
+ chan = chan16->chan;
+ break;
+ }
+ }
+
+ if (!chan)
+ return nouveau_abi16_put(abi16, -ENOENT);
+
+ if (unlikely(atomic_read(&chan->killed)))
+ return nouveau_abi16_put(abi16, -ENODEV);
+
+ struct nvif_chan_mthd_set_zcull_ctxsw_buffer args = {
+ .addr = req->addr,
+ };
+
+ ret = nvif_mthd(&chan->user, NVIF_CHAN_MTHD_SET_ZCULL_CTXSW_BUFFER,
+ &args, sizeof(args));
+
+ return nouveau_abi16_put(abi16, ret);
+}
+
+
int
nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
{
@@ -7,6 +7,7 @@
int nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_get_zcull_info(ABI16_IOCTL_ARGS);
+int nouveau_abi16_ioctl_set_zcull_ctxsw_buffer(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS);
int nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS);
@@ -1245,6 +1245,7 @@ nouveau_ioctls[] = {
DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_abi16_ioctl_notifierobj_alloc, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_abi16_ioctl_gpuobj_free, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_GET_ZCULL_INFO, nouveau_abi16_ioctl_get_zcull_info, DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(NOUVEAU_SET_ZCULL_CTXSW_BUFFER, nouveau_abi16_ioctl_set_zcull_ctxsw_buffer, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_INIT, nouveau_svmm_init, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_SVM_BIND, nouveau_svmm_bind, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_RENDER_ALLOW),
@@ -345,6 +345,14 @@ nvkm_chan_get_chid(struct nvkm_engine *engine, int id, unsigned long *pirqflags)
return NULL;
}
+int
+nvkm_chan_set_zcull_ctxsw_buffer(struct nvkm_chan *chan, u64 addr)
+{
+ if (chan->func->set_zcull_ctxsw_buffer)
+ return chan->func->set_zcull_ctxsw_buffer(chan, addr);
+ return -ENODEV;
+}
+
int
nvkm_chan_new_(const struct nvkm_chan_func *func, struct nvkm_runl *runl, int runq,
struct nvkm_cgrp *cgrp, const char *name, bool priv, u32 devm, struct nvkm_vmm *vmm,
@@ -54,6 +54,7 @@ struct nvkm_chan_func {
void (*stop)(struct nvkm_chan *);
void (*preempt)(struct nvkm_chan *);
u32 (*doorbell_handle)(struct nvkm_chan *);
+ int (*set_zcull_ctxsw_buffer)(struct nvkm_chan *, u64 addr);
};
int nvkm_chan_new_(const struct nvkm_chan_func *, struct nvkm_runl *, int runq, struct nvkm_cgrp *,
@@ -73,6 +74,7 @@ int nvkm_chan_cctx_get(struct nvkm_chan *, struct nvkm_engn *, struct nvkm_cctx
struct nvkm_client * /*TODO: remove need for this */);
void nvkm_chan_cctx_put(struct nvkm_chan *, struct nvkm_cctx **);
void nvkm_chan_cctx_bind(struct nvkm_chan *, struct nvkm_engn *, struct nvkm_cctx *);
+int nvkm_chan_set_zcull_ctxsw_buffer(struct nvkm_chan *chan, u64 addr);
#define CHAN_PRCLI(c,l,p,f,a...) CGRP_PRINT((c)->cgrp, l, p, "%04x:[%s]"f, (c)->id, (c)->name, ##a)
#define CHAN_PRINT(c,l,p,f,a...) CGRP_PRINT((c)->cgrp, l, p, "%04x:"f, (c)->id, ##a)
@@ -39,6 +39,7 @@
#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080ce.h>
#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080fifo.h>
#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080gpu.h>
+#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080gr.h>
#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080internal.h>
#include <nvrm/535.113.01/common/sdk/nvidia/inc/ctrl/ctrla06f/ctrla06fgpfifo.h>
#include <nvrm/535.113.01/nvidia/generated/g_kernel_channel_nvoc.h>
@@ -328,6 +329,30 @@ r535_chan_id_get(struct nvkm_chan *chan, struct nvkm_memory *muserd, u64 ouserd)
return ret;
}
+static int
+r535_chan_set_zcull_ctxsw_buffer(struct nvkm_chan *chan, u64 addr)
+{
+ NV2080_CTRL_GR_CTXSW_ZCULL_BIND_PARAMS *ctrl;
+
+ ctrl = nvkm_gsp_rm_ctrl_get(&chan->vmm->rm.device.subdevice,
+ NV2080_CTRL_CMD_GR_CTXSW_ZCULL_BIND, sizeof(*ctrl));
+
+ if (WARN_ON(IS_ERR(ctrl)))
+ return PTR_ERR(ctrl);
+
+ ctrl->hClient = chan->vmm->rm.client.object.handle;
+ ctrl->hChannel = chan->rm.object.handle;
+ if (addr) {
+ ctrl->vMemPtr = addr;
+ ctrl->zcullMode = NV2080_CTRL_CTXSW_ZCULL_MODE_SEPARATE_BUFFER;
+ } else {
+ ctrl->vMemPtr = 0;
+ ctrl->zcullMode = NV2080_CTRL_CTXSW_ZCULL_MODE_NO_CTXSW;
+ }
+
+ return nvkm_gsp_rm_ctrl_wr(&chan->vmm->rm.device.subdevice, ctrl);
+}
+
static const struct nvkm_chan_func
r535_chan = {
.id_get = r535_chan_id_get,
@@ -338,6 +363,7 @@ r535_chan = {
.start = r535_chan_start,
.stop = r535_chan_stop,
.doorbell_handle = r535_chan_doorbell_handle,
+ .set_zcull_ctxsw_buffer = r535_chan_set_zcull_ctxsw_buffer,
};
static const struct nvkm_cgrp_func
@@ -31,6 +31,7 @@
#include <subdev/mmu.h>
#include <engine/dma.h>
+#include <nvkm/engine/gr.h>
#include <nvif/if0020.h>
struct nvkm_uchan {
@@ -268,6 +269,21 @@ nvkm_uchan_map(struct nvkm_object *object, void *argv, u32 argc,
return 0;
}
+static int
+nvkm_uchan_mthd(struct nvkm_object *object, u32 mthd, void *argv, u32 argc)
+{
+ struct nvkm_chan *chan = nvkm_uchan(object)->chan;
+ struct nvif_chan_mthd_set_zcull_ctxsw_buffer *args = argv;
+
+ if (mthd != NVIF_CHAN_MTHD_SET_ZCULL_CTXSW_BUFFER)
+ return -ENOTTY;
+
+ if (argc < sizeof(*args))
+ return -EINVAL;
+
+ return nvkm_chan_set_zcull_ctxsw_buffer(chan, args->addr);
+}
+
static int
nvkm_uchan_fini(struct nvkm_object *object, bool suspend)
{
@@ -312,6 +328,7 @@ nvkm_uchan = {
.dtor = nvkm_uchan_dtor,
.init = nvkm_uchan_init,
.fini = nvkm_uchan_fini,
+ .mthd = nvkm_uchan_mthd,
.map = nvkm_uchan_map,
.sclass = nvkm_uchan_sclass,
.uevent = nvkm_uchan_uevent,
@@ -448,6 +448,20 @@ struct drm_nouveau_get_zcull_info {
__u32 ctxsw_align;
};
+struct drm_nouveau_set_zcull_ctxsw_buffer {
+ /**
+ * @ptr: The virtual address for the buffer, or null to bind nothing
+ */
+ __u64 addr;
+
+ /**
+ * @channel: the channel to set the buffer on
+ */
+ __u32 channel;
+
+ __u32 pad;
+};
+
#define DRM_NOUVEAU_GETPARAM 0x00
#define DRM_NOUVEAU_SETPARAM 0x01 /* deprecated */
#define DRM_NOUVEAU_CHANNEL_ALLOC 0x02
@@ -462,6 +476,7 @@ struct drm_nouveau_get_zcull_info {
#define DRM_NOUVEAU_VM_BIND 0x11
#define DRM_NOUVEAU_EXEC 0x12
#define DRM_NOUVEAU_GET_ZCULL_INFO 0x13
+#define DRM_NOUVEAU_SET_ZCULL_CTXSW_BUFFER 0x14
#define DRM_NOUVEAU_GEM_NEW 0x40
#define DRM_NOUVEAU_GEM_PUSHBUF 0x41
#define DRM_NOUVEAU_GEM_CPU_PREP 0x42
@@ -532,6 +547,7 @@ struct drm_nouveau_svm_bind {
#define DRM_IOCTL_NOUVEAU_EXEC DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_EXEC, struct drm_nouveau_exec)
#define DRM_IOCTL_NOUVEAU_GET_ZCULL_INFO DRM_IOR (DRM_COMMAND_BASE + DRM_NOUVEAU_GET_ZCULL_INFO, struct drm_nouveau_get_zcull_info)
+#define DRM_IOCTL_NOUVEAU_SET_ZCULL_CTXSW_BUFFER DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_SET_ZCULL_CTXSW_BUFFER, struct drm_nouveau_set_zcull_ctxsw_buffer)
#if defined(__cplusplus)
}
#endif
We add this ioctl to set up the zcull context switch buffer so userspace can manage it. This also includes support for unbinding the buffer, which helps simplify device teardown on the userspace side. Signed-off-by: Mel Henning <mhenning@darkrefraction.com> --- drivers/gpu/drm/nouveau/include/nvif/if0020.h | 6 +++ .../gpu/drm/nouveau/include/nvkm/engine/gr.h | 1 + .../sdk/nvidia/inc/ctrl/ctrl2080/ctrl2080gr.h | 53 +++++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_abi16.c | 46 ++++++++++++++++ drivers/gpu/drm/nouveau/nouveau_abi16.h | 1 + drivers/gpu/drm/nouveau/nouveau_drm.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 8 +++ .../gpu/drm/nouveau/nvkm/engine/fifo/chan.h | 2 + .../gpu/drm/nouveau/nvkm/engine/fifo/r535.c | 26 +++++++++ .../gpu/drm/nouveau/nvkm/engine/fifo/uchan.c | 17 ++++++ include/uapi/drm/nouveau_drm.h | 16 ++++++ 11 files changed, 177 insertions(+)