drm/nouveau/fence: minor api changes for an upcoming rework

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 1aa03a8..6d66314 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -35,6 +35,7 @@
 #include "nouveau_dma.h"
 #include "nouveau_mm.h"
 #include "nouveau_vm.h"
+#include "nouveau_fence.h"
 
 #include <linux/log2.h>
 #include <linux/slab.h>
@@ -478,7 +479,7 @@
 	struct nouveau_fence *fence = NULL;
 	int ret;
 
-	ret = nouveau_fence_new(chan, &fence, true);
+	ret = nouveau_fence_new(chan, &fence);
 	if (ret)
 		return ret;
 
@@ -1196,7 +1197,7 @@
 static bool
 nouveau_bo_fence_signalled(void *sync_obj, void *sync_arg)
 {
-	return nouveau_fence_signalled(sync_obj);
+	return nouveau_fence_done(sync_obj);
 }
 
 static int
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 26c08e9..694f632 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -28,6 +28,7 @@
 #include "nouveau_drm.h"
 #include "nouveau_dma.h"
 #include "nouveau_ramht.h"
+#include "nouveau_fence.h"
 #include "nouveau_software.h"
 
 static int
@@ -369,7 +370,7 @@
 	nouveau_fence_update(chan);
 
 	if (chan->fence.sequence != chan->fence.sequence_ack) {
-		ret = nouveau_fence_new(chan, &fence, true);
+		ret = nouveau_fence_new(chan, &fence);
 		if (!ret) {
 			ret = nouveau_fence_wait(fence, false, false);
 			nouveau_fence_unref(&fence);
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index a13f251..f9cdc92 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -35,6 +35,7 @@
 #include "nouveau_connector.h"
 #include "nouveau_software.h"
 #include "nouveau_gpio.h"
+#include "nouveau_fence.h"
 #include "nv50_display.h"
 
 static void
@@ -465,7 +466,7 @@
 	}
 	FIRE_RING (chan);
 
-	ret = nouveau_fence_new(chan, pfence, true);
+	ret = nouveau_fence_new(chan, pfence);
 	if (ret)
 		goto fail;
 
@@ -486,7 +487,7 @@
 	struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
 	struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
 	struct nouveau_page_flip_state *s;
-	struct nouveau_channel *chan;
+	struct nouveau_channel *chan = NULL;
 	struct nouveau_fence *fence;
 	int ret;
 
@@ -509,7 +510,9 @@
 		  new_bo->bo.offset };
 
 	/* Choose the channel the flip will be handled in */
-	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
+	fence = new_bo->bo.sync_obj;
+	if (fence)
+		chan = nouveau_channel_get_unlocked(fence->channel);
 	if (!chan)
 		chan = nouveau_channel_get_unlocked(dev_priv->channel);
 	mutex_lock(&chan->mutex);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index b17444a..43a46f1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -1444,26 +1444,12 @@
 extern void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *);
 
 /* nouveau_fence.c */
-struct nouveau_fence;
-extern int nouveau_fence_init(struct drm_device *);
-extern void nouveau_fence_fini(struct drm_device *);
-extern int nouveau_fence_channel_init(struct nouveau_channel *);
-extern void nouveau_fence_channel_fini(struct nouveau_channel *);
-extern void nouveau_fence_update(struct nouveau_channel *);
-extern int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **,
-			     bool emit);
-extern int nouveau_fence_emit(struct nouveau_fence *);
-extern void nouveau_fence_work(struct nouveau_fence *fence,
-			       void (*work)(void *priv, bool signalled),
-			       void *priv);
-struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *);
-
-extern bool nouveau_fence_signalled(struct nouveau_fence *);
-extern int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
-extern void nouveau_fence_unref(struct nouveau_fence **);
-extern struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *);
-extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
-
+int  nouveau_fence_init(struct drm_device *);
+void nouveau_fence_fini(struct drm_device *);
+int  nouveau_fence_channel_init(struct nouveau_channel *);
+void nouveau_fence_channel_fini(struct nouveau_channel *);
+void nouveau_fence_work(struct nouveau_fence *fence,
+			void (*work)(void *priv, bool signalled), void *priv);
 /* nouveau_gem.c */
 extern int nouveau_gem_new(struct drm_device *, int size, int align,
 			   uint32_t domain, uint32_t tile_mode,
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index f26177a..2c10d54 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -32,47 +32,13 @@
 
 #include "nouveau_drv.h"
 #include "nouveau_ramht.h"
+#include "nouveau_fence.h"
 #include "nouveau_software.h"
 #include "nouveau_dma.h"
 
 #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
 #define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
 
-struct nouveau_fence {
-	struct nouveau_channel *channel;
-	struct kref refcount;
-	struct list_head entry;
-
-	uint32_t sequence;
-	bool signalled;
-	unsigned long timeout;
-
-	void (*work)(void *priv, bool signalled);
-	void *priv;
-};
-
-struct nouveau_semaphore {
-	struct kref ref;
-	struct drm_device *dev;
-	struct drm_mm_node *mem;
-};
-
-static inline struct nouveau_fence *
-nouveau_fence(void *sync_obj)
-{
-	return (struct nouveau_fence *)sync_obj;
-}
-
-static void
-nouveau_fence_del(struct kref *ref)
-{
-	struct nouveau_fence *fence =
-		container_of(ref, struct nouveau_fence, refcount);
-
-	nouveau_channel_ref(NULL, &fence->channel);
-	kfree(fence);
-}
-
 void
 nouveau_fence_update(struct nouveau_channel *chan)
 {
@@ -94,16 +60,16 @@
 		chan->fence.sequence_ack = sequence;
 	}
 
-	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
+	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, head) {
 		if (fence->sequence > chan->fence.sequence_ack)
 			break;
 
-		fence->signalled = true;
-		list_del(&fence->entry);
+		fence->channel = NULL;
+		list_del(&fence->head);
 		if (fence->work)
 			fence->work(fence->priv, true);
 
-		kref_put(&fence->refcount, nouveau_fence_del);
+		nouveau_fence_unref(&fence);
 	}
 
 out:
