[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