drm/nve0/fifo: support engine selection when creating fifo channels

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
index 4914c3b..5b80f3e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
@@ -182,7 +182,7 @@
 		    struct nouveau_oclass *oclass, void *data, u32 size,
 		    struct nouveau_object **pobject)
 {
-	struct nv_channel_ind_class *args = data;
+	struct nv50_channel_ind_class *args = data;
 	struct nouveau_bar *bar = nouveau_bar(parent);
 	struct nv50_fifo_base *base = (void *)parent;
 	struct nv50_fifo_chan *chan;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
index 765affb..d3b0356 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
@@ -150,7 +150,7 @@
 	struct nouveau_bar *bar = nouveau_bar(parent);
 	struct nv50_fifo_base *base = (void *)parent;
 	struct nv50_fifo_chan *chan;
-	struct nv_channel_ind_class *args = data;
+	struct nv50_channel_ind_class *args = data;
 	u64 ioffset, ilength;
 	int ret;
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
index ef403fe..a4ae2bf 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
@@ -163,7 +163,7 @@
 	struct nvc0_fifo_priv *priv = (void *)engine;
 	struct nvc0_fifo_base *base = (void *)parent;
 	struct nvc0_fifo_chan *chan;
-	struct nv_channel_ind_class *args = data;
+	struct nv50_channel_ind_class *args = data;
 	u64 usermem, ioffset, ilength;
 	int ret, i;
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index aaff086..c3f4955 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -38,6 +38,22 @@
 #include <engine/dmaobj.h>
 #include <engine/fifo.h>
 
+#define _(a,b) { (a), ((1 << (a)) | (b)) }
+static const struct {
+	int subdev;
+	u32 mask;
+} fifo_engine[] = {
+	_(NVDEV_ENGINE_GR      , (1 << NVDEV_ENGINE_SW)),
+	_(NVDEV_ENGINE_VP      , 0),
+	_(NVDEV_ENGINE_PPP     , 0),
+	_(NVDEV_ENGINE_BSP     , 0),
+	_(NVDEV_ENGINE_COPY0   , 0),
+	_(NVDEV_ENGINE_COPY1   , 0),
+	_(NVDEV_ENGINE_VENC    , 0),
+};
+#undef _
+#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
+
 struct nve0_fifo_engn {
 	struct nouveau_gpuobj *playlist[2];
 	int cur_playlist;
@@ -45,7 +61,7 @@
 
 struct nve0_fifo_priv {
 	struct nouveau_fifo base;
-	struct nve0_fifo_engn engine[16];
+	struct nve0_fifo_engn engine[FIFO_ENGINE_NR];
 	struct {
 		struct nouveau_gpuobj *mem;
 		struct nouveau_vma bar;
@@ -119,7 +135,9 @@
 
 	switch (nv_engidx(object->engine)) {
 	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
+	case NVDEV_ENGINE_GR   :
+	case NVDEV_ENGINE_COPY0:
+	case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
 	default:
 		return -EINVAL;
 	}
@@ -149,7 +167,9 @@
 
 	switch (nv_engidx(object->engine)) {
 	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
+	case NVDEV_ENGINE_GR   :
+	case NVDEV_ENGINE_COPY0:
+	case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
 	default:
 		return -EINVAL;
 	}
@@ -178,24 +198,36 @@
 	struct nve0_fifo_priv *priv = (void *)engine;
 	struct nve0_fifo_base *base = (void *)parent;
 	struct nve0_fifo_chan *chan;
-	struct nv_channel_ind_class *args = data;
+	struct nve0_channel_ind_class *args = data;
 	u64 usermem, ioffset, ilength;
 	int ret, i;
 
 	if (size < sizeof(*args))
 		return -EINVAL;
 
+	for (i = 0; i < FIFO_ENGINE_NR; i++) {
+		if (args->engine & (1 << i)) {
+			if (nouveau_engine(parent, fifo_engine[i].subdev)) {
+				args->engine = (1 << i);
+				break;
+			}
+		}
+	}
+
+	if (i == FIFO_ENGINE_NR)
+		return -ENODEV;
+
 	ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
 					  priv->user.bar.offset, 0x200,
 					  args->pushbuf,
-					  (1 << NVDEV_ENGINE_SW) |
-					  (1 << NVDEV_ENGINE_GR), &chan);
+					  fifo_engine[i].mask, &chan);
 	*pobject = nv_object(chan);
 	if (ret)
 		return ret;
 
 	nv_parent(chan)->context_attach = nve0_fifo_context_attach;
 	nv_parent(chan)->context_detach = nve0_fifo_context_detach;
+	chan->engine = i;
 
 	usermem = chan->base.chid * 0x200;
 	ioffset = args->ioffset;
@@ -235,6 +267,7 @@
 	if (ret)
 		return ret;
 
+	nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
 	nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
 	nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
 	nve0_fifo_playlist_update(priv, chan->engine);
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
index 17326dd..9c6b0eb 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -65,13 +65,30 @@
 /* 506f: NV50_CHANNEL_IND
  * 826f: NV84_CHANNEL_IND
  * 906f: NVC0_CHANNEL_IND
- * a06f: NVE0_CHANNEL_IND
  */
 
-struct nv_channel_ind_class {
+struct nv50_channel_ind_class {
 	u32 pushbuf;
 	u32 ilength;
 	u64 ioffset;
 };
 
+/* a06f: NVE0_CHANNEL_IND
+ */
+
+#define NVE0_CHANNEL_IND_ENGINE_GR  0x00000001
+#define NVE0_CHANNEL_IND_ENGINE_VP  0x00000002
+#define NVE0_CHANNEL_IND_ENGINE_PPP 0x00000004
+#define NVE0_CHANNEL_IND_ENGINE_BSP 0x00000008
+#define NVE0_CHANNEL_IND_ENGINE_CE0 0x00000010
+#define NVE0_CHANNEL_IND_ENGINE_CE1 0x00000020
+#define NVE0_CHANNEL_IND_ENGINE_ENC 0x00000040
+
+struct nve0_channel_ind_class {
+	u32 pushbuf;
+	u32 ilength;
+	u64 ioffset;
+	u32 engine;
+};
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h
index 4db7b01..1305593 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/device.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/device.h
@@ -36,7 +36,7 @@
 	NVDEV_ENGINE_COPY0,
 	NVDEV_ENGINE_COPY1,
 	NVDEV_ENGINE_UNK1C1,
-	NVDEV_ENGINE_FENCE,
+	NVDEV_ENGINE_VENC,
 	NVDEV_ENGINE_DISP,
 	NVDEV_SUBDEV_NR,
 };
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index 3dd5f71..b1eea19 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -188,7 +188,7 @@
 {
 	static const u16 oclasses[] = { 0xa06f, 0x906f, 0x826f, 0x506f, 0 };
 	const u16 *oclass = oclasses;
-	struct nv_channel_ind_class args;
+	struct nve0_channel_ind_class args;
 	struct nouveau_channel *chan;
 	int ret;
 
@@ -202,6 +202,7 @@
 	args.pushbuf = chan->push.handle;
 	args.ioffset = 0x10000 + chan->push.vma.offset;
 	args.ilength = 0x02000;
+	args.engine  = NVE0_CHANNEL_IND_ENGINE_GR;
 
 	do {
 		ret = nouveau_object_new(nv_object(cli), parent, handle,