drm/nv50-/disp: share channel creation between nv50/gf110 impls

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index ca8ce9c..4f1ed89 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -43,14 +43,16 @@
  * EVO channel base class
  ******************************************************************************/
 
-int
+static int
 nv50_disp_chan_create_(struct nouveau_object *parent,
 		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, int chid,
+		       struct nouveau_oclass *oclass, int head,
 		       int length, void **pobject)
 {
+	const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs;
 	struct nv50_disp_base *base = (void *)parent;
 	struct nv50_disp_chan *chan;
+	int chid = impl->chid + head;
 	int ret;
 
 	if (base->chan & (1 << chid))
@@ -63,12 +65,14 @@
 	chan = *pobject;
 	if (ret)
 		return ret;
-
 	chan->chid = chid;
+
+	nv_parent(chan)->object_attach = impl->attach;
+	nv_parent(chan)->object_detach = impl->detach;
 	return 0;
 }
 
-void
+static void
 nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
 {
 	struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
@@ -115,16 +119,16 @@
 	nouveau_ramht_remove(base->ramht, cookie);
 }
 
-int
+static int
 nv50_disp_dmac_create_(struct nouveau_object *parent,
 		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, u32 pushbuf, int chid,
+		       struct nouveau_oclass *oclass, u32 pushbuf, int head,
 		       int length, void **pobject)
 {
 	struct nv50_disp_dmac *dmac;
 	int ret;
 
-	ret = nv50_disp_chan_create_(parent, engine, oclass, chid,
+	ret = nv50_disp_chan_create_(parent, engine, oclass, head,
 				     length, pobject);
 	dmac = *pobject;
 	if (ret)
@@ -397,7 +401,7 @@
 	}
 };
 
-static int
+int
 nv50_disp_mast_ctor(struct nouveau_object *parent,
 		    struct nouveau_object *engine,
 		    struct nouveau_oclass *oclass, void *data, u32 size,
@@ -416,8 +420,6 @@
 	if (ret)
 		return ret;
 
-	nv_parent(mast)->object_attach = nv50_disp_dmac_object_attach;
-	nv_parent(mast)->object_detach = nv50_disp_dmac_object_detach;
 	return 0;
 }
 
@@ -479,14 +481,17 @@
 	return nv50_disp_chan_fini(&mast->base, suspend);
 }
 
-struct nouveau_ofuncs
+struct nv50_disp_chan_impl
 nv50_disp_mast_ofuncs = {
-	.ctor = nv50_disp_mast_ctor,
-	.dtor = nv50_disp_dmac_dtor,
-	.init = nv50_disp_mast_init,
-	.fini = nv50_disp_mast_fini,
-	.rd32 = nv50_disp_chan_rd32,
-	.wr32 = nv50_disp_chan_wr32,
+	.base.ctor = nv50_disp_mast_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = nv50_disp_mast_init,
+	.base.fini = nv50_disp_mast_fini,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 0,
+	.attach = nv50_disp_dmac_object_attach,
+	.detach = nv50_disp_dmac_object_detach,
 };
 
 /*******************************************************************************
@@ -543,39 +548,40 @@
 	}
 };
 
-static int
+int
 nv50_disp_sync_ctor(struct nouveau_object *parent,
 		    struct nouveau_object *engine,
 		    struct nouveau_oclass *oclass, void *data, u32 size,
 		    struct nouveau_object **pobject)
 {
 	struct nv50_display_sync_class *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
 	struct nv50_disp_dmac *dmac;
 	int ret;
 
-	if (size < sizeof(*args) || args->head > 1)
+	if (size < sizeof(*args) || args->head >= priv->head.nr)
 		return -EINVAL;
 
 	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
-				     1 + args->head, sizeof(*dmac),
-				     (void **)&dmac);
+				     args->head, sizeof(*dmac), (void **)&dmac);
 	*pobject = nv_object(dmac);
 	if (ret)
 		return ret;
 
-	nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
-	nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
 	return 0;
 }
 
-struct nouveau_ofuncs
+struct nv50_disp_chan_impl
 nv50_disp_sync_ofuncs = {
-	.ctor = nv50_disp_sync_ctor,
-	.dtor = nv50_disp_dmac_dtor,
-	.init = nv50_disp_dmac_init,
-	.fini = nv50_disp_dmac_fini,
-	.rd32 = nv50_disp_chan_rd32,
-	.wr32 = nv50_disp_chan_wr32,
+	.base.ctor = nv50_disp_sync_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = nv50_disp_dmac_init,
+	.base.fini = nv50_disp_dmac_fini,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 1,
+	.attach = nv50_disp_dmac_object_attach,
+	.detach = nv50_disp_dmac_object_detach,
 };
 
 /*******************************************************************************
@@ -620,39 +626,40 @@
 	}
 };
 
-static int
+int
 nv50_disp_ovly_ctor(struct nouveau_object *parent,
 		    struct nouveau_object *engine,
 		    struct nouveau_oclass *oclass, void *data, u32 size,
 		    struct nouveau_object **pobject)
 {
 	struct nv50_display_ovly_class *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
 	struct nv50_disp_dmac *dmac;
 	int ret;
 
-	if (size < sizeof(*args) || args->head > 1)
+	if (size < sizeof(*args) || args->head >= priv->head.nr)
 		return -EINVAL;
 
 	ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf,
-				     3 + args->head, sizeof(*dmac),
-				     (void **)&dmac);
+				     args->head, sizeof(*dmac), (void **)&dmac);
 	*pobject = nv_object(dmac);
 	if (ret)
 		return ret;
 
-	nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach;
-	nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach;
 	return 0;
 }
 
-struct nouveau_ofuncs
+struct nv50_disp_chan_impl
 nv50_disp_ovly_ofuncs = {
-	.ctor = nv50_disp_ovly_ctor,
-	.dtor = nv50_disp_dmac_dtor,
-	.init = nv50_disp_dmac_init,
-	.fini = nv50_disp_dmac_fini,
-	.rd32 = nv50_disp_chan_rd32,
-	.wr32 = nv50_disp_chan_wr32,
+	.base.ctor = nv50_disp_ovly_ctor,
+	.base.dtor = nv50_disp_dmac_dtor,
+	.base.init = nv50_disp_dmac_init,
+	.base.fini = nv50_disp_dmac_fini,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 3,
+	.attach = nv50_disp_dmac_object_attach,
+	.detach = nv50_disp_dmac_object_detach,
 };
 
 /*******************************************************************************
@@ -662,14 +669,14 @@
 static int
 nv50_disp_pioc_create_(struct nouveau_object *parent,
 		       struct nouveau_object *engine,
-		       struct nouveau_oclass *oclass, int chid,
+		       struct nouveau_oclass *oclass, int head,
 		       int length, void **pobject)
 {
-	return nv50_disp_chan_create_(parent, engine, oclass, chid,
+	return nv50_disp_chan_create_(parent, engine, oclass, head,
 				      length, pobject);
 }
 
-static void
+void
 nv50_disp_pioc_dtor(struct nouveau_object *object)
 {
 	struct nv50_disp_pioc *pioc = (void *)object;
@@ -727,20 +734,21 @@
  * EVO immediate overlay channel objects
  ******************************************************************************/
 
