• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 fd_pipe *pipe = fd_submit->base.pipe;
41    struct msm_pipe *msm_pipe = to_msm_pipe(pipe);
42    struct drm_msm_gem_submit req = {
43       .flags = msm_pipe->pipe,
44       .queueid = msm_pipe->queue_id,
45    };
46    int ret;
47 
48    unsigned nr_cmds = 0;
49 
50    MESA_TRACE_FUNC();
51 
52    /* Determine the number of extra cmds's from deferred submits that
53     * we will be merging in:
54     */
55    foreach_submit (submit, submit_list) {
56       assert(submit->pipe == &msm_pipe->base);
57       nr_cmds += to_fd_ringbuffer_sp(submit->primary)->u.nr_cmds;
58    }
59 
60    struct drm_msm_gem_submit_cmd cmds[nr_cmds];
61 
62    unsigned cmd_idx = 0;
63 
64    /* Build up the table of cmds, and for all but the last submit in the
65     * list, merge their bo tables into the last submit.
66     */
67    foreach_submit_safe (submit, submit_list) {
68       struct fd_ringbuffer_sp *deferred_primary =
69          to_fd_ringbuffer_sp(submit->primary);
70 
71       for (unsigned i = 0; i < deferred_primary->u.nr_cmds; i++) {
72          struct fd_bo *ring_bo = deferred_primary->u.cmds[i].ring_bo;
73          cmds[cmd_idx].type = MSM_SUBMIT_CMD_BUF;
74          cmds[cmd_idx].submit_idx = fd_submit_append_bo(fd_submit, ring_bo);
75          cmds[cmd_idx].submit_offset = submit_offset(ring_bo, deferred_primary->offset);
76          cmds[cmd_idx].size = deferred_primary->u.cmds[i].size;
77          cmds[cmd_idx].pad = 0;
78          cmds[cmd_idx].nr_relocs = 0;
79 
80          cmd_idx++;
81       }
82 
83       /* We are merging all the submits in the list into the last submit,
84        * so the remainder of the loop body doesn't apply to the last submit
85        */
86       if (submit == last_submit(submit_list)) {
87          DEBUG_MSG("merged %u submits", cmd_idx);
88          break;
89       }
90 
91       struct fd_submit_sp *fd_deferred_submit = to_fd_submit_sp(submit);
92       for (unsigned i = 0; i < fd_deferred_submit->nr_bos; i++) {
93          /* Note: if bo is used in both the current submit and the deferred
94           * submit being merged, we expect to hit the fast-path as we add it
95           * to the current submit:
96           */
97          fd_submit_append_bo(fd_submit, fd_deferred_submit->bos[i]);
98       }
99 
100       /* Now that the cmds/bos have been transfered over to the current submit,
101        * we can remove the deferred submit from the list and drop it's reference
102        */
103       list_del(&submit->node);
104       fd_submit_del(submit);
105    }
106 
107    if (fd_submit->in_fence_fd != -1) {
108       req.flags |= MSM_SUBMIT_FENCE_FD_IN;
109       req.fence_fd = fd_submit->in_fence_fd;
110    }
111 
112    if (pipe->no_implicit_sync) {
113       req.flags |= MSM_SUBMIT_NO_IMPLICIT;
114    }
115 
116    if (fd_submit->out_fence->use_fence_fd) {
117       req.flags |= MSM_SUBMIT_FENCE_FD_OUT;
118    }
119 
120    /* Needs to be after get_cmd() as that could create bos/cmds table:
121     *
122     * NOTE allocate on-stack in the common case, but with an upper-
123     * bound to limit on-stack allocation to 4k:
124     */
125    const unsigned bo_limit = 4096 / sizeof(struct drm_msm_gem_submit_bo);
126    bool bos_on_stack = fd_submit->nr_bos < bo_limit;
127    struct drm_msm_gem_submit_bo
128       _submit_bos[bos_on_stack ? fd_submit->nr_bos : 0];
129    struct drm_msm_gem_submit_bo *submit_bos;
130    if (bos_on_stack) {
131       submit_bos = _submit_bos;
132    } else {
133       submit_bos = malloc(fd_submit->nr_bos * sizeof(submit_bos[0]));
134    }
135 
136    for (unsigned i = 0; i < fd_submit->nr_bos; i++) {
137       submit_bos[i].flags = fd_submit->bos[i]->reloc_flags;
138       submit_bos[i].handle = fd_submit->bos[i]->handle;
139       submit_bos[i].presumed = 0;
140    }
141 
142    req.bos = VOID2U64(submit_bos);
143    req.nr_bos = fd_submit->nr_bos;
144    req.cmds = VOID2U64(cmds);
145    req.nr_cmds = nr_cmds;
146 
147    DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos);
148 
149    ret = drmCommandWriteRead(msm_pipe->base.dev->fd, DRM_MSM_GEM_SUBMIT, &req,
150                              sizeof(req));
151    if (ret) {
152       ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno));
153       msm_dump_submit(&req);
154    } else if (!ret) {
155       fd_submit->out_fence->kfence = req.fence;
156       fd_submit->out_fence->fence_fd = req.fence_fd;
157    }
158 
159    if (!bos_on_stack)
160       free(submit_bos);
161 
162    if (fd_submit->in_fence_fd != -1)
163       close(fd_submit->in_fence_fd);
164 
165    return ret;
166 }
167 
168 struct fd_submit *
msm_submit_sp_new(struct fd_pipe * pipe)169 msm_submit_sp_new(struct fd_pipe *pipe)
170 {
171    /* We don't do any translation from internal FD_RELOC flags to MSM flags. */
172    STATIC_ASSERT(FD_RELOC_READ == MSM_SUBMIT_BO_READ);
173    STATIC_ASSERT(FD_RELOC_WRITE == MSM_SUBMIT_BO_WRITE);
174    STATIC_ASSERT(FD_RELOC_DUMP == MSM_SUBMIT_BO_DUMP);
175 
176    return fd_submit_sp_new(pipe, flush_submit_list);
177 }
178