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 36static int 37flush_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 167struct fd_submit * 168msm_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