All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@gmail.com>
To: Thierry Reding <thierry.reding@gmail.com>
Cc: dri-devel@lists.freedesktop.org, linux-tegra@vger.kernel.org
Subject: [PATCH libdrm 12/25] tegra: Add job and push buffer APIs
Date: Fri, 27 Aug 2021 15:22:52 +0200	[thread overview]
Message-ID: <20210827132305.3572077-13-thierry.reding@gmail.com> (raw)
In-Reply-To: <20210827132305.3572077-1-thierry.reding@gmail.com>

From: Thierry Reding <treding@nvidia.com>

These new functions can be used to create a job on a given channel, add
commands to the job using its push buffer and submit the job.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 tegra/job.c             | 164 ++++++++++++++++++++++++++++++++++++++++
 tegra/meson.build       |   2 +-
 tegra/private.h         |  32 ++++++++
 tegra/pushbuf.c         | 136 +++++++++++++++++++++++++++++++++
 tegra/tegra-symbols.txt |   7 ++
 tegra/tegra.h           |  34 +++++++++
 6 files changed, 374 insertions(+), 1 deletion(-)
 create mode 100644 tegra/job.c
 create mode 100644 tegra/pushbuf.c

diff --git a/tegra/job.c b/tegra/job.c
new file mode 100644
index 000000000000..c8c94e131ef0
--- /dev/null
+++ b/tegra/job.c
@@ -0,0 +1,164 @@
+/*
+ * 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 <time.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+
+#include "private.h"
+
+struct drm_tegra_submit_cmd *
+drm_tegra_job_add_command(struct drm_tegra_job *job, uint32_t type,
+                          uint32_t flags)
+{
+    struct drm_tegra_submit_cmd *commands, *command;
+    size_t size;
+
+    size = (job->num_commands + 1) * sizeof(*commands);
+
+    commands = realloc(job->commands, size);
+    if (!commands)
+        return NULL;
+
+    command = &commands[job->num_commands];
+    memset(command, 0, sizeof(*command));
+    command->type = type;
+    command->flags = flags;
+
+    job->commands = commands;
+    job->num_commands++;
+
+    return command;
+}
+
+drm_public int
+drm_tegra_job_new(struct drm_tegra_channel *channel,
+                  struct drm_tegra_job **jobp)
+{
+    struct drm_tegra_job *job;
+
+    job = calloc(1, sizeof(*job));
+    if (!job)
+        return -ENOMEM;
+
+    job->page_size = sysconf(_SC_PAGESIZE);
+    job->channel = channel;
+
+    *jobp = job;
+
+    return 0;
+}
+
+drm_public int drm_tegra_job_free(struct drm_tegra_job *job)
+{
+    if (!job)
+        return -EINVAL;
+
+    if (job->pushbuf)
+        drm_tegra_pushbuf_free(job->pushbuf);
+
+    if (job->commands)
+        free(job->commands);
+
+    if (job->buffers)
+        free(job->buffers);
+
+    free(job);
+
+    return 0;
+}
+
+drm_public int
+drm_tegra_job_get_pushbuf(struct drm_tegra_job *job,
+                          struct drm_tegra_pushbuf **pushbufp)
+{
+    struct drm_tegra_pushbuf *pushbuf;
+
+    if (!job->pushbuf) {
+        pushbuf = calloc(1, sizeof(*pushbuf));
+        if (!pushbuf)
+            return -ENOMEM;
+
+        pushbuf->job = job;
+
+        pushbuf->start = calloc(1, job->page_size);
+        if (!pushbuf->start) {
+            free(pushbuf);
+            return -ENOMEM;
+        }
+
+        pushbuf->end = pushbuf->start + job->page_size / 4;
+        pushbuf->ptr = pushbuf->start;
+
+        job->pushbuf = pushbuf;
+    }
+
+    *pushbufp = job->pushbuf;
+
+    return 0;
+}
+
+drm_public int
+drm_tegra_job_submit(struct drm_tegra_job *job, struct drm_tegra_fence *fence)
+{
+    struct drm_tegra_channel *channel = job->channel;
+    struct drm_tegra *drm = channel->drm;
+    struct drm_tegra_channel_submit args;
+    int err;
+
+    memset(&args, 0, sizeof(args));
+    args.context = channel->context;
+    args.num_bufs = job->num_buffers;
+    args.num_cmds = job->num_commands;
+    args.gather_data_words = job->pushbuf->ptr - job->pushbuf->start;
+    args.syncpt.id = job->syncpt.id;
+    args.syncpt.increments = job->syncpt.increments;
+
+    args.bufs_ptr = (uintptr_t)job->buffers;
+    args.cmds_ptr = (uintptr_t)job->commands;
+    args.gather_data_ptr = (uintptr_t)job->pushbuf->start;
+
+    err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CHANNEL_SUBMIT, &args);
+    if (err < 0)
+        return -errno;
+
+    job->syncpt.fence = args.syncpt.value;
+
+    if (fence) {
+        fence->drm = drm;
+        fence->syncpt = job->syncpt.id;
+        fence->value = job->syncpt.fence;
+    }
+
+    return 0;
+}
diff --git a/tegra/meson.build b/tegra/meson.build
index e115966fc8ed..38e43039837c 100644
--- a/tegra/meson.build
+++ b/tegra/meson.build
@@ -22,7 +22,7 @@ libdrm_tegra = library(
   'drm_tegra',
   [
     files(
-      'channel.c', 'private.h', 'tegra.c'
+      'channel.c', 'job.c', 'private.h', 'pushbuf.c', 'tegra.c'
     ),
     config_file
   ],
diff --git a/tegra/private.h b/tegra/private.h
index 7c05276707bf..970ee8ad66d4 100644
--- a/tegra/private.h
+++ b/tegra/private.h
@@ -72,4 +72,36 @@ struct drm_tegra_mapping {
     uint32_t id;
 };
 
+struct drm_tegra_pushbuf {
+    struct drm_tegra_job *job;
+
+    uint32_t *start;
+    uint32_t *end;
+    uint32_t *ptr;
+};
+
+void drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf);
+
+struct drm_tegra_job {
+    struct drm_tegra_channel *channel;
+    struct drm_tegra_pushbuf *pushbuf;
+    size_t page_size;
+
+    struct drm_tegra_submit_cmd *commands;
+    unsigned int num_commands;
+
+    struct drm_tegra_submit_buf *buffers;
+    unsigned int num_buffers;
+
+    struct {
+        uint32_t id;
+        uint32_t increments;
+        uint32_t fence;
+    } syncpt;
+};
+
+struct drm_tegra_submit_cmd *
+drm_tegra_job_add_command(struct drm_tegra_job *job, uint32_t type,
+                          uint32_t flags);
+
 #endif /* __DRM_TEGRA_PRIVATE_H__ */