@@ -111,37 +77,8 @@
 }
 
 int
-nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence,
-		  bool emit)
+nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
 {
-	struct nouveau_fence *fence;
-	int ret = 0;
-
-	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
-	if (!fence)
-		return -ENOMEM;
-	kref_init(&fence->refcount);
-	nouveau_channel_ref(chan, &fence->channel);
-
-	if (emit)
-		ret = nouveau_fence_emit(fence);
-
-	if (ret)
-		nouveau_fence_unref(&fence);
-	*pfence = fence;
-	return ret;
-}
-
-struct nouveau_channel *
-nouveau_fence_channel(struct nouveau_fence *fence)
-{
-	return fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
-}
-
-int
-nouveau_fence_emit(struct nouveau_fence *fence)
-{
-	struct nouveau_channel *chan = fence->channel;
 	struct drm_device *dev = chan->dev;
 	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	int ret;
@@ -158,10 +95,11 @@
 	}
 
 	fence->sequence = ++chan->fence.sequence;
+	fence->channel = chan;
 
-	kref_get(&fence->refcount);
+	kref_get(&fence->kref);
 	spin_lock(&chan->fence.lock);
-	list_add_tail(&fence->entry, &chan->fence.pending);
+	list_add_tail(&fence->head, &chan->fence.pending);
 	spin_unlock(&chan->fence.lock);
 
 	if (USE_REFCNT(dev)) {
@@ -179,50 +117,12 @@
 	return 0;
 }
 
-void
-nouveau_fence_work(struct nouveau_fence *fence,
-		   void (*work)(void *priv, bool signalled),
-		   void *priv)
-{
-	BUG_ON(fence->work);
-
-	spin_lock(&fence->channel->fence.lock);
-
-	if (fence->signalled) {
-		work(priv, true);
-	} else {
-		fence->work = work;
-		fence->priv = priv;
-	}
-
-	spin_unlock(&fence->channel->fence.lock);
-}
-
-void
-nouveau_fence_unref(struct nouveau_fence **pfence)
-{
-	if (*pfence)
-		kref_put(&(*pfence)->refcount, nouveau_fence_del);
-	*pfence = NULL;
-}
-
-struct nouveau_fence *
-nouveau_fence_ref(struct nouveau_fence *fence)
-{
-	kref_get(&fence->refcount);
-	return fence;
-}
-
 bool
-nouveau_fence_signalled(struct nouveau_fence *fence)
+nouveau_fence_done(struct nouveau_fence *fence)
 {
-	struct nouveau_channel *chan = fence->channel;
-
-	if (fence->signalled)
-		return true;
-
-	nouveau_fence_update(chan);
-	return fence->signalled;
+	if (fence->channel)
+		nouveau_fence_update(fence->channel);
+	return !fence->channel;
 }
 
 int
@@ -232,8 +132,8 @@
 	ktime_t t;
 	int ret = 0;
 
-	while (!nouveau_fence_signalled(fence)) {
-		if (time_after_eq(jiffies, fence->timeout)) {
+	while (!nouveau_fence_done(fence)) {
+		if (fence->timeout && time_after_eq(jiffies, fence->timeout)) {
 			ret = -EBUSY;
 			break;
 		}
@@ -255,10 +155,71 @@
 	}
 
 	__set_current_state(TASK_RUNNING);
-
 	return ret;
 }
 
+static void
+nouveau_fence_del(struct kref *kref)
+{
+	struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref);
+	kfree(fence);
+}
+
+void
+nouveau_fence_unref(struct nouveau_fence **pfence)
+{
+	if (*pfence)
+		kref_put(&(*pfence)->kref, nouveau_fence_del);
+	*pfence = NULL;
+}
+
+struct nouveau_fence *
+nouveau_fence_ref(struct nouveau_fence *fence)
+{
+	kref_get(&fence->kref);
+	return fence;
+}
+
+int
+nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence)
+{
+	struct nouveau_fence *fence;
+	int ret = 0;
+
+	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+	if (!fence)
+		return -ENOMEM;
+	kref_init(&fence->kref);
+
+	if (chan) {
+		ret = nouveau_fence_emit(fence, chan);
+		if (ret)
+			nouveau_fence_unref(&fence);
+	}
+
+	*pfence = fence;
+	return ret;
+}
+
+struct nouveau_semaphore {
+	struct kref ref;
+	struct drm_device *dev;
+	struct drm_mm_node *mem;
+};
+
+void
+nouveau_fence_work(struct nouveau_fence *fence,
+		   void (*work)(void *priv, bool signalled),
+		   void *priv)
+{
+	if (!fence->channel) {
+		work(priv, true);
+	} else {
+		fence->work = work;
+		fence->priv = priv;
+	}
+}
+
 static struct nouveau_semaphore *
 semaphore_alloc(struct drm_device *dev)
 {
@@ -367,7 +328,7 @@
 	}
 
 	/* Delay semaphore destruction until its work is done */
