[RFC PATCH 5/7] libdrm: nouveau: Support fence fds

Lauri Peltonen lpeltonen at nvidia.com
Fri Sep 26 03:00:10 PDT 2014


Add a new nouveau_pushbuf_kick_fence function that takes and emits
a sync fence fd.  The fence fd can be waited on, or merged with
other fence fd's, or passed back to kernel as a prerquisite for a
subsequent hw operation.

Signed-off-by: Lauri Peltonen <lpeltonen at nvidia.com>
---
 include/drm/nouveau_drm.h | 10 +++++
 nouveau/nouveau.h         |  2 +
 nouveau/pushbuf.c         | 93 ++++++++++++++++++++++++++++++++---------------
 3 files changed, 76 insertions(+), 29 deletions(-)

diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h
index b18cad0..3e40210 100644
--- a/include/drm/nouveau_drm.h
+++ b/include/drm/nouveau_drm.h
@@ -171,6 +171,15 @@ struct drm_nouveau_gem_pushbuf {
 	uint64_t gart_available;
 };
 
+#define NOUVEAU_GEM_PUSHBUF_2_FENCE_WAIT                             0x00000001
+#define NOUVEAU_GEM_PUSHBUF_2_FENCE_EMIT                             0x00000002
+struct drm_nouveau_gem_pushbuf_2 {
+	struct drm_nouveau_gem_pushbuf base;
+	uint32_t flags;
+	int32_t  fence;
+	uint64_t reserved;
+};
+
 #define NOUVEAU_GEM_CPU_PREP_NOWAIT                                  0x00000001
 #define NOUVEAU_GEM_CPU_PREP_NOBLOCK                                 0x00000002
 #define NOUVEAU_GEM_CPU_PREP_WRITE                                   0x00000004
