@@ -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
new file mode 100644
@@ -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_open_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;
+}
new file mode 100644
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+ drmMsg("DRM_IOCTL_TEGRA_SYNCPT_WAIT: %d\n", -errno);
+ 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);
+}
new file mode 100644
@@ -0,0 +1,167 @@
+/*
+ * 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;
+}
+
+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->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;
+
+ if (fencep) {
+ fence = calloc(1, sizeof(*fence));
+ if (!fence)
+ return -ENOMEM;
+ }
+
+ cmdbufs = calloc(job->num_pushbufs, sizeof(*cmdbufs));
+ if (!cmdbufs) {
+ free(fence);
+ return -ENOMEM;
+ }
+
+ DRMLISTFOREACHENTRY(pushbuf, &job->pushbufs, list) {
+ struct drm_tegra_cmdbuf *cmdbuf = &cmdbufs[i];
+
+ cmdbuf->handle = pushbuf->bo->handle;
+ cmdbuf->offset = pushbuf->offset;
+ cmdbuf->words = pushbuf->base.ptr - pushbuf->start;
+ }
+
+ 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_pushbufs;
+ 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)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;
+ }
+
+ if (fencep)
+ *fencep = fence;
+
+ free(syncpts);
+ free(cmdbufs);
+
+ return 0;
+}
@@ -26,10 +26,13 @@
#define __DRM_TEGRA_PRIVATE_H__ 1
#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
+#include <libdrm_lists.h>
#include <xf86atomic.h>
+#include "tegra_drm.h"
#include "tegra.h"
#if defined(HAVE_VISIBILITY)
@@ -40,6 +43,18 @@
# define drm_public
#endif
+#define container_of(ptr, type, member) ({ \
+ const typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); \
+ })
+
+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;
@@ -55,4 +70,48 @@ 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;
+ struct drm_tegra_bo *bo;
+ unsigned long offset;
+ drmMMListHead list;
+ uint32_t *start;
+};
+
+static inline struct drm_tegra_pushbuf_private *
+pushbuf_priv(struct drm_tegra_pushbuf *pb)
+{
+ return container_of(pb, struct drm_tegra_pushbuf_private, base);
+}
+
+struct drm_tegra_job {
+ struct drm_tegra_channel *channel;
+
+ unsigned int increments;
+ uint32_t syncpt;
+
+ struct drm_tegra_reloc *relocs;
+ unsigned int num_relocs;
+
+ unsigned int num_pushbufs;
+ drmMMListHead pushbufs;
+};
+
+int drm_tegra_job_add_reloc(struct drm_tegra_job *job,
+ const struct drm_tegra_reloc *reloc);
+
#endif /* __DRM_TEGRA_PRIVATE_H__ */
new file mode 100644
@@ -0,0 +1,137 @@
+/*
+ * 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))
+
+static inline unsigned long
+drm_tegra_pushbuf_get_offset(struct drm_tegra_pushbuf *pushbuf)
+{
+ struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
+ struct drm_tegra_bo *bo = priv->bo;
+
+ return (unsigned long)pushbuf->ptr - (unsigned long)bo->map;
+}
+
+drm_public
+int drm_tegra_pushbuf_new(struct drm_tegra_pushbuf **pushbufp,
+ struct drm_tegra_job *job,
+ struct drm_tegra_bo *bo,
+ unsigned long offset)
+{
+ struct drm_tegra_pushbuf_private *pushbuf;
+ void *ptr;
+ int err;
+
+ pushbuf = calloc(1, sizeof(*pushbuf));
+ if (!pushbuf)
+ return -ENOMEM;
+
+ pushbuf->bo = drm_tegra_bo_get(bo);
+ DRMINITLISTHEAD(&pushbuf->list);
+ pushbuf->job = job;
+
+ err = drm_tegra_bo_map(bo, &ptr);
+ if (err < 0) {
+ drm_tegra_bo_put(bo);
+ free(pushbuf);
+ return err;
+ }
+
+ pushbuf->start = pushbuf->base.ptr = ptr + offset;
+ pushbuf->offset = offset;
+
+ DRMLISTADD(&pushbuf->list, &job->pushbufs);
+ job->num_pushbufs++;
+
+ *pushbufp = &pushbuf->base;
+
+ return 0;
+}
+
+drm_public
+int drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf)
+{
+ struct drm_tegra_pushbuf_private *priv = pushbuf_priv(pushbuf);
+
+ if (!pushbuf)
+ return -EINVAL;
+
+ drm_tegra_bo_unmap(priv->bo);
+ drm_tegra_bo_put(priv->bo);
+ DRMLISTDEL(&priv->list);
+ free(priv);
+
+ 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;
+
+ 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;
+}
@@ -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,
+ struct drm_tegra_bo *bo,
+ unsigned long offset);
+int drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf);
+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__ */