-	ret = nouveau_fence_new(chan, &fence, true);
+	ret = nouveau_fence_new(chan, &fence);
 	if (ret)
 		return ret;
 
@@ -421,7 +382,7 @@
 	}
 
 	/* Delay semaphore destruction until its work is done */
-	ret = nouveau_fence_new(chan, &fence, true);
+	ret = nouveau_fence_new(chan, &fence);
 	if (ret)
 		return ret;
 
@@ -435,13 +396,13 @@
 nouveau_fence_sync(struct nouveau_fence *fence,
 		   struct nouveau_channel *wchan)
 {
-	struct nouveau_channel *chan = nouveau_fence_channel(fence);
+	struct nouveau_channel *chan;
 	struct drm_device *dev = wchan->dev;
 	struct nouveau_semaphore *sema;
 	int ret = 0;
 
-	if (likely(!chan || chan == wchan ||
-		   nouveau_fence_signalled(fence)))
+	chan = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
+	if (likely(!chan || chan == wchan || nouveau_fence_done(fence)))
 		goto out;
 
 	sema = semaphore_alloc(dev);
@@ -480,12 +441,6 @@
 }
 
 int
-__nouveau_fence_flush(void *sync_obj, void *sync_arg)
-{
-	return 0;
-}
-
-int
 nouveau_fence_channel_init(struct nouveau_channel *chan)
 {
 	struct drm_device *dev = chan->dev;
@@ -538,14 +493,14 @@
 	struct nouveau_fence *tmp, *fence;
 
 	spin_lock(&chan->fence.lock);
-	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
-		fence->signalled = true;
-		list_del(&fence->entry);
+	list_for_each_entry_safe(fence, tmp, &chan->fence.pending, head) {
+		fence->channel = NULL;
+		list_del(&fence->head);
 
 		if (unlikely(fence->work))
 			fence->work(fence->priv, false);
 
-		kref_put(&fence->refcount, nouveau_fence_del);
+		kref_put(&fence->kref, nouveau_fence_del);
 	}
 	spin_unlock(&chan->fence.lock);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
new file mode 100644
index 0000000..1337acb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -0,0 +1,28 @@
+#ifndef __NOUVEAU_FENCE_H__
+#define __NOUVEAU_FENCE_H__
+
+struct nouveau_fence {
+	struct list_head head;
+	struct kref kref;
+
+	struct nouveau_channel *channel;
+	unsigned long timeout;
+	u32 sequence;
+
+	void (*work)(void *priv, bool signalled);
+	void *priv;
+};
+
+int  nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **);
+struct nouveau_fence *
+nouveau_fence_ref(struct nouveau_fence *);
+void nouveau_fence_unref(struct nouveau_fence **);
+
+int  nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
+bool nouveau_fence_done(struct nouveau_fence *);
+int  nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
+int  nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
+void nouveau_fence_idle(struct nouveau_channel *);
+void nouveau_fence_update(struct nouveau_channel *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 666dad0..996755a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -30,6 +30,7 @@
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 #include "nouveau_dma.h"
+#include "nouveau_fence.h"
 
 #define nouveau_gem_pushbuf_sync(chan) 0
 
@@ -778,7 +779,7 @@
 		}
 	}
 
-	ret = nouveau_fence_new(chan, &fence, true);
+	ret = nouveau_fence_new(chan, &fence);
 	if (ret) {
 		NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
 		WIND_RING(chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 585dcbe..1935212 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -39,6 +39,7 @@
 #include "nouveau_pm.h"
 #include "nouveau_mm.h"
 #include "nouveau_vm.h"
+#include "nouveau_fence.h"
 
 /*
  * NV10-NV40 tiling helpers
@@ -89,7 +90,7 @@
 	spin_lock(&dev_priv->tile.lock);
 
 	if (!tile->used &&
-	    (!tile->fence || nouveau_fence_signalled(tile->fence)))
+	    (!tile->fence || nouveau_fence_done(tile->fence)))
 		tile->used = true;
 	else
 		tile = NULL;