Skip to contentSkip to conversation

drm/nouveau: Add support for fence FDs

PATCH New Thierry Reding 1 participant 4 messages Jan 11, 2018 1 message not in the archive

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover drm/nouveau: Add support for fence FDs

From: Thierry Reding <[email protected]>

This small series of patches implements support for waiting on and emitting fence FDs on kickoff. This enables explicit fencing and can be used for example to synchronize buffer accesses between the display engine and the GPU on Tegra.

The first patch lays the groundwork by splitting up nouveau_fence_sync() to allow reuse. Patch 2 is where the interesting stuff happens. It adds a new IOCTL (PUSHBUF2) that is a superset of the existing PUSHBUF IOCTL and reuses most of the code while adding support for pre- and post- fences.

Finally, the third patch teaches Nouveau how to deal with fence arrays, which are usually a result of chaining together multiple dependent jobs.

I have corresponding userspace support for these in libdrm and Mesa:

https://cgit.freedesktop.org/~tagr/drm/log/?h=nouveau-sync-fd
https://cgit.freedesktop.org/~tagr/mesa/log/?h=nouveau-sync-fd

I'll send those patches out shortly. There's some more work depending on these patches that I plan to send out in the coming days or weeks. The final result allows Nouveau and Tegra DRM to negotiate for a framebuffer modifier and then go into a render/scanout loop using fences for synchronization. All of this was tested using a slightly modified version of kmscube.

Thierry

Thierry Reding (3):
drm/nouveau: Split nouveau_fence_sync()
drm/nouveau: Support fence FDs at kickoff
drm/nouveau: Support DMA fence arrays

 drivers/gpu/drm/nouveau/nouveau_bo.c      | 38 ++++++++++++++-
 drivers/gpu/drm/nouveau/nouveau_bo.h      |  2 +
 drivers/gpu/drm/nouveau/nouveau_display.c |  4 +-
 drivers/gpu/drm/nouveau/nouveau_drm.c     |  1 +
 drivers/gpu/drm/nouveau/nouveau_fence.c   | 81 +++++++++++++------------------
 drivers/gpu/drm/nouveau/nouveau_fence.h   |  2 +-
 drivers/gpu/drm/nouveau/nouveau_gem.c     | 80 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/nouveau/nouveau_gem.h     |  2 +
 include/uapi/drm/nouveau_drm.h            | 14 ++++++
 9 files changed, 167 insertions(+), 57 deletions(-)
Signature · 1 line
2.15.1

A message that is not in the archive (sent off-list or not yet received): 20180111221546.28547-1-thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#2 lore raw

PATCH 1/3 drm/nouveau: Split nouveau_fence_sync()

From: Thierry Reding <[email protected]>

Turn nouveau_fence_sync() into a low-level helper that adds fence waits to the channel command stream. The new nouveau_bo_sync() helper replaces the previous nouveau_fence_sync() implementation. It passes each of the buffer object's fences to nouveau_fence_sync() in turn.

This provides more fine-grained control over fences which is needed by subsequent patches for sync fd support.

Heavily based on work by Lauri Peltonen <[email protected]>.

---
 drivers/gpu/drm/nouveau/nouveau_bo.c      | 38 ++++++++++++++++-
 drivers/gpu/drm/nouveau/nouveau_bo.h      |  2 +
 drivers/gpu/drm/nouveau/nouveau_display.c |  4 +-
 drivers/gpu/drm/nouveau/nouveau_fence.c   | 68 +++++++------------------------
 drivers/gpu/drm/nouveau/nouveau_fence.h   |  2 +-
 drivers/gpu/drm/nouveau/nouveau_gem.c     |  2 +-
 6 files changed, 57 insertions(+), 59 deletions(-)
drivers/gpu/drm/nouveau/nouveau_bo.c +37 -1
index 41e7f2927443..0285ca4c6235 100644
@@ -545,6 +545,42 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
 					PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
+int
+nouveau_bo_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan,
+		bool exclusive, bool intr)
+{
+	struct reservation_object *resv = nvbo->bo.resv;
+	struct reservation_object_list *fobj;
+	struct dma_fence *fence;
+	int ret = 0, i;
+
+	if (!exclusive) {
+		ret = reservation_object_reserve_shared(resv);
+		if (ret < 0)
+			return ret;
+	}
+
+	fobj = reservation_object_get_list(resv);
+	fence = reservation_object_get_excl(resv);
+
+	if (fence && (!exclusive || !fobj || !fobj->shared_count))
+		return nouveau_fence_sync(fence, chan, intr);
+
+	if (!exclusive || !fobj)
+		return ret;
+
+	for (i = 0; i < fobj->shared_count && !ret; ++i) {
+		fence = rcu_dereference_protected(fobj->shared[i],
+						  reservation_object_held(resv));
+
+		ret = nouveau_fence_sync(fence, chan, intr);
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
 int
 nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
 		    bool no_wait_gpu)
@@ -1114,7 +1150,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
 	}
 
 	mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
