drm/nv50: extend vblank semaphore to generic dmaobj + offset pair

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index a5dc984..03da383 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -910,7 +910,6 @@
 extern int  nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle,
 				   int cout, uint32_t start, uint32_t end,
 				   uint32_t *offset);
-extern int  nouveau_notifier_offset(struct nouveau_gpuobj *, uint32_t *);
 
 /* nouveau_channel.c */
 extern void nouveau_channel_cleanup(struct drm_device *, struct drm_file *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c
index aa54915..69c93b8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_notifier.c
+++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c
@@ -161,21 +161,3 @@
 	*b_offset = mem->start;
 	return 0;
 }
-
-int
-nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
-{
-	if (!nobj || nobj->dtor != nouveau_notifier_gpuobj_dtor)
-		return -EINVAL;
-
-	if (poffset) {
-		struct drm_mm_node *mem = nobj->priv;
-
-		if (*poffset >= mem->size)
-			return false;
-
-		*poffset += mem->start;
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_software.h b/drivers/gpu/drm/nouveau/nouveau_software.h
index e60bc6c..9914cf1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_software.h
+++ b/drivers/gpu/drm/nouveau/nouveau_software.h
@@ -4,13 +4,15 @@
 struct nouveau_software_priv {
 	struct nouveau_exec_engine base;
 	struct list_head vblank;
+	spinlock_t peephole_lock;
 };
 
 struct nouveau_software_chan {
 	struct list_head flip;
 	struct {
 		struct list_head list;
-		struct nouveau_bo *bo;
+		u32 channel;
+		u32 ctxdma;
 		u32 offset;
 		u32 value;
 		u32 head;
@@ -18,23 +20,6 @@
 };
 
 static inline void
-nouveau_software_vblank(struct drm_device *dev, int crtc)
-{
-	struct nouveau_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
-	struct nouveau_software_chan *pch, *tmp;
-
-	list_for_each_entry_safe(pch, tmp, &psw->vblank, vblank.list) {
-		if (pch->vblank.head != crtc)
-			continue;
-
-		nouveau_bo_wr32(pch->vblank.bo, pch->vblank.offset,
-						pch->vblank.value);
-		list_del(&pch->vblank.list);
-		drm_vblank_put(dev, crtc);
-	}
-}
-
-static inline void
 nouveau_software_context_new(struct nouveau_software_chan *pch)
 {
 	INIT_LIST_HEAD(&pch->flip);
@@ -44,6 +29,7 @@
 nouveau_software_create(struct nouveau_software_priv *psw)
 {
 	INIT_LIST_HEAD(&psw->vblank);
+	spin_lock_init(&psw->peephole_lock);
 }
 
 static inline u16
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 5c41612..b244d99 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -646,7 +646,30 @@
 static void
 nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
 {
-	nouveau_software_vblank(dev, crtc);
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
+	struct nouveau_software_chan *pch, *tmp;
+
+	list_for_each_entry_safe(pch, tmp, &psw->vblank, vblank.list) {
+		if (pch->vblank.head != crtc)
+			continue;
+
+		spin_lock(&psw->peephole_lock);
+		nv_wr32(dev, 0x001704, pch->vblank.channel);
+		nv_wr32(dev, 0x001710, 0x80000000 | pch->vblank.ctxdma);
+		if (dev_priv->chipset == 0x50) {
+			nv_wr32(dev, 0x001570, pch->vblank.offset);
+			nv_wr32(dev, 0x001574, pch->vblank.value);
+		} else {
+			nv_wr32(dev, 0x060010, pch->vblank.offset);
+			nv_wr32(dev, 0x060014, pch->vblank.value);
+		}
+		spin_unlock(&psw->peephole_lock);
+
+		list_del(&pch->vblank.list);
+		drm_vblank_put(dev, crtc);
+	}
+
 	drm_handle_vblank(dev, crtc);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nv50_software.c b/drivers/gpu/drm/nouveau/nv50_software.c
index 114d251..df554d9 100644
--- a/drivers/gpu/drm/nouveau/nv50_software.c
+++ b/drivers/gpu/drm/nouveau/nv50_software.c
@@ -36,9 +36,6 @@
 
 struct nv50_software_chan {
 	struct nouveau_software_chan base;
-	struct {
-		struct nouveau_gpuobj *object;
-	} vblank;
 };
 
 static int
@@ -51,11 +48,7 @@
 	if (!gpuobj)
 		return -ENOENT;
 
-	if (nouveau_notifier_offset(gpuobj, NULL))
-		return -EINVAL;
-
-	pch->vblank.object = gpuobj;
-	pch->base.vblank.offset = ~0;
+	pch->base.vblank.ctxdma = gpuobj->cinst >> 4;
 	return 0;
 }
 
@@ -63,11 +56,7 @@
 mthd_vblsem_offset(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
 {
 	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
-
-	if (nouveau_notifier_offset(pch->vblank.object, &data))
-		return -ERANGE;
-
-	pch->base.vblank.offset = data >> 2;
+	pch->base.vblank.offset = data;
 	return 0;
 }
 
@@ -86,7 +75,7 @@
 	struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
 	struct drm_device *dev = chan->dev;
 
-	if (!pch->vblank.object || pch->base.vblank.offset == ~0 || data > 1)
+	if (data > 1)
 		return -EINVAL;
 
 	drm_vblank_get(dev, data);
@@ -116,7 +105,7 @@
 		return -ENOMEM;
 
 	nouveau_software_context_new(&pch->base);
-	pch->base.vblank.bo = chan->notifier_bo;
+	pch->base.vblank.channel = chan->ramin->vinst >> 12;
 	chan->engctx[engine] = pch;
 
 	/* dma objects for display sync channel semaphore blocks */