drm/nv84/fence: access fences with full virtual address, not offset

Allows most of the code to be shared between nv84/nvc0 implementations,
and paves the way for doing emit/sync on non-VRAM buffers (multi-gpu,
dma-buf).

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index be6166e..2324911 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -68,8 +68,27 @@
 int nv50_fence_create(struct nouveau_drm *);
 int nv84_fence_create(struct nouveau_drm *);
 int nvc0_fence_create(struct nouveau_drm *);
-u64 nvc0_fence_crtc(struct nouveau_channel *, int crtc);
 
 int nouveau_flip_complete(void *chan);
 
+struct nv84_fence_chan {
+	struct nouveau_fence_chan base;
+	struct nouveau_vma vma;
+	struct nouveau_vma dispc_vma[4];
+};
+
+struct nv84_fence_priv {
+	struct nouveau_fence_priv base;
+	struct nouveau_bo *bo;
+	u32 *suspend;
+};
+
+u64  nv84_fence_crtc(struct nouveau_channel *, int);
+u32  nv84_fence_read(struct nouveau_channel *);
+int  nv84_fence_context_new(struct nouveau_channel *);
+void nv84_fence_context_del(struct nouveau_channel *);
+bool nv84_fence_suspend(struct nouveau_drm *);
+void nv84_fence_resume(struct nouveau_drm *);
+void nv84_fence_destroy(struct nouveau_drm *);
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index c9da4f1..102a873 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -502,7 +502,7 @@
 		if (ret)
 			return ret;
 
-		if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
+		if (nv_mclass(chan->object) < NV84_CHANNEL_IND_CLASS) {
 			BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
 			OUT_RING  (chan, NvEvoSema0 + nv_crtc->index);
 			OUT_RING  (chan, sync->sem.offset);
@@ -512,24 +512,36 @@
 			OUT_RING  (chan, sync->sem.offset ^ 0x10);
 			OUT_RING  (chan, 0x74b1e000);
 			BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
-			if (nv_mclass(chan->object) < NV84_CHANNEL_DMA_CLASS)
-				OUT_RING  (chan, NvSema);
-			else
-				OUT_RING  (chan, chan->vram);
+			OUT_RING  (chan, NvSema);
+		} else
+		if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
+			u64 offset = nv84_fence_crtc(chan, nv_crtc->index);
+			offset += sync->sem.offset;
+
+			BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+			OUT_RING  (chan, upper_32_bits(offset));
+			OUT_RING  (chan, lower_32_bits(offset));
+			OUT_RING  (chan, 0xf00d0000 | sync->sem.value);
+			OUT_RING  (chan, 0x00000002);
+			BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+			OUT_RING  (chan, upper_32_bits(offset));
+			OUT_RING  (chan, lower_32_bits(offset ^ 0x10));
+			OUT_RING  (chan, 0x74b1e000);
+			OUT_RING  (chan, 0x00000001);
 		} else {
-			u64 offset = nvc0_fence_crtc(chan, nv_crtc->index);
+			u64 offset = nv84_fence_crtc(chan, nv_crtc->index);
 			offset += sync->sem.offset;
 
 			BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 			OUT_RING  (chan, upper_32_bits(offset));
 			OUT_RING  (chan, lower_32_bits(offset));
 			OUT_RING  (chan, 0xf00d0000 | sync->sem.value);
-			OUT_RING  (chan, 0x1002);
+			OUT_RING  (chan, 0x00001002);
 			BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
 			OUT_RING  (chan, upper_32_bits(offset));
 			OUT_RING  (chan, lower_32_bits(offset ^ 0x10));
 			OUT_RING  (chan, 0x74b1e000);
-			OUT_RING  (chan, 0x1001);
+			OUT_RING  (chan, 0x00001001);
 		}
 
 		FIRE_RING (chan);
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c
index e64e815..58c2401 100644
--- a/drivers/gpu/drm/nouveau/nv84_fence.c
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -23,6 +23,7 @@
  */
 
 #include <core/object.h>
+#include <core/client.h>
 #include <core/class.h>
 
 #include <engine/fifo.h>
@@ -33,80 +34,96 @@
 
 #include "nv50_display.h"
 
