diff options
Diffstat (limited to 'tegra/pushbuf.c')
-rw-r--r-- | tegra/pushbuf.c | 111 |
1 files changed, 99 insertions, 12 deletions
diff --git a/tegra/pushbuf.c b/tegra/pushbuf.c index 7be12a76..54a0f831 100644 --- a/tegra/pushbuf.c +++ b/tegra/pushbuf.c @@ -48,9 +48,14 @@ int drm_tegra_pushbuf_queue(struct drm_tegra_pushbuf_private *pushbuf) /* add buffer object as command buffers for this job */ memset(&cmdbuf, 0, sizeof(cmdbuf)); - cmdbuf.words = pushbuf->base.ptr - pushbuf->start; - cmdbuf.handle = pushbuf->bo->handle; + cmdbuf.index = pushbuf->index; cmdbuf.offset = 0; + cmdbuf.words = pushbuf->base.ptr - pushbuf->start; + + if (pushbuf->num_fences) { + cmdbuf.fences = (uintptr_t)pushbuf->fences; + cmdbuf.num_fences = pushbuf->num_fences; + } err = drm_tegra_job_add_cmdbuf(pushbuf->job, &cmdbuf); if (err < 0) @@ -82,7 +87,7 @@ int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp, *pushbufp = &pushbuf->base; - DRMLISTADD(&pushbuf->list, &job->pushbufs); + DRMLISTADDTAIL(&pushbuf->list, &job->pushbufs); job->pushbuf = pushbuf; return 0; @@ -117,6 +122,7 @@ int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf, { struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf); struct drm_tegra_channel *channel = priv->job->channel; + struct drm_tegra_buffer buffer; struct drm_tegra_bo *bo; void *ptr; int err; @@ -148,12 +154,19 @@ int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf, return err; } - DRMLISTADD(&bo->list, &priv->bos); + DRMLISTADDTAIL(&bo->list, &priv->bos); priv->start = priv->base.ptr = ptr; - priv->end = priv->start + bo->size; + priv->end = priv->start + bo->size / 4; priv->bo = bo; + memset(&buffer, 0, sizeof(buffer)); + buffer.handle = bo->handle; + + err = drm_tegra_job_add_buffer(priv->job, &buffer, &priv->index); + if (err < 0) + return err; + return 0; } @@ -163,13 +176,22 @@ int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, unsigned long shift) { struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf); + struct drm_tegra_buffer buffer; struct drm_tegra_reloc reloc; + unsigned int index; int err; + memset(&buffer, 0, sizeof(buffer)); + buffer.handle = target->handle; + + err = drm_tegra_job_add_buffer(priv->job, &buffer, &index); + if (err < 0) + return err; + memset(&reloc, 0, sizeof(reloc)); - reloc.cmdbuf.handle = priv->bo->handle; + reloc.cmdbuf.index = priv->index; reloc.cmdbuf.offset = drm_tegra_pushbuf_get_offset(pushbuf); - reloc.target.handle = target->handle; + reloc.target.index = index; reloc.target.offset = offset; reloc.shift = shift; @@ -182,17 +204,82 @@ int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, return 0; } -int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf, - enum drm_tegra_syncpt_cond cond) +static int drm_tegra_pushbuf_add_fence(struct drm_tegra_pushbuf *pushbuf, + const struct drm_tegra_fence *fence) { struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf); + struct drm_tegra_fence *fences; + size_t size; + + size = (priv->num_fences + 1) * sizeof(*fence); + + fences = realloc(priv->fences, size); + if (!fences) + return -ENOMEM; + + priv->fences = fences; + + priv->fences[priv->num_fences++] = *fence; + + return 0; +} + +int drm_tegra_pushbuf_wait_fd(struct drm_tegra_pushbuf *pushbuf, + int fd) +{ + struct drm_tegra_fence fence; + int err; + + memset(&fence, 0, sizeof(fence)); + fence.handle = fd; + fence.flags = DRM_TEGRA_FENCE_FD | DRM_TEGRA_FENCE_WAIT; - if (cond >= DRM_TEGRA_SYNCPT_COND_MAX) + err = drm_tegra_pushbuf_add_fence(pushbuf, &fence); + if (err < 0) + return err; + + return 0; +} + +int drm_tegra_pushbuf_wait_syncobj(struct drm_tegra_pushbuf *pushbuf, + uint32_t syncobj) +{ + struct drm_tegra_fence fence; + int err; + + memset(&fence, 0, sizeof(fence)); + fence.handle = syncobj; + fence.flags = DRM_TEGRA_FENCE_WAIT; + + err = drm_tegra_pushbuf_add_fence(pushbuf, &fence); + if (err < 0) + return err; + + return 0; +} + +int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf, + unsigned int index, unsigned int value, + enum drm_tegra_sync_cond cond) +{ + struct drm_tegra_fence fence; + int err; + + if (cond >= DRM_TEGRA_SYNC_COND_MAX) return -EINVAL; *pushbuf->ptr++ = HOST1X_OPCODE_NONINCR(0x0, 0x1); - *pushbuf->ptr++ = cond << 8 | priv->job->syncpt; - priv->job->increments++; + *pushbuf->ptr++ = cond; + + memset(&fence, 0, sizeof(fence)); + fence.flags = DRM_TEGRA_FENCE_EMIT; + fence.offset = drm_tegra_pushbuf_get_offset(pushbuf) - 4; + fence.index = index; + fence.value = value; + + err = drm_tegra_pushbuf_add_fence(pushbuf, &fence); + if (err < 0) + return err; return 0; } |