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