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