-	ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, intr);
+	ret = nouveau_bo_sync(nouveau_bo(bo), chan, true, intr);
 	if (ret == 0) {
 		ret = drm->ttm.move(chan, bo, &bo->mem, new_reg);
 		if (ret == 0) {
drivers/gpu/drm/nouveau/nouveau_bo.h +2 -0
index 7b5cc5c73d20..d2ef12c0e39a 100644
@@ -93,6 +93,8 @@ int  nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
 			 bool no_wait_gpu);
 void nouveau_bo_sync_for_device(struct nouveau_bo *nvbo);
 void nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo);
+int nouveau_bo_sync(struct nouveau_bo *nvbo, struct nouveau_channel *channel,
+		    bool exclusive, bool intr);
 
 /* TODO: submit equivalent to TTM generic API upstream? */
 static inline void __iomem *
drivers/gpu/drm/nouveau/nouveau_display.c +2 -2
index 009713404cc4..526280e9677a 100644
@@ -755,7 +755,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 
 	/* Synchronize with the old framebuffer */
-	ret = nouveau_fence_sync(old_bo, chan, false, false);
+	ret = nouveau_bo_sync(old_bo, chan, false, false);
 	if (ret)
 		goto fail;
 
@@ -819,7 +819,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 		goto fail_unpin;
 
 	/* synchronise rendering channel with the kernel's channel */
-	ret = nouveau_fence_sync(new_bo, chan, false, true);
+	ret = nouveau_bo_sync(new_bo, chan, false, true);
 	if (ret) {
 		ttm_bo_unreserve(&new_bo->bo);
 		goto fail_unpin;
drivers/gpu/drm/nouveau/nouveau_fence.c +14 -54

80 lines not on this page · raw message

drivers/gpu/drm/nouveau/nouveau_fence.h +1 -1
index 5bd8d30d1657..2c46d9e767ab 100644
@@ -24,7 +24,7 @@ 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_bo *, struct nouveau_channel *, bool exclusive, bool intr);
+int  nouveau_fence_sync(struct dma_fence *, struct nouveau_channel *, bool intr);
 
 struct nouveau_fence_chan {
 	spinlock_t lock;
drivers/gpu/drm/nouveau/nouveau_gem.c +1 -1
index e72a7e37eb0a..ea5e55551cbd 100644
@@ -494,7 +494,7 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
 			return ret;
 		}
 
-		ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains, true);
+		ret = nouveau_bo_sync(nvbo, chan, !!b->write_domains, true);
 		if (unlikely(ret)) {
 			if (ret != -ERESTARTSYS)
 				NV_PRINTK(err, cli, "fail post-validate sync\n");
Signature · 1 line
2.15.1
#3 lore raw

PATCH 2/3 drm/nouveau: Support fence FDs at kickoff

In reply to a message not in the archive

From: Thierry Reding <[email protected]>

Add a new NOUVEAU_GEM_PUSHBUF2 IOCTL that accepts and emits a sync fence FD from/to userspace if requested by the corresponding flags.

Based heavily on work by Lauri Peltonen <[email protected]>

---
 drivers/gpu/drm/nouveau/nouveau_drm.c |  1 +
 drivers/gpu/drm/nouveau/nouveau_gem.c | 78 +++++++++++++++++++++++++++++++++--
 drivers/gpu/drm/nouveau/nouveau_gem.h |  2 +
 include/uapi/drm/nouveau_drm.h        | 14 +++++++
 4 files changed, 91 insertions(+), 4 deletions(-)
drivers/gpu/drm/nouveau/nouveau_drm.c +1 -0
index 3ce2f02e9e58..b38500a64236 100644
@@ -1012,6 +1012,7 @@ nouveau_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF2, nouveau_gem_ioctl_pushbuf2, DRM_AUTH|DRM_RENDER_ALLOW),
 };
 
 long
drivers/gpu/drm/nouveau/nouveau_gem.c +74 -4

124 lines not on this page · raw message

drivers/gpu/drm/nouveau/nouveau_gem.h +2 -0
index eb55c1eb1d9f..3c98b0f87c4b 100644
@@ -31,6 +31,8 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
 				      struct drm_file *);
 extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
 				  struct drm_file *);
