[PATCH v2 libdrm 4/7] tegra: Add channel, job, pushbuf and fence APIs
Thierry Reding
thierry.reding at gmail.com
Wed Apr 9 04:40:27 PDT 2014
From: Thierry Reding <treding at nvidia.com>
These functions can be used to open channels to engines, manage job
submissions, create push buffers to store command streams in and wait
until jobs have been completed.
Signed-off-by: Thierry Reding <treding at nvidia.com>
---
Changes in v2:
- automatically allocate buffer objects as required by pushbuffers
- pushbuffers can now have more than one associated buffer object
- add drm_tegra_pushbuf_prepare() function
tegra/Makefile.am | 4 ++
tegra/channel.c | 127 +++++++++++++++++++++++++++++++++
tegra/fence.c | 71 +++++++++++++++++++
tegra/job.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++
tegra/private.h | 72 +++++++++++++++++++
tegra/pushbuf.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
tegra/tegra.c | 2 +
tegra/tegra.h | 52 ++++++++++++++
8 files changed, 713 insertions(+)
create mode 100644 tegra/channel.c
create mode 100644 tegra/fence.c
create mode 100644 tegra/job.c
create mode 100644 tegra/pushbuf.c
diff --git a/tegra/Makefile.am b/tegra/Makefile.am
index 1b83145b120d..c73587e8661e 100644
--- a/tegra/Makefile.am
+++ b/tegra/Makefile.am
@@ -11,6 +11,10 @@ libdrm_tegra_la_LDFLAGS = -version-number 0:0:0 -no-undefined
libdrm_tegra_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@
libdrm_tegra_la_SOURCES = \
+ channel.c \
+ fence.c \
+ job.c \
+ pushbuf.c \
tegra.c
libdrm_tegraincludedir = ${includedir}/libdrm
diff --git a/tegra/channel.c b/tegra/channel.c
new file mode 100644
index 000000000000..3ab1d578f8e5
--- /dev/null
+++ b/tegra/channel.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include "private.h"
+
+static int drm_tegra_channel_setup(struct drm_tegra_channel *channel)
+{
+ struct drm_tegra *drm = channel->drm;
+ struct drm_tegra_get_syncpt args;
+ int err;
+
+ memset(&args, 0, sizeof(args));
+ args.context = channel->context;
+ args.index = 0;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_GET_SYNCPT, &args);
+ if (err < 0)
+ return -errno;
+
+ channel->syncpt = args.id;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_channel_open(struct drm_tegra_channel **channelp,
+ struct drm_tegra *drm,
+ enum drm_tegra_class client)
+{
+ struct drm_tegra_open_channel args;
+ struct drm_tegra_channel *channel;
+ enum host1x_class class;
+ int err;
+
+ switch (client) {
+ case DRM_TEGRA_GR2D:
+ class = HOST1X_CLASS_GR2D;
+ break;
+
+ case DRM_TEGRA_GR3D:
+ class = HOST1X_CLASS_GR3D;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ channel = calloc(1, sizeof(*channel));
+ if (!channel)
+ return -ENOMEM;
+
+ channel->drm = drm;
+
+ memset(&args, 0, sizeof(args));
+ args.client = class;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_OPEN_CHANNEL, &args);
+ if (err < 0) {
+ free(channel);
+ return -errno;
+ }
+
+ channel->context = args.context;
+ channel->class = class;
+
+ err = drm_tegra_channel_setup(channel);
+ if (err < 0) {
+ free(channel);
+ return err;
+ }
+
+ *channelp = channel;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_channel_close(struct drm_tegra_channel *channel)
+{
+ struct drm_tegra_close_channel args;
+ struct drm_tegra *drm;
+ int err;
+
+ if (!channel)
+ return -EINVAL;
+
+ drm = channel->drm;
+
+ memset(&args, 0, sizeof(args));
+ args.context = channel->context;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CLOSE_CHANNEL, &args);
+ if (err < 0)
+ return -errno;
+
+ free(channel);
+
+ return 0;
+}
diff --git a/tegra/fence.c b/tegra/fence.c
new file mode 100644
index 000000000000..f58725ca8472
--- /dev/null
+++ b/tegra/fence.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include "private.h"
+
+drm_public
+int drm_tegra_fence_wait_timeout(struct drm_tegra_fence *fence,
+ unsigned long timeout)
+{
+ struct drm_tegra_syncpt_wait args;
+ int err;
+
+ memset(&args, 0, sizeof(args));
+ args.id = fence->syncpt;
+ args.thresh = fence->value;
+ args.timeout = timeout;
+
+ while (true) {
+ err = ioctl(fence->drm->fd, DRM_IOCTL_TEGRA_SYNCPT_WAIT, &args);
+ if (err < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_fence_wait(struct drm_tegra_fence *fence)
+{
+ return drm_tegra_fence_wait_timeout(fence, -1);
+}
+
+drm_public
+void drm_tegra_fence_free(struct drm_tegra_fence *fence)
+{
+ free(fence);
+}
diff --git a/tegra/job.c b/tegra/job.c
new file mode 100644
index 000000000000..8df643c9a9bb
--- /dev/null
+++ b/tegra/job.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "private.h"
+
+int drm_tegra_job_add_reloc(struct drm_tegra_job *job,
+ const struct drm_tegra_reloc *reloc)
+{
+ struct drm_tegra_reloc *relocs;
+ size_t size;
+
+ size = (job->num_relocs + 1) * sizeof(*reloc);
+
+ relocs = realloc(job->relocs, size);
+ if (!reloc)
+ return -ENOMEM;
+
+ job->relocs = relocs;
+
+ job->relocs[job->num_relocs++] = *reloc;
+
+ return 0;
+}
+
+int drm_tegra_job_add_cmdbuf(struct drm_tegra_job *job,
+ const struct drm_tegra_cmdbuf *cmdbuf)
+{
+ struct drm_tegra_cmdbuf *cmdbufs;
+ size_t size;
+
+ size = (job->num_cmdbufs + 1) * sizeof(*cmdbuf);
+
+ cmdbufs = realloc(job->cmdbufs, size);
+ if (!cmdbufs)
+ return -ENOMEM;
+
+ cmdbufs[job->num_cmdbufs++] = *cmdbuf;
+ job->cmdbufs = cmdbufs;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_job_new(struct drm_tegra_job **jobp,
+ struct drm_tegra_channel *channel)
+{
+ struct drm_tegra_job *job;
+
+ job = calloc(1, sizeof(*job));
+ if (!job)
+ return -ENOMEM;
+
+ DRMINITLISTHEAD(&job->pushbufs);
+ job->channel = channel;
+
+ *jobp = job;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_job_free(struct drm_tegra_job *job)
+{
+ struct drm_tegra_pushbuf_private *pushbuf;
+
+ if (!job)
+ return -EINVAL;
+
+ DRMLISTFOREACHENTRY(pushbuf, &job->pushbufs, list)
+ drm_tegra_pushbuf_free(&pushbuf->base);
+
+ free(job->cmdbufs);
+ free(job->relocs);
+ free(job);
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_job_submit(struct drm_tegra_job *job,
+ struct drm_tegra_fence **fencep)
+{
+ struct drm_tegra *drm = job->channel->drm;
+ struct drm_tegra_pushbuf_private *pushbuf;
+ struct drm_tegra_fence *fence = NULL;
+ struct drm_tegra_cmdbuf *cmdbufs;
+ struct drm_tegra_syncpt *syncpts;
+ struct drm_tegra_submit args;
+ unsigned int i;
+ int err;
+
+ /*
+ * Make sure the current command stream buffer is queued for
+ * submission.
+ */
+ err = drm_tegra_pushbuf_queue(job->pushbuf);
+ if (err < 0)
+ return err;
+
+ job->pushbuf = NULL;
+
+ if (fencep) {
+ fence = calloc(1, sizeof(*fence));
+ if (!fence)
+ return -ENOMEM;
+ }
+
+ syncpts = calloc(1, sizeof(*syncpts));
+ if (!syncpts) {
+ free(cmdbufs);
+ free(fence);
+ return -ENOMEM;
+ }
+
+ syncpts[0].id = job->syncpt;
+ syncpts[0].incrs = job->increments;
+
+ memset(&args, 0, sizeof(args));
+ args.context = job->channel->context;
+ args.num_syncpts = 1;
+ args.num_cmdbufs = job->num_cmdbufs;
+ args.num_relocs = job->num_relocs;
+ args.num_waitchks = 0;
+ args.waitchk_mask = 0;
+ args.timeout = 1000;
+
+ args.syncpts = (uintptr_t)syncpts;
+ args.cmdbufs = (uintptr_t)job->cmdbufs;
+ args.relocs = (uintptr_t)job->relocs;
+ args.waitchks = 0;
+
+ err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SUBMIT, &args);
+ if (err < 0) {
+ free(syncpts);
+ free(cmdbufs);
+ free(fence);
+ return -errno;
+ }
+
+ if (fence) {
+ fence->syncpt = job->syncpt;
+ fence->value = args.fence;
+ fence->drm = drm;
+ *fencep = fence;
+ }
+
+ free(syncpts);
+ free(cmdbufs);
+
+ return 0;
+}
diff --git a/tegra/private.h b/tegra/private.h
index 9b6bc9395d23..fc74fb56b58d 100644
--- a/tegra/private.h
+++ b/tegra/private.h
@@ -26,13 +26,31 @@
#define __DRM_TEGRA_PRIVATE_H__ 1
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
#include <libdrm.h>
+#include <libdrm_lists.h>
#include <xf86atomic.h>
+#include "tegra_drm.h"
#include "tegra.h"
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); \
+ })
+
+#define align(offset, align) \
+ (((offset) + (align) - 1) & ~((align) - 1))
+
+enum host1x_class {
+ HOST1X_CLASS_HOST1X = 0x01,
+ HOST1X_CLASS_GR2D = 0x51,
+ HOST1X_CLASS_GR2D_SB = 0x52,
+ HOST1X_CLASS_GR3D = 0x60,
+};
+
struct drm_tegra {
bool close;
int fd;
@@ -40,6 +58,7 @@ struct drm_tegra {
struct drm_tegra_bo {
struct drm_tegra *drm;
+ drmMMListHead list;
uint32_t handle;
uint32_t offset;
uint32_t flags;
@@ -48,4 +67,57 @@ struct drm_tegra_bo {
void *map;
};
+struct drm_tegra_channel {
+ struct drm_tegra *drm;
+ enum host1x_class class;
+ uint64_t context;
+ uint32_t syncpt;
+};
+
+struct drm_tegra_fence {
+ struct drm_tegra *drm;
+ uint32_t syncpt;
+ uint32_t value;
+};
+
+struct drm_tegra_pushbuf_private {
+ struct drm_tegra_pushbuf base;
+ struct drm_tegra_job *job;
+ drmMMListHead list;
+ drmMMListHead bos;
+
+ struct drm_tegra_bo *bo;
+ uint32_t *start;
+ uint32_t *end;
+};
+
+static inline struct drm_tegra_pushbuf_private *
+pushbuf_priv(struct drm_tegra_pushbuf *pb)
+{
+ return container_of(pb, struct drm_tegra_pushbuf_private, base);
+}
+
+int drm_tegra_pushbuf_queue(struct drm_tegra_pushbuf_private *pushbuf);
+
+struct drm_tegra_job {
+ struct drm_tegra_channel *channel;
+
+ unsigned int increments;
+ uint32_t syncpt;
+
+ struct drm_tegra_reloc *relocs;
+ unsigned int num_relocs;
+
+ struct drm_tegra_cmdbuf *cmdbufs;
+ unsigned int num_cmdbufs;
+
+ struct drm_tegra_pushbuf_private *pushbuf;
+ drmMMListHead pushbufs;
+};
+
+int drm_tegra_job_add_reloc(struct drm_tegra_job *job,
+ const struct drm_tegra_reloc *reloc);
+int drm_tegra_job_add_cmdbuf(struct drm_tegra_job *job,
+ const struct drm_tegra_cmdbuf *cmdbuf);
+
#endif /* __DRM_TEGRA_PRIVATE_H__ */
diff --git a/tegra/pushbuf.c b/tegra/pushbuf.c
new file mode 100644
index 000000000000..178d5cd57541
--- /dev/null
+++ b/tegra/pushbuf.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright © 2012, 2013 Thierry Reding
+ * Copyright © 2013 Erik Faye-Lund
+ * Copyright © 2014 NVIDIA Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "private.h"
+
+#define HOST1X_OPCODE_NONINCR(offset, count) \
+ ((0x2 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff))
+
+int drm_tegra_pushbuf_queue(struct drm_tegra_pushbuf_private *pushbuf)
+{
+ struct drm_tegra_cmdbuf cmdbuf;
+ int err;
+
+ if (!pushbuf || !pushbuf->bo)
+ return 0;
+
+ /* unmap buffer object since it won't be accessed anymore */
+ drm_tegra_bo_unmap(pushbuf->bo);
+
+ /* 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.offset = 0;
+
+ err = drm_tegra_job_add_cmdbuf(pushbuf->job, &cmdbuf);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static inline unsigned long
+drm_tegra_pushbuf_get_offset(struct drm_tegra_pushbuf *pushbuf)
+{
+ struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
+
+ return (unsigned long)pushbuf->ptr - (unsigned long)priv->start;
+}
+
+drm_public
+int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp,
+ struct drm_tegra_job *job)
+{
+ struct drm_tegra_pushbuf_private *pushbuf;
+ void *ptr;
+ int err;
+
+ pushbuf = calloc(1, sizeof(*pushbuf));
+ if (!pushbuf)
+ return -ENOMEM;
+
+ DRMINITLISTHEAD(&pushbuf->list);
+ DRMINITLISTHEAD(&pushbuf->bos);
+ pushbuf->job = job;
+
+ *pushbufp = &pushbuf->base;
+
+ DRMLISTADD(&pushbuf->list, &job->pushbufs);
+ job->pushbuf = pushbuf;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf)
+{
+ struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
+ struct drm_tegra_bo *bo, *tmp;
+
+ if (!pushbuf)
+ return -EINVAL;
+
+ drm_tegra_bo_unmap(priv->bo);
+
+ DRMLISTFOREACHENTRYSAFE(bo, tmp, &priv->bos, list)
+ drm_tegra_bo_put(priv->bo);
+
+ DRMLISTDEL(&priv->list);
+ free(priv);
+
+ return 0;
+}
+
+/**
+ * drm_tegra_pushbuf_prepare() - prepare push buffer for a series of pushes
+ * @pushbuf: push buffer
+ * @words: maximum number of words in series of pushes to follow
+ */
+drm_public
+int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf,
+ unsigned int words)
+{
+ struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
+ struct drm_tegra_channel *channel = priv->job->channel;
+ struct drm_tegra_bo *bo;
+ void *ptr;
+ int err;
+
+ if (priv->bo && (pushbuf->ptr + words < priv->end))
+ return 0;
+
+ /*
+ * Align to full pages, since buffer object allocations are page
+ * granular anyway.
+ */
+ words = align(words, 1024);
+
+ err = drm_tegra_bo_new(&bo, channel->drm, 0, words * sizeof(uint32_t));
+ if (err < 0)
+ return err;
+
+ err = drm_tegra_bo_map(bo, &ptr);
+ if (err < 0) {
+ drm_tegra_bo_put(bo);
+ return err;
+ }
+
+ /* queue current command stream buffer for submission */
+ err = drm_tegra_pushbuf_queue(priv);
+ if (err < 0) {
+ drm_tegra_bo_unmap(bo);
+ drm_tegra_bo_put(bo);
+ return err;
+ }
+
+ DRMLISTADD(&bo->list, &priv->bos);
+
+ priv->start = priv->base.ptr = ptr;
+ priv->end = priv->start + bo->size;
+ priv->bo = bo;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf,
+ struct drm_tegra_bo *target,
+ unsigned long offset,
+ unsigned long shift)
+{
+ struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
+ struct drm_tegra_reloc reloc;
+ int err;
+
+ memset(&reloc, 0, sizeof(reloc));
+ reloc.cmdbuf.handle = priv->bo->handle;
+ reloc.cmdbuf.offset = drm_tegra_pushbuf_get_offset(pushbuf);
+ reloc.target.handle = target->handle;
+ reloc.target.offset = offset;
+ reloc.shift = shift;
+
+ err = drm_tegra_job_add_reloc(priv->job, &reloc);
+ if (err < 0)
+ return err;
+
+ *pushbuf->ptr++ = 0xdeadbeef;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf,
+ enum drm_tegra_syncpt_cond cond)
+{
+ struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
+
+ if (cond >= DRM_TEGRA_SYNCPT_COND_MAX)
+ return -EINVAL;
+
+ *pushbuf->ptr++ = HOST1X_OPCODE_NONINCR(0x0, 0x1);
+ *pushbuf->ptr++ = cond << 8 | priv->job->syncpt;
+ priv->job->increments++;
+
+ return 0;
+}
diff --git a/tegra/tegra.c b/tegra/tegra.c
index bf6d035453d5..1f7b9e7345b6 100644
--- a/tegra/tegra.c
+++ b/tegra/tegra.c
@@ -56,6 +56,7 @@ static void drm_tegra_bo_free(struct drm_tegra_bo *bo)
drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args);
+ DRMLISTDEL(&bo->list);
free(bo);
}
@@ -127,6 +128,7 @@ int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm,
if (!bo)
return -ENOMEM;
+ DRMINITLISTHEAD(&bo->list);
atomic_set(&bo->ref, 1);
bo->flags = flags;
bo->size = size;
diff --git a/tegra/tegra.h b/tegra/tegra.h
index 0731cb3bd4dc..4cf3b49a3e3e 100644
--- a/tegra/tegra.h
+++ b/tegra/tegra.h
@@ -28,6 +28,13 @@
#include <stdint.h>
#include <stdlib.h>
+#include <tegra_drm.h>
+
+enum drm_tegra_class {
+ DRM_TEGRA_GR2D,
+ DRM_TEGRA_GR3D,
+};
+
struct drm_tegra_bo;
struct drm_tegra;
@@ -44,4 +51,49 @@ int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle);
int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr);
int drm_tegra_bo_unmap(struct drm_tegra_bo *bo);
+struct drm_tegra_channel;
+struct drm_tegra_job;
+
+struct drm_tegra_pushbuf {
+ uint32_t *ptr;
+};
+
+struct drm_tegra_fence;
+
+enum drm_tegra_syncpt_cond {
+ DRM_TEGRA_SYNCPT_COND_IMMEDIATE,
+ DRM_TEGRA_SYNCPT_COND_OP_DONE,
+ DRM_TEGRA_SYNCPT_COND_RD_DONE,
+ DRM_TEGRA_SYNCPT_COND_WR_SAFE,
+ DRM_TEGRA_SYNCPT_COND_MAX,
+};
+
+int drm_tegra_channel_open(struct drm_tegra_channel **channelp,
+ struct drm_tegra *drm,
+ enum drm_tegra_class client);
+int drm_tegra_channel_close(struct drm_tegra_channel *channel);
+
+int drm_tegra_job_new(struct drm_tegra_job **jobp,
+ struct drm_tegra_channel *channel);
+int drm_tegra_job_free(struct drm_tegra_job *job);
+int drm_tegra_job_submit(struct drm_tegra_job *job,
+ struct drm_tegra_fence **fencep);
+
+int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp,
+ struct drm_tegra_job *job);
+int drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf);
+int drm_tegra_pushbuf_prepare(struct drm_tegra_pushbuf *pushbuf,
+ unsigned int words);
+int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf,
+ struct drm_tegra_bo *target,
+ unsigned long offset,
+ unsigned long shift);
+int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf,
+ enum drm_tegra_syncpt_cond cond);
+
+int drm_tegra_fence_wait_timeout(struct drm_tegra_fence *fence,
+ unsigned long timeout);
+int drm_tegra_fence_wait(struct drm_tegra_fence *fence);
+void drm_tegra_fence_free(struct drm_tegra_fence *fence);
+
#endif /* __DRM_TEGRA_H__ */
--
1.9.1
More information about the dri-devel
mailing list