-struct nv84_fence_chan {
-	struct nouveau_fence_chan base;
-};
-
-struct nv84_fence_priv {
-	struct nouveau_fence_priv base;
-	struct nouveau_gpuobj *mem;
-};
+u64
+nv84_fence_crtc(struct nouveau_channel *chan, int crtc)
+{
+	struct nv84_fence_chan *fctx = chan->fence;
+	return fctx->dispc_vma[crtc].offset;
+}
 
 static int
 nv84_fence_emit(struct nouveau_fence *fence)
 {
 	struct nouveau_channel *chan = fence->channel;
+	struct nv84_fence_chan *fctx = chan->fence;
 	struct nouveau_fifo_chan *fifo = (void *)chan->object;
-	int ret = RING_SPACE(chan, 8);
+	u64 addr = fctx->vma.offset + fifo->chid * 16;
+	int ret;
+
+	ret = RING_SPACE(chan, 8);
 	if (ret == 0) {
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
-		OUT_RING  (chan, NvSema);
+		OUT_RING  (chan, chan->vram);
 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 5);
-		OUT_RING  (chan, upper_32_bits(fifo->chid * 16));
-		OUT_RING  (chan, lower_32_bits(fifo->chid * 16));
+		OUT_RING  (chan, upper_32_bits(addr));
+		OUT_RING  (chan, lower_32_bits(addr));
 		OUT_RING  (chan, fence->sequence);
 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
 		OUT_RING  (chan, 0x00000000);
 		FIRE_RING (chan);
 	}
+
 	return ret;
 }
 
-
 static int
 nv84_fence_sync(struct nouveau_fence *fence,
 		struct nouveau_channel *prev, struct nouveau_channel *chan)
 {
+	struct nv84_fence_chan *fctx = chan->fence;
 	struct nouveau_fifo_chan *fifo = (void *)prev->object;
-	int ret = RING_SPACE(chan, 7);
+	u64 addr = fctx->vma.offset + fifo->chid * 16;
+	int ret;
+
+	ret = RING_SPACE(chan, 7);
 	if (ret == 0) {
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
-		OUT_RING  (chan, NvSema);
+		OUT_RING  (chan, chan->vram);
 		BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
-		OUT_RING  (chan, upper_32_bits(fifo->chid * 16));
-		OUT_RING  (chan, lower_32_bits(fifo->chid * 16));
+		OUT_RING  (chan, upper_32_bits(addr));
+		OUT_RING  (chan, lower_32_bits(addr));
 		OUT_RING  (chan, fence->sequence);
 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL);
 		FIRE_RING (chan);
 	}
+
 	return ret;
 }
 
-static u32
+u32
 nv84_fence_read(struct nouveau_channel *chan)
 {
 	struct nouveau_fifo_chan *fifo = (void *)chan->object;
 	struct nv84_fence_priv *priv = chan->drm->fence;
-	return nv_ro32(priv->mem, fifo->chid * 16);
+	return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4);
 }
 
-static void
+void
 nv84_fence_context_del(struct nouveau_channel *chan)
 {
+	struct drm_device *dev = chan->drm->dev;
+	struct nv84_fence_priv *priv = chan->drm->fence;
 	struct nv84_fence_chan *fctx = chan->fence;
+	int i;
+
+	for (i = 0; i < dev->mode_config.num_crtc; i++) {
+		struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
+		nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
+	}
+
+	nouveau_bo_vma_del(priv->bo, &fctx->vma);
 	nouveau_fence_context_del(&fctx->base);
 	chan->fence = NULL;
 	kfree(fctx);
 }
 
-static int
+int
 nv84_fence_context_new(struct nouveau_channel *chan)
 {
-	struct drm_device *dev = chan->drm->dev;
 	struct nouveau_fifo_chan *fifo = (void *)chan->object;
+	struct nouveau_client *client = nouveau_client(fifo);
 	struct nv84_fence_priv *priv = chan->drm->fence;
 	struct nv84_fence_chan *fctx;
-	struct nouveau_object *object;
 	int ret, i;
 
 	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -115,43 +132,59 @@
 
 	nouveau_fence_context_new(&fctx->base);
 
-	ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
-				 NvSema, 0x0002,
-				 &(struct nv_dma_class) {
-					.flags = NV_DMA_TARGET_VRAM |
-						 NV_DMA_ACCESS_RDWR,
-					.start = priv->mem->addr,
-					.limit = priv->mem->addr +
-						 priv->mem->size - 1,
-				 }, sizeof(struct nv_dma_class),
-				 &object);
-
-	/* dma objects for display sync channel semaphore blocks */
-	for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
-		struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
-
-		ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
-					 NvEvoSema0 + i, 0x003d,
-					 &(struct nv_dma_class) {
-						.flags = NV_DMA_TARGET_VRAM |
-							 NV_DMA_ACCESS_RDWR,
-						.start = bo->bo.offset,
-						.limit = bo->bo.offset + 0xfff,
-					 }, sizeof(struct nv_dma_class),
-					 &object);
-	}
-
+	ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma);
 	if (ret)
 		nv84_fence_context_del(chan);
-	nv_wo32(priv->mem, fifo->chid * 16, 0x00000000);
+
+	/* map display semaphore buffers into channel's vm */
+	for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
+		struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i);
+		ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]);
+	}
+
+	nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000);
 	return ret;
 }
 
