1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2018 Rob Clark <robclark@freedesktop.org>
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Rob Clark <robclark@freedesktop.org>
25bf215546Sopenharmony_ci */
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include <assert.h>
28bf215546Sopenharmony_ci#include <inttypes.h>
29bf215546Sopenharmony_ci#include <pthread.h>
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "util/os_file.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "drm/freedreno_ringbuffer_sp.h"
34bf215546Sopenharmony_ci#include "msm_priv.h"
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_cistatic int
37bf215546Sopenharmony_ciflush_submit_list(struct list_head *submit_list)
38bf215546Sopenharmony_ci{
39bf215546Sopenharmony_ci   struct fd_submit_sp *fd_submit = to_fd_submit_sp(last_submit(submit_list));
40bf215546Sopenharmony_ci   struct msm_pipe *msm_pipe = to_msm_pipe(fd_submit->base.pipe);
41bf215546Sopenharmony_ci   struct drm_msm_gem_submit req = {
42bf215546Sopenharmony_ci      .flags = msm_pipe->pipe,
43bf215546Sopenharmony_ci      .queueid = msm_pipe->queue_id,
44bf215546Sopenharmony_ci   };
45bf215546Sopenharmony_ci   int ret;
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci   unsigned nr_cmds = 0;
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci   /* Determine the number of extra cmds's from deferred submits that
50bf215546Sopenharmony_ci    * we will be merging in:
51bf215546Sopenharmony_ci    */
52bf215546Sopenharmony_ci   foreach_submit (submit, submit_list) {
53bf215546Sopenharmony_ci      assert(submit->pipe == &msm_pipe->base);
54bf215546Sopenharmony_ci      nr_cmds += to_fd_ringbuffer_sp(submit->primary)->u.nr_cmds;
55bf215546Sopenharmony_ci   }
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci   struct drm_msm_gem_submit_cmd cmds[nr_cmds];
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   unsigned cmd_idx = 0;
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   /* Build up the table of cmds, and for all but the last submit in the
62bf215546Sopenharmony_ci    * list, merge their bo tables into the last submit.
63bf215546Sopenharmony_ci    */
64bf215546Sopenharmony_ci   foreach_submit_safe (submit, submit_list) {
65bf215546Sopenharmony_ci      struct fd_ringbuffer_sp *deferred_primary =
66bf215546Sopenharmony_ci         to_fd_ringbuffer_sp(submit->primary);
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci      for (unsigned i = 0; i < deferred_primary->u.nr_cmds; i++) {
69bf215546Sopenharmony_ci         cmds[cmd_idx].type = MSM_SUBMIT_CMD_BUF;
70bf215546Sopenharmony_ci         cmds[cmd_idx].submit_idx =
71bf215546Sopenharmony_ci               fd_submit_append_bo(fd_submit, deferred_primary->u.cmds[i].ring_bo);
72bf215546Sopenharmony_ci         cmds[cmd_idx].submit_offset = deferred_primary->offset;
73bf215546Sopenharmony_ci         cmds[cmd_idx].size = deferred_primary->u.cmds[i].size;
74bf215546Sopenharmony_ci         cmds[cmd_idx].pad = 0;
75bf215546Sopenharmony_ci         cmds[cmd_idx].nr_relocs = 0;
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci         cmd_idx++;
78bf215546Sopenharmony_ci      }
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci      /* We are merging all the submits in the list into the last submit,
81bf215546Sopenharmony_ci       * so the remainder of the loop body doesn't apply to the last submit
82bf215546Sopenharmony_ci       */
83bf215546Sopenharmony_ci      if (submit == last_submit(submit_list)) {
84bf215546Sopenharmony_ci         DEBUG_MSG("merged %u submits", cmd_idx);
85bf215546Sopenharmony_ci         break;
86bf215546Sopenharmony_ci      }
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci      struct fd_submit_sp *fd_deferred_submit = to_fd_submit_sp(submit);
89bf215546Sopenharmony_ci      for (unsigned i = 0; i < fd_deferred_submit->nr_bos; i++) {
90bf215546Sopenharmony_ci         /* Note: if bo is used in both the current submit and the deferred
91bf215546Sopenharmony_ci          * submit being merged, we expect to hit the fast-path as we add it
92bf215546Sopenharmony_ci          * to the current submit:
93bf215546Sopenharmony_ci          */
94bf215546Sopenharmony_ci         fd_submit_append_bo(fd_submit, fd_deferred_submit->bos[i]);
95bf215546Sopenharmony_ci      }
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci      /* Now that the cmds/bos have been transfered over to the current submit,
98bf215546Sopenharmony_ci       * we can remove the deferred submit from the list and drop it's reference
99bf215546Sopenharmony_ci       */
100bf215546Sopenharmony_ci      list_del(&submit->node);
101bf215546Sopenharmony_ci      fd_submit_del(submit);
102bf215546Sopenharmony_ci   }
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   if (fd_submit->in_fence_fd != -1) {
105bf215546Sopenharmony_ci      req.flags |= MSM_SUBMIT_FENCE_FD_IN;
106bf215546Sopenharmony_ci      req.fence_fd = fd_submit->in_fence_fd;
107bf215546Sopenharmony_ci      msm_pipe->no_implicit_sync = true;
108bf215546Sopenharmony_ci   }
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci   if (msm_pipe->no_implicit_sync) {
111bf215546Sopenharmony_ci      req.flags |= MSM_SUBMIT_NO_IMPLICIT;
112bf215546Sopenharmony_ci   }
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   if (fd_submit->out_fence && fd_submit->out_fence->use_fence_fd) {
115bf215546Sopenharmony_ci      req.flags |= MSM_SUBMIT_FENCE_FD_OUT;
116bf215546Sopenharmony_ci   }
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   /* Needs to be after get_cmd() as that could create bos/cmds table:
119bf215546Sopenharmony_ci    *
120bf215546Sopenharmony_ci    * NOTE allocate on-stack in the common case, but with an upper-
121bf215546Sopenharmony_ci    * bound to limit on-stack allocation to 4k:
122bf215546Sopenharmony_ci    */
123bf215546Sopenharmony_ci   const unsigned bo_limit = 4096 / sizeof(struct drm_msm_gem_submit_bo);
124bf215546Sopenharmony_ci   bool bos_on_stack = fd_submit->nr_bos < bo_limit;
125bf215546Sopenharmony_ci   struct drm_msm_gem_submit_bo
126bf215546Sopenharmony_ci      _submit_bos[bos_on_stack ? fd_submit->nr_bos : 0];
127bf215546Sopenharmony_ci   struct drm_msm_gem_submit_bo *submit_bos;
128bf215546Sopenharmony_ci   if (bos_on_stack) {
129bf215546Sopenharmony_ci      submit_bos = _submit_bos;
130bf215546Sopenharmony_ci   } else {
131bf215546Sopenharmony_ci      submit_bos = malloc(fd_submit->nr_bos * sizeof(submit_bos[0]));
132bf215546Sopenharmony_ci   }
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   for (unsigned i = 0; i < fd_submit->nr_bos; i++) {
135bf215546Sopenharmony_ci      submit_bos[i].flags = fd_submit->bos[i]->reloc_flags;
136bf215546Sopenharmony_ci      submit_bos[i].handle = fd_submit->bos[i]->handle;
137bf215546Sopenharmony_ci      submit_bos[i].presumed = 0;
138bf215546Sopenharmony_ci   }
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   req.bos = VOID2U64(submit_bos);
141bf215546Sopenharmony_ci   req.nr_bos = fd_submit->nr_bos;
142bf215546Sopenharmony_ci   req.cmds = VOID2U64(cmds);
143bf215546Sopenharmony_ci   req.nr_cmds = nr_cmds;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos);
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   ret = drmCommandWriteRead(msm_pipe->base.dev->fd, DRM_MSM_GEM_SUBMIT, &req,
148bf215546Sopenharmony_ci                             sizeof(req));
149bf215546Sopenharmony_ci   if (ret) {
150bf215546Sopenharmony_ci      ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno));
151bf215546Sopenharmony_ci      msm_dump_submit(&req);
152bf215546Sopenharmony_ci   } else if (!ret && fd_submit->out_fence) {
153bf215546Sopenharmony_ci      fd_submit->out_fence->fence.kfence = req.fence;
154bf215546Sopenharmony_ci      fd_submit->out_fence->fence.ufence = fd_submit->base.fence;
155bf215546Sopenharmony_ci      fd_submit->out_fence->fence_fd = req.fence_fd;
156bf215546Sopenharmony_ci   }
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   if (!bos_on_stack)
159bf215546Sopenharmony_ci      free(submit_bos);
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   if (fd_submit->in_fence_fd != -1)
162bf215546Sopenharmony_ci      close(fd_submit->in_fence_fd);
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   return ret;
165bf215546Sopenharmony_ci}
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_cistruct fd_submit *
168bf215546Sopenharmony_cimsm_submit_sp_new(struct fd_pipe *pipe)
169bf215546Sopenharmony_ci{
170bf215546Sopenharmony_ci   /* We don't do any translation from internal FD_RELOC flags to MSM flags. */
171bf215546Sopenharmony_ci   STATIC_ASSERT(FD_RELOC_READ == MSM_SUBMIT_BO_READ);
172bf215546Sopenharmony_ci   STATIC_ASSERT(FD_RELOC_WRITE == MSM_SUBMIT_BO_WRITE);
173bf215546Sopenharmony_ci   STATIC_ASSERT(FD_RELOC_DUMP == MSM_SUBMIT_BO_DUMP);
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci   return fd_submit_sp_new(pipe, flush_submit_list);
176bf215546Sopenharmony_ci}
177