+extern int nouveau_gem_ioctl_pushbuf2(struct drm_device *, void *,
+				      struct drm_file *);
 
 struct dma_buf *nouveau_gem_prime_export(struct drm_device *dev,
 					 struct drm_gem_object *obj,
include/uapi/drm/nouveau_drm.h +14 -0
index 259588a4b61b..e50e65515303 100644
@@ -114,6 +114,18 @@ struct drm_nouveau_gem_pushbuf {
 	__u64 gart_available;
 };
 
+#define NOUVEAU_GEM_PUSHBUF_FENCE_WAIT (1 << 0)
+#define NOUVEAU_GEM_PUSHBUF_FENCE_EMIT (1 << 1)
+#define NOUVEAU_GEM_PUSHBUF_FLAGS (NOUVEAU_GEM_PUSHBUF_FENCE_WAIT | \
+				   NOUVEAU_GEM_PUSHBUF_FENCE_EMIT)
+
+struct drm_nouveau_gem_pushbuf2 {
+	struct drm_nouveau_gem_pushbuf base;
+	__u32 flags;
+	__s32 fence;
+	__u64 reserved;
+};
+
 #define NOUVEAU_GEM_CPU_PREP_NOWAIT                                  0x00000001
 #define NOUVEAU_GEM_CPU_PREP_WRITE                                   0x00000004
 struct drm_nouveau_gem_cpu_prep {
@@ -138,12 +150,14 @@ struct drm_nouveau_gem_cpu_fini {
 #define DRM_NOUVEAU_GEM_CPU_PREP       0x42
 #define DRM_NOUVEAU_GEM_CPU_FINI       0x43
 #define DRM_NOUVEAU_GEM_INFO           0x44
+#define DRM_NOUVEAU_GEM_PUSHBUF2       0x45
 
 #define DRM_IOCTL_NOUVEAU_GEM_NEW            DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_NEW, struct drm_nouveau_gem_new)
 #define DRM_IOCTL_NOUVEAU_GEM_PUSHBUF        DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_PUSHBUF, struct drm_nouveau_gem_pushbuf)
 #define DRM_IOCTL_NOUVEAU_GEM_CPU_PREP       DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_CPU_PREP, struct drm_nouveau_gem_cpu_prep)
 #define DRM_IOCTL_NOUVEAU_GEM_CPU_FINI       DRM_IOW (DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_CPU_FINI, struct drm_nouveau_gem_cpu_fini)
 #define DRM_IOCTL_NOUVEAU_GEM_INFO           DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_INFO, struct drm_nouveau_gem_info)
+#define DRM_IOCTL_NOUVEAU_GEM_PUSHBUF2       DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GEM_PUSHBUF2, struct drm_nouveau_gem_pushbuf2)
 
 #if defined(__cplusplus)
 }
Signature · 6 lines
2.15.1

_______________________________________________
Nouveau mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/nouveau
#4 lore raw

PATCH 3/3 drm/nouveau: Support DMA fence arrays

In reply to a message not in the archive

From: Thierry Reding <[email protected]>

---
 drivers/gpu/drm/nouveau/nouveau_fence.c | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)
drivers/gpu/drm/nouveau/nouveau_fence.c +28 -3
index d61fcfb97b09..53178b1471e3 100644
@@ -28,6 +28,7 @@
 
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
+#include <linux/dma-fence-array.h>
 #include <trace/events/dma_fence.h>
 
 #include <nvif/cl826e.h>
@@ -331,9 +332,9 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
 		return 0;
 }
 
-int
-nouveau_fence_sync(struct dma_fence *fence, struct nouveau_channel *chan,
-		   bool intr)
+static int
+__nouveau_fence_sync(struct dma_fence *fence, struct nouveau_channel *chan,
+		     bool intr)
 {
 	struct nouveau_fence_chan *fctx = chan->fence;
 	struct nouveau_channel *prev = NULL;
@@ -356,6 +357,30 @@ nouveau_fence_sync(struct dma_fence *fence, struct nouveau_channel *chan,
 	return ret;
 }
 
+int
+nouveau_fence_sync(struct dma_fence *fence, struct nouveau_channel *chan,
+		   bool intr)
+{
+	int ret = 0;
+
+	if (dma_fence_is_array(fence)) {
+		struct dma_fence_array *array = to_dma_fence_array(fence);
+		unsigned int i;
+
+		for (i = 0; i < array->num_fences; i++) {
+			struct dma_fence *f = array->fences[i];
+
+			ret = __nouveau_fence_sync(f, chan, intr);
+			if (ret < 0)
+				break;
+		}
+	} else {
+		ret = __nouveau_fence_sync(fence, chan, intr);
+	}
+
+	return ret;
+}
+
 void
 nouveau_fence_unref(struct nouveau_fence **pfence)
 {
Signature · 1 line
2.15.1