-static void
+bool
+nv84_fence_suspend(struct nouveau_drm *drm)
+{
+	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
+	struct nv84_fence_priv *priv = drm->fence;
+	int i;
+
+	priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32));
+	if (priv->suspend) {
+		for (i = 0; i <= pfifo->max; i++)
+			priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
+	}
+
+	return priv->suspend != NULL;
+}
+
+void
+nv84_fence_resume(struct nouveau_drm *drm)
+{
+	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
+	struct nv84_fence_priv *priv = drm->fence;
+	int i;
+
+	if (priv->suspend) {
+		for (i = 0; i <= pfifo->max; i++)
+			nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
+		vfree(priv->suspend);
+		priv->suspend = NULL;
+	}
+}
+
+void
 nv84_fence_destroy(struct nouveau_drm *drm)
 {
 	struct nv84_fence_priv *priv = drm->fence;
-	nouveau_gpuobj_ref(NULL, &priv->mem);
+	nouveau_bo_unmap(priv->bo);
+	if (priv->bo)
+		nouveau_bo_unpin(priv->bo);
+	nouveau_bo_ref(NULL, &priv->bo);
 	drm->fence = NULL;
 	kfree(priv);
 }
@@ -161,7 +194,6 @@
 {
 	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
 	struct nv84_fence_priv *priv;
-	u32 chan = pfifo->max + 1;
 	int ret;
 
 	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -169,6 +201,8 @@
 		return -ENOMEM;
 
 	priv->base.dtor = nv84_fence_destroy;
+	priv->base.suspend = nv84_fence_suspend;
+	priv->base.resume = nv84_fence_resume;
 	priv->base.context_new = nv84_fence_context_new;
 	priv->base.context_del = nv84_fence_context_del;
 	priv->base.emit = nv84_fence_emit;
@@ -178,8 +212,19 @@
 	init_waitqueue_head(&priv->base.waiting);
 	priv->base.uevent = true;
 
-	ret = nouveau_gpuobj_new(drm->device, NULL, chan * 16, 0x1000, 0,
-				&priv->mem);
+	ret = nouveau_bo_new(drm->dev, 16 * (pfifo->max + 1), 0,
+			     TTM_PL_FLAG_VRAM, 0, 0, NULL, &priv->bo);
+	if (ret == 0) {
+		ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
+		if (ret == 0) {
+			ret = nouveau_bo_map(priv->bo);
+			if (ret)
+				nouveau_bo_unpin(priv->bo);
+		}
+		if (ret)
+			nouveau_bo_ref(NULL, &priv->bo);
+	}
+
 	if (ret)
 		nv84_fence_destroy(drm);
 	return ret;
diff --git a/drivers/gpu/drm/nouveau/nvc0_fence.c b/drivers/gpu/drm/nouveau/nvc0_fence.c
index d8ed2c5..e4c4ead 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fence.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fence.c
@@ -34,30 +34,11 @@
 
 #include "nv50_display.h"
 
-struct nvc0_fence_priv {
-	struct nouveau_fence_priv base;
-	struct nouveau_bo *bo;
-	u32 *suspend;
-};
-
-struct nvc0_fence_chan {
-	struct nouveau_fence_chan base;
-	struct nouveau_vma vma;
-	struct nouveau_vma dispc_vma[4];
-};
-
-u64
-nvc0_fence_crtc(struct nouveau_channel *chan, int crtc)
-{
-	struct nvc0_fence_chan *fctx = chan->fence;
-	return fctx->dispc_vma[crtc].offset;
-}
-
 static int
 nvc0_fence_emit(struct nouveau_fence *fence)
 {
 	struct nouveau_channel *chan = fence->channel;
-	struct nvc0_fence_chan *fctx = chan->fence;
+	struct nv84_fence_chan *fctx = chan->fence;
 	struct nouveau_fifo_chan *fifo = (void *)chan->object;
 	u64 addr = fctx->vma.offset + fifo->chid * 16;
 	int ret;
@@ -80,7 +61,7 @@
 nvc0_fence_sync(struct nouveau_fence *fence,
 		struct nouveau_channel *prev, struct nouveau_channel *chan)
 {
-	struct nvc0_fence_chan *fctx = chan->fence;
+	struct nv84_fence_chan *fctx = chan->fence;
 	struct nouveau_fifo_chan *fifo = (void *)prev->object;
 	u64 addr = fctx->vma.offset + fifo->chid * 16;
 	int ret;
@@ -99,124 +80,25 @@
 	return ret;
 }
 
-static u32
-nvc0_fence_read(struct nouveau_channel *chan)
-{
-	struct nouveau_fifo_chan *fifo = (void *)chan->object;
-	struct nvc0_fence_priv *priv = chan->drm->fence;
-	return nouveau_bo_rd32(priv->bo, fifo->chid * 16/4);
-}
-
-static void
-nvc0_fence_context_del(struct nouveau_channel *chan)
-{
-	struct drm_device *dev = chan->drm->dev;
-	struct nvc0_fence_priv *priv = chan->drm->fence;
-	struct nvc0_fence_chan *fctx = chan->fence;
-	int i;
-
-	for (i = 0; i < dev->mode_config.num_crtc; i++) {
-		struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
-		nouveau_bo_vma_del(bo, &fctx->dispc_vma[i]);
-	}
-
-	nouveau_bo_vma_del(priv->bo, &fctx->vma);
-	nouveau_fence_context_del(&fctx->base);
-	chan->fence = NULL;
-	kfree(fctx);
-}
-
-static int
-nvc0_fence_context_new(struct nouveau_channel *chan)
-{
-	struct nouveau_fifo_chan *fifo = (void *)chan->object;
-	struct nouveau_client *client = nouveau_client(fifo);
-	struct nvc0_fence_priv *priv = chan->drm->fence;
-	struct nvc0_fence_chan *fctx;
-	int ret, i;
-
-	fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
-	if (!fctx)
-		return -ENOMEM;
-
-	nouveau_fence_context_new(&fctx->base);
-
-	ret = nouveau_bo_vma_add(priv->bo, client->vm, &fctx->vma);
-	if (ret)
-		nvc0_fence_context_del(chan);
-
-	/* map display semaphore buffers into channel's vm */
-	for (i = 0; !ret && i < chan->drm->dev->mode_config.num_crtc; i++) {
-		struct nouveau_bo *bo = nv50_display_crtc_sema(chan->drm->dev, i);
-		ret = nouveau_bo_vma_add(bo, client->vm, &fctx->dispc_vma[i]);
-	}
-
-	nouveau_bo_wr32(priv->bo, fifo->chid * 16/4, 0x00000000);
-	return ret;
-}
-
-static bool
-nvc0_fence_suspend(struct nouveau_drm *drm)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
-	struct nvc0_fence_priv *priv = drm->fence;
-	int i;
-
-	priv->suspend = vmalloc((pfifo->max + 1) * sizeof(u32));
-	if (priv->suspend) {
-		for (i = 0; i <= pfifo->max; i++)
-			priv->suspend[i] = nouveau_bo_rd32(priv->bo, i);
-	}
-
-	return priv->suspend != NULL;
-}
-
-static void
-nvc0_fence_resume(struct nouveau_drm *drm)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
-	struct nvc0_fence_priv *priv = drm->fence;
-	int i;
-
-	if (priv->suspend) {
-		for (i = 0; i <= pfifo->max; i++)
-			nouveau_bo_wr32(priv->bo, i, priv->suspend[i]);
-		vfree(priv->suspend);
-		priv->suspend = NULL;
-	}
-}
-
-static void
-nvc0_fence_destroy(struct nouveau_drm *drm)
-{
-	struct nvc0_fence_priv *priv = drm->fence;
-	nouveau_bo_unmap(priv->bo);
-	if (priv->bo)
-		nouveau_bo_unpin(priv->bo);
-	nouveau_bo_ref(NULL, &priv->bo);
-	drm->fence = NULL;
-	kfree(priv);
-}
-
 int
 nvc0_fence_create(struct nouveau_drm *drm)
 {
 	struct nouveau_fifo *pfifo = nouveau_fifo(drm->device);
-	struct nvc0_fence_priv *priv;
+	struct nv84_fence_priv *priv;
 	int ret;
 
 	priv = drm->fence = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	priv->base.dtor = nvc0_fence_destroy;
-	priv->base.suspend = nvc0_fence_suspend;
-	priv->base.resume = nvc0_fence_resume;
-	priv->base.context_new = nvc0_fence_context_new;
-	priv->base.context_del = nvc0_fence_context_del;
+	priv->base.dtor = nv84_fence_destroy;
+	priv->base.suspend = nv84_fence_suspend;
+	priv->base.resume = nv84_fence_resume;
+	priv->base.context_new = nv84_fence_context_new;
+	priv->base.context_del = nv84_fence_context_del;
 	priv->base.emit = nvc0_fence_emit;
 	priv->base.sync = nvc0_fence_sync;
-	priv->base.read = nvc0_fence_read;
+	priv->base.read = nv84_fence_read;
 
 	init_waitqueue_head(&priv->base.waiting);
 	priv->base.uevent = true;
@@ -235,6 +117,6 @@
 	}
 
 	if (ret)
-		nvc0_fence_destroy(drm);
+		nv84_fence_destroy(drm);
 	return ret;
 }