diff options
author | Thierry Reding <treding@nvidia.com> | 2017-10-02 15:51:08 +0200 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2018-05-02 17:29:39 +0200 |
commit | 248f843f0e36ca7875ad0a252af72d050f27b8c1 (patch) | |
tree | 62db24338558b2d1041662496d00697466e441c7 /nouveau | |
parent | 1ac3ecde2f2c9afd7110389eccc6860daa6627ca (diff) |
nouveau: Support fence FDs
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
FDs, or passed back to the kernel as a prerequisite for a subsequent HW
operation.
Based heavily on work by Lauri Peltonen <lpeltonen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'nouveau')
-rw-r--r-- | nouveau/nouveau.h | 2 | ||||
-rw-r--r-- | nouveau/pushbuf.c | 133 |
2 files changed, 101 insertions, 34 deletions
diff --git a/nouveau/nouveau.h b/nouveau/nouveau.h index 335ce77d..70d68070 100644 --- a/nouveau/nouveau.h +++ b/nouveau/nouveau.h @@ -226,6 +226,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 *chan); +int nouveau_pushbuf_kick_fence(struct nouveau_pushbuf *, + struct nouveau_object *chan, 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 445c966e..fb1daea3 100644 --- a/nouveau/pushbuf.c +++ b/nouveau/pushbuf.c @@ -29,6 +29,7 @@ #include <string.h> #include <assert.h> #include <errno.h> +#include <unistd.h> #include <xf86drm.h> #include <xf86atomic.h> @@ -73,7 +74,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, @@ -168,7 +169,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) { @@ -303,7 +304,8 @@ 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_fd) { struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); struct nouveau_pushbuf_krec *krec = nvpb->list; @@ -311,9 +313,9 @@ pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan) struct nouveau_drm *drm = nouveau_drm(&dev->object); struct drm_nouveau_gem_pushbuf_bo_presumed *info; struct drm_nouveau_gem_pushbuf_bo *kref; - struct drm_nouveau_gem_pushbuf req; struct nouveau_fifo *fifo = chan->data; struct nouveau_bo *bo; + int fence_out = -1; int krec_id = 0; int ret = 0, i; @@ -326,34 +328,83 @@ pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan) nouveau_pushbuf_data(push, NULL, 0, 0); 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; - if (dbg_on(0)) pushbuf_dump(krec, krec_id++, fifo->channel); + if (fence_fd) { + struct drm_nouveau_gem_pushbuf2 req; + struct drm_nouveau_gem_fence fence; + + memset(&req, 0, sizeof(req)); + 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.flags = 0; + + memset(&fence, 0, sizeof(fence)); + fence.flags = NOUVEAU_GEM_FENCE_EMIT | NOUVEAU_GEM_FENCE_FD; + + if (*fence_fd >= 0) { + fence.flags |= NOUVEAU_GEM_FENCE_WAIT; + fence.handle = *fence_fd; + } + + req.fences = (uint64_t)(unsigned long)&fence; + req.num_fences = 1; + +#ifndef SIMULATE + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_PUSHBUF2, + &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 * + nouveau_device(dev)->gart_limit_percent) / 100; +#else + if (dbg_on(31)) + ret = -EINVAL; +#endif + + if (!ret) + fence_out = fence.handle; + } else { + struct drm_nouveau_gem_pushbuf req; + + 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; + #ifndef SIMULATE - ret = drmCommandWriteRead(drm->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 * - nouveau_device(dev)->gart_limit_percent) / 100; + ret = drmCommandWriteRead(drm->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 * + nouveau_device(dev)->gart_limit_percent) / 100; #else - if (dbg_on(31)) - ret = -EINVAL; + if (dbg_on(31)) + ret = -EINVAL; #endif + } if (ret) { err("kernel rejected pushbuf: %s\n", strerror(-ret)); @@ -384,11 +435,18 @@ pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan) krec = krec->next; } + if (!ret && fence_fd) { + if (*fence_fd >= 0) + close(*fence_fd); + + *fence_fd = 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; @@ -398,7 +456,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)); @@ -468,7 +526,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); } @@ -520,7 +578,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); } } @@ -672,7 +730,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; } @@ -768,10 +826,17 @@ nouveau_pushbuf_refd(struct nouveau_pushbuf *push, struct nouveau_bo *bo) } 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); } + +int +nouveau_pushbuf_kick(struct nouveau_pushbuf *pushbuf, struct nouveau_object *chan) +{ + return nouveau_pushbuf_kick_fence(pushbuf, chan, NULL); +} |