diff --git a/tegra/pushbuf.c b/tegra/pushbuf.c
new file mode 100644
index 000000000000..380a50abbbb0
--- /dev/null
+++ b/tegra/pushbuf.c
@@ -0,0 +1,136 @@
+/*
+ * 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 "util_math.h"
+#include "private.h"
+
+#define HOST1X_OPCODE_NONINCR(offset, count) \
+    ((0x2 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff))
+
+static inline unsigned int
+drm_tegra_pushbuf_get_offset(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr)
+{
+    return ptr - pushbuf->start;
+}
+
+void drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf)
+{
+    if (pushbuf->start)
+        free(pushbuf->start);
+
+    free(pushbuf);
+}
+
+/**
+ * drm_tegra_pushbuf_begin() - 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_begin(struct drm_tegra_pushbuf *pushbuf,
+                        unsigned int words, uint32_t **ptrp)
+{
+    struct drm_tegra_job *job = pushbuf->job;
+    unsigned long offset;
+    size_t size;
+    void *ptr;
+
+    if (pushbuf->ptr + words >= pushbuf->end) {
+        words = pushbuf->end - pushbuf->start + words;
+        size = ALIGN(words * 4, job->page_size);
+        offset = pushbuf->ptr - pushbuf->start;
+
+        ptr = realloc(pushbuf->start, size);
+        if (!ptr)
+            return -ENOMEM;
+
+        pushbuf->start = ptr;
+        pushbuf->end = pushbuf->start + size / 4;
+        pushbuf->ptr = pushbuf->start + offset;
+    }
+
+    if (ptrp)
+        *ptrp = pushbuf->ptr;
+
+    return 0;
+}
+
+drm_public int
+drm_tegra_pushbuf_end(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr)
+{
+    struct drm_tegra_submit_cmd *command;
+
+    command = drm_tegra_job_add_command(pushbuf->job,
+                                        DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR,
+                                        0);
+    if (!command)
+        return -ENOMEM;
+
+    command->gather_uptr.words = ptr - pushbuf->start;
+    pushbuf->ptr = ptr;
+
+    return 0;
+}
+
+drm_public int
+drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, uint32_t **ptrp,
+                           struct drm_tegra_mapping *target,
+                           unsigned long offset, unsigned int shift,
+                           uint32_t flags)
+{
+    struct drm_tegra_submit_buf *buffers, *buffer;
+    struct drm_tegra_job *job = pushbuf->job;
+    size_t size;
+
+    size = (job->num_buffers + 1) * sizeof(*buffer);
+
+    buffers = realloc(job->buffers, size);
+    if (!buffers)
+        return -ENOMEM;
+
+    buffer = &buffers[job->num_buffers];
+
+    memset(buffer, 0, sizeof(*buffer));
+    buffer->mapping = target->id;
+    buffer->flags = flags;
+    buffer->reloc.target_offset = offset;
+    buffer->reloc.gather_offset_words = drm_tegra_pushbuf_get_offset(pushbuf,
+                                                                     *ptrp);
+    buffer->reloc.shift = shift;
+
+    *(*ptrp)++ = 0xdeadbeef;
+
+    job->buffers = buffers;
+    job->num_buffers++;
+
+    return 0;
+}
diff --git a/tegra/tegra-symbols.txt b/tegra/tegra-symbols.txt
index c16a351171f1..da3972cb99e1 100644
--- a/tegra/tegra-symbols.txt
+++ b/tegra/tegra-symbols.txt
@@ -15,4 +15,11 @@ drm_tegra_channel_map
 drm_tegra_channel_open
 drm_tegra_channel_unmap
 drm_tegra_close
+drm_tegra_job_free
+drm_tegra_job_get_pushbuf
+drm_tegra_job_new
+drm_tegra_job_submit
 drm_tegra_new
+drm_tegra_pushbuf_begin
+drm_tegra_pushbuf_end
+drm_tegra_pushbuf_relocate
diff --git a/tegra/tegra.h b/tegra/tegra.h
index 621fef6b7000..0213e3b11e04 100644
--- a/tegra/tegra.h
+++ b/tegra/tegra.h
@@ -63,6 +63,22 @@ int drm_tegra_bo_import(struct drm_tegra *drm, int fd,
 
 struct drm_tegra_channel;
 struct drm_tegra_mapping;
+struct drm_tegra_pushbuf;
+struct drm_tegra_job;
+
+enum drm_tegra_sync_cond {
+    DRM_TEGRA_SYNC_COND_IMMEDIATE,
+    DRM_TEGRA_SYNC_COND_OP_DONE,
+    DRM_TEGRA_SYNC_COND_RD_DONE,
+    DRM_TEGRA_SYNC_COND_WR_SAFE,
+    DRM_TEGRA_SYNC_COND_MAX,
+  };
+
+struct drm_tegra_fence {
+    struct drm_tegra *drm;
+    uint32_t syncpt;
+    uint32_t value;
+};
 
 int drm_tegra_channel_open(struct drm_tegra *drm,
                            enum drm_tegra_class client,
@@ -74,4 +90,22 @@ int drm_tegra_channel_map(struct drm_tegra_channel *channel,
                           struct drm_tegra_mapping **mapp);
 int drm_tegra_channel_unmap(struct drm_tegra_mapping *map);
 
+int drm_tegra_job_new(struct drm_tegra_channel *channel,
+                      struct drm_tegra_job **jobp);
+int drm_tegra_job_free(struct drm_tegra_job *job);
+int drm_tegra_job_get_pushbuf(struct drm_tegra_job *job,
+                              struct drm_tegra_pushbuf **pushbufp);
+int drm_tegra_job_submit(struct drm_tegra_job *job,
+                         struct drm_tegra_fence *fence);
+int drm_tegra_job_wait(struct drm_tegra_job *job, unsigned long timeout);
+
+int drm_tegra_pushbuf_begin(struct drm_tegra_pushbuf *pushbuf,
+                            unsigned int words, uint32_t **ptrp);
+int drm_tegra_pushbuf_end(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr);
+int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf,
+                               uint32_t **ptrp,
+                               struct drm_tegra_mapping *target,
+                               unsigned long offset, unsigned int shift,
+                               uint32_t flags);
+
 #endif /* __DRM_TEGRA_H__ */