-static int
+int
 nv50_disp_oimm_ctor(struct nouveau_object *parent,
 		    struct nouveau_object *engine,
 		    struct nouveau_oclass *oclass, void *data, u32 size,
 		    struct nouveau_object **pobject)
 {
 	struct nv50_display_oimm_class *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
 	struct nv50_disp_pioc *pioc;
 	int ret;
 
-	if (size < sizeof(*args) || args->head > 1)
+	if (size < sizeof(*args) || args->head >= priv->head.nr)
 		return -EINVAL;
 
-	ret = nv50_disp_pioc_create_(parent, engine, oclass, 5 + args->head,
+	ret = nv50_disp_pioc_create_(parent, engine, oclass, args->head,
 				     sizeof(*pioc), (void **)&pioc);
 	*pobject = nv_object(pioc);
 	if (ret)
@@ -749,34 +757,36 @@
 	return 0;
 }
 
-struct nouveau_ofuncs
+struct nv50_disp_chan_impl
 nv50_disp_oimm_ofuncs = {
-	.ctor = nv50_disp_oimm_ctor,
-	.dtor = nv50_disp_pioc_dtor,
-	.init = nv50_disp_pioc_init,
-	.fini = nv50_disp_pioc_fini,
-	.rd32 = nv50_disp_chan_rd32,
-	.wr32 = nv50_disp_chan_wr32,
+	.base.ctor = nv50_disp_oimm_ctor,
+	.base.dtor = nv50_disp_pioc_dtor,
+	.base.init = nv50_disp_pioc_init,
+	.base.fini = nv50_disp_pioc_fini,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 5,
 };
 
 /*******************************************************************************
  * EVO cursor channel objects
  ******************************************************************************/
 
-static int
+int
 nv50_disp_curs_ctor(struct nouveau_object *parent,
 		    struct nouveau_object *engine,
 		    struct nouveau_oclass *oclass, void *data, u32 size,
 		    struct nouveau_object **pobject)
 {
 	struct nv50_display_curs_class *args = data;
+	struct nv50_disp_priv *priv = (void *)engine;
 	struct nv50_disp_pioc *pioc;
 	int ret;
 
-	if (size < sizeof(*args) || args->head > 1)
+	if (size < sizeof(*args) || args->head >= priv->head.nr)
 		return -EINVAL;
 
-	ret = nv50_disp_pioc_create_(parent, engine, oclass, 7 + args->head,
+	ret = nv50_disp_pioc_create_(parent, engine, oclass, args->head,
 				     sizeof(*pioc), (void **)&pioc);
 	*pobject = nv_object(pioc);
 	if (ret)
@@ -785,14 +795,15 @@
 	return 0;
 }
 
-struct nouveau_ofuncs
+struct nv50_disp_chan_impl
 nv50_disp_curs_ofuncs = {
-	.ctor = nv50_disp_curs_ctor,
-	.dtor = nv50_disp_pioc_dtor,
-	.init = nv50_disp_pioc_init,
-	.fini = nv50_disp_pioc_fini,
-	.rd32 = nv50_disp_chan_rd32,
-	.wr32 = nv50_disp_chan_wr32,
+	.base.ctor = nv50_disp_curs_ctor,
+	.base.dtor = nv50_disp_pioc_dtor,
+	.base.init = nv50_disp_pioc_init,
+	.base.fini = nv50_disp_pioc_fini,
+	.base.rd32 = nv50_disp_chan_rd32,
+	.base.wr32 = nv50_disp_chan_wr32,
+	.chid = 7,
 };
 
 /*******************************************************************************
@@ -966,11 +977,11 @@
 
 static struct nouveau_oclass
 nv50_disp_sclass[] = {
-	{ NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
-	{ NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs },
-	{ NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs },
-	{ NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs },
-	{ NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs },
+	{ NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs.base },
+	{ NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs.base },
+	{ NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs.base },
+	{ NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs.base },
+	{ NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs.base },
 	{}
 };