@@ -204,5 +213,6 @@ struct drm_nouveau_sarea {
 #define DRM_NOUVEAU_GEM_CPU_PREP       0x42
 #define DRM_NOUVEAU_GEM_CPU_FINI       0x43
 #define DRM_NOUVEAU_GEM_INFO           0x44
+#define DRM_NOUVEAU_GEM_PUSHBUF_2      0x45
 
 #endif /* __NOUVEAU_DRM_H__ */
diff --git a/nouveau/nouveau.h b/nouveau/nouveau.h
index a55e2b0..281420f 100644
--- a/nouveau/nouveau.h
+++ b/nouveau/nouveau.h
@@ -225,6 +225,8 @@ void nouveau_pushbuf_reloc(struct nouveau_pushbuf *, struct nouveau_bo *,
 int  nouveau_pushbuf_validate(struct nouveau_pushbuf *);
 uint32_t nouveau_pushbuf_refd(struct nouveau_pushbuf *, struct nouveau_bo *);
 int  nouveau_pushbuf_kick(struct nouveau_pushbuf *, struct nouveau_object *channel);
+int  nouveau_pushbuf_kick_fence(struct nouveau_pushbuf *,
+				struct nouveau_object *channel, int *fence);
 struct nouveau_bufctx *
 nouveau_pushbuf_bufctx(struct nouveau_pushbuf *, struct nouveau_bufctx *);
 
diff --git a/nouveau/pushbuf.c b/nouveau/pushbuf.c
index 6e703a4..8667d05 100644
--- a/nouveau/pushbuf.c
+++ b/nouveau/pushbuf.c
@@ -33,6 +33,7 @@
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
+#include <unistd.h>
 
 #include <xf86drm.h>
 #include <xf86atomic.h>
@@ -77,7 +78,7 @@ nouveau_pushbuf(struct nouveau_pushbuf *push)
 }
 
 static int pushbuf_validate(struct nouveau_pushbuf *, bool);
-static int pushbuf_flush(struct nouveau_pushbuf *);
+static int pushbuf_flush(struct nouveau_pushbuf *, int *);
 
 static bool
 pushbuf_kref_fits(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
@@ -172,7 +173,7 @@ pushbuf_kref(struct nouveau_pushbuf *push, struct nouveau_bo *bo,
 	 */
 	fpush = cli_push_get(push->client, bo);
 	if (fpush && fpush != push)
-		pushbuf_flush(fpush);
+		pushbuf_flush(fpush, NULL);
 
 	kref = cli_kref_get(push->client, bo);
 	if (kref) {
@@ -305,18 +306,21 @@ pushbuf_dump(struct nouveau_pushbuf_krec *krec, int krec_id, int chid)
 }
 
 static int
-pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan)
+pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan,
+	       int *fence)
 {
 	struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
 	struct nouveau_pushbuf_krec *krec = nvpb->list;
 	struct nouveau_device *dev = push->client->device;
 	struct drm_nouveau_gem_pushbuf_bo_presumed *info;
 	struct drm_nouveau_gem_pushbuf_bo *kref;
-	struct drm_nouveau_gem_pushbuf req;
+	struct drm_nouveau_gem_pushbuf_2 req_2;
+	struct drm_nouveau_gem_pushbuf *req = &req_2.base;
 	struct nouveau_fifo *fifo = chan->data;
 	struct nouveau_bo *bo;
 	int krec_id = 0;
 	int ret = 0, i;
+	int fence_out = -1;
 
 	if (chan->oclass != NOUVEAU_FIFO_CHANNEL_CLASS)
 		return -EINVAL;
@@ -326,30 +330,42 @@ pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan)
 
 	nouveau_pushbuf_data(push, NULL, 0, 0);
 
+	/* TODO: If fence is requested, force kickoff. */
 	while (krec && krec->nr_push) {
-		req.channel = fifo->channel;
-		req.nr_buffers = krec->nr_buffer;
-		req.buffers = (uint64_t)(unsigned long)krec->buffer;
-		req.nr_relocs = krec->nr_reloc;
-		req.nr_push = krec->nr_push;
-		req.relocs = (uint64_t)(unsigned long)krec->reloc;
-		req.push = (uint64_t)(unsigned long)krec->push;
-		req.suffix0 = nvpb->suffix0;
-		req.suffix1 = nvpb->suffix1;
-		req.vram_available = 0; /* for valgrind */
-		req.gart_available = 0;
+		req->channel = fifo->channel;
+		req->nr_buffers = krec->nr_buffer;
+		req->buffers = (uint64_t)(unsigned long)krec->buffer;
+		req->nr_relocs = krec->nr_reloc;
+		req->nr_push = krec->nr_push;
+		req->relocs = (uint64_t)(unsigned long)krec->reloc;
+		req->push = (uint64_t)(unsigned long)krec->push;
+		req->suffix0 = nvpb->suffix0;
+		req->suffix1 = nvpb->suffix1;
+		req->vram_available = 0; /* for valgrind */
+		req->gart_available = 0;
+		if (fence) {
+			req_2.flags = NOUVEAU_GEM_PUSHBUF_2_FENCE_EMIT;
+			if (*fence >= 0)
+				req_2.flags |= NOUVEAU_GEM_PUSHBUF_2_FENCE_WAIT;
+			req_2.fence = *fence;
+			req_2.reserved = 0;
+		}
 
 		if (dbg_on(0))
 			pushbuf_dump(krec, krec_id++, fifo->channel);
 
 #ifndef SIMULATE
-		ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
-					  &req, sizeof(req));
-		nvpb->suffix0 = req.suffix0;
-		nvpb->suffix1 = req.suffix1;
-		dev->vram_limit = (req.vram_available *
+		if (fence)
+			ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_PUSHBUF_2,
+						  &req_2, sizeof(req_2));
+		else
+			ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_PUSHBUF,
+						  req, sizeof(*req));
+		nvpb->suffix0 = req->suffix0;
+		nvpb->suffix1 = req->suffix1;
+		dev->vram_limit = (req->vram_available *
 				nouveau_device(dev)->vram_limit_percent) / 100;