-- 
2.32.0


  parent reply	other threads:[~2021-08-27 13:23 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-27 13:22 [PATCH libdrm 00/25] Update Tegra support Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 01/25] tegra: Indent according to .editorconfig Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 02/25] tegra: Remove unused IOCTL implementations Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 03/25] tegra: Extract common buffer object allocation code Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 04/25] tegra: Fix mmap() of GEM buffer objects Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 05/25] tegra: Add flink helpers Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 06/25] tegra: Add PRIME support helpers Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 07/25] tegra: Make API more consistent Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 08/25] tegra: Install tegra-openclose test Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 09/25] tegra: Update for new UABI Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 10/25] tegra: Include private.h in list of source files Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 11/25] tegra: Add channel APIs Thierry Reding
2021-08-27 13:22 ` Thierry Reding [this message]
2021-08-27 13:22 ` [PATCH libdrm 13/25] tegra: Add syncpoint APIs Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 14/25] tests: tegra: Add helper library for tests Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 15/25] tests: tegra: Add gr2d-fill test Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 16/25] tests: tegra: Add syncpt-wait test Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 17/25] tests: tegra: Add syncpoint timeout test Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 18/25] tests: tegra: Add VIC support Thierry Reding
2021-08-27 13:22 ` [PATCH libdrm 19/25] tests: tegra: Add VIC 3.0 support Thierry Reding
2021-08-27 14:06   ` Michał Mirosław
2021-08-27 13:23 ` [PATCH libdrm 20/25] tests: tegra: Add VIC 4.0 support Thierry Reding
2021-08-27 13:23 ` [PATCH libdrm 21/25] tests: tegra: Add VIC 4.1 support Thierry Reding
2021-08-27 13:23 ` [PATCH libdrm 22/25] tests: tegra: Add VIC 4.2 support Thierry Reding
2021-08-27 13:23 ` [PATCH libdrm 23/25] tests: tegra: Add VIC clear test Thierry Reding
2021-08-27 13:23 ` [PATCH libdrm 24/25] tests: tegra: Add VIC blit test Thierry Reding
2021-08-27 13:23 ` [PATCH libdrm 25/25] tests: tegra: Add VIC flip test Thierry Reding
2021-09-20 16:43 ` [PATCH libdrm 00/25] Update Tegra support Dmitry Osipenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210827132305.3572077-13-thierry.reding@gmail.com \
    --to=thierry.reding@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-tegra@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.