-		dev->gart_limit = (req.gart_available *
+		dev->gart_limit = (req->gart_available *
 				nouveau_device(dev)->gart_limit_percent) / 100;
 #else
 		if (dbg_on(31))
@@ -362,6 +378,12 @@ pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan)
 			break;
 		}
 
+		if (fence) {
+			if (fence_out >= 0)
+				close(fence_out);
+			fence_out = req_2.fence;
+		}
+
 		kref = krec->buffer;
 		for (i = 0; i < krec->nr_buffer; i++, kref++) {
 			bo = (void *)(unsigned long)kref->user_priv;
@@ -385,11 +407,17 @@ pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan)
 		krec = krec->next;
 	}
 
+	if (!ret && fence) {
+		if (*fence >= 0)
+			close(*fence);
+		*fence = fence_out;
+	}
+
 	return ret;
 }
 
 static int
-pushbuf_flush(struct nouveau_pushbuf *push)
+pushbuf_flush(struct nouveau_pushbuf *push, int *fence)
 {
 	struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push);
 	struct nouveau_pushbuf_krec *krec = nvpb->krec;
@@ -399,7 +427,7 @@ pushbuf_flush(struct nouveau_pushbuf *push)
 	int ret = 0, i;
 
 	if (push->channel) {
-		ret = pushbuf_submit(push, push->channel);
+		ret = pushbuf_submit(push, push->channel, fence);
 	} else {
 		nouveau_pushbuf_data(push, NULL, 0, 0);
 		krec->next = malloc(sizeof(*krec));
@@ -469,7 +497,7 @@ pushbuf_refn(struct nouveau_pushbuf *push, bool retry,
 	if (ret) {
 		pushbuf_refn_fail(push, sref, krec->nr_reloc);
 		if (retry) {
-			pushbuf_flush(push);
+			pushbuf_flush(push, NULL);
 			nouveau_pushbuf_space(push, 0, 0, 0);
 			return pushbuf_refn(push, false, refs, nr);
 		}
@@ -521,7 +549,7 @@ pushbuf_validate(struct nouveau_pushbuf *push, bool retry)
 	if (ret) {
 		pushbuf_refn_fail(push, sref, srel);
 		if (retry) {
-			pushbuf_flush(push);
+			pushbuf_flush(push, NULL);
 			return pushbuf_validate(push, false);
 		}
 	}
@@ -673,7 +701,7 @@ nouveau_pushbuf_space(struct nouveau_pushbuf *push,
 	    krec->nr_reloc + relocs >= NOUVEAU_GEM_MAX_RELOCS ||
 	    krec->nr_push + pushes >= NOUVEAU_GEM_MAX_PUSH) {
 		if (nvpb->bo && krec->nr_buffer)
-			pushbuf_flush(push);
+			pushbuf_flush(push, NULL);
 		flushed = true;
 	}
 
@@ -767,10 +795,17 @@ nouveau_pushbuf_refd(struct nouveau_pushbuf *push, struct nouveau_bo *bo)
 }
 
 drm_public int
-nouveau_pushbuf_kick(struct nouveau_pushbuf *push, struct nouveau_object *chan)
+nouveau_pushbuf_kick_fence(struct nouveau_pushbuf *push,
+			   struct nouveau_object *chan, int *fence)
 {
 	if (!push->channel)
-		return pushbuf_submit(push, chan);
-	pushbuf_flush(push);
+		return pushbuf_submit(push, chan, fence);
+	pushbuf_flush(push, fence);
 	return pushbuf_validate(push, false);
 }
+
+drm_public int
+nouveau_pushbuf_kick(struct nouveau_pushbuf *push, struct nouveau_object *chan)
+{
+	return nouveau_pushbuf_kick_fence(push, chan, NULL);
+}
-- 
1.8.1.5



More information about the dri-devel mailing list