17e102996Smaya/* 27e102996Smaya * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 37e102996Smaya * 47e102996Smaya * Permission is hereby granted, free of charge, to any person obtaining a 57e102996Smaya * copy of this software and associated documentation files (the "Software"), 67e102996Smaya * to deal in the Software without restriction, including without limitation 77e102996Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87e102996Smaya * and/or sell copies of the Software, and to permit persons to whom the 97e102996Smaya * Software is furnished to do so, subject to the following conditions: 107e102996Smaya * 117e102996Smaya * The above copyright notice and this permission notice (including the next 127e102996Smaya * paragraph) shall be included in all copies or substantial portions of the 137e102996Smaya * Software. 147e102996Smaya * 157e102996Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167e102996Smaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177e102996Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187e102996Smaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197e102996Smaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 207e102996Smaya * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 217e102996Smaya * SOFTWARE. 227e102996Smaya * 237e102996Smaya * Authors: 247e102996Smaya * Rob Clark <robclark@freedesktop.org> 257e102996Smaya */ 267e102996Smaya 277e102996Smaya#include <assert.h> 287e102996Smaya#include <inttypes.h> 297e102996Smaya 307e102996Smaya#include "util/hash_table.h" 317e102996Smaya#include "util/set.h" 327e102996Smaya#include "util/slab.h" 337e102996Smaya 347e102996Smaya#include "drm/freedreno_ringbuffer.h" 357e102996Smaya#include "msm_priv.h" 367e102996Smaya 377e102996Smaya/* The legacy implementation of submit/ringbuffer, which still does the 387e102996Smaya * traditional reloc and cmd tracking 397e102996Smaya */ 407e102996Smaya 417e102996Smaya#define INIT_SIZE 0x1000 427e102996Smaya 437e102996Smayastruct msm_submit { 447ec681f3Smrg struct fd_submit base; 457e102996Smaya 467ec681f3Smrg DECLARE_ARRAY(struct drm_msm_gem_submit_bo, submit_bos); 477ec681f3Smrg DECLARE_ARRAY(struct fd_bo *, bos); 487e102996Smaya 497ec681f3Smrg /* maps fd_bo to idx in bos table: */ 507ec681f3Smrg struct hash_table *bo_table; 517e102996Smaya 527ec681f3Smrg struct slab_mempool ring_pool; 537e102996Smaya 547ec681f3Smrg /* hash-set of associated rings: */ 557ec681f3Smrg struct set *ring_set; 567e102996Smaya 577ec681f3Smrg /* Allow for sub-allocation of stateobj ring buffers (ie. sharing 587ec681f3Smrg * the same underlying bo).. 597ec681f3Smrg * 607ec681f3Smrg * We also rely on previous stateobj having been fully constructed 617ec681f3Smrg * so we can reclaim extra space at it's end. 627ec681f3Smrg */ 637ec681f3Smrg struct fd_ringbuffer *suballoc_ring; 647e102996Smaya}; 657e102996SmayaFD_DEFINE_CAST(fd_submit, msm_submit); 667e102996Smaya 677e102996Smaya/* for FD_RINGBUFFER_GROWABLE rb's, tracks the 'finalized' cmdstream buffers 687e102996Smaya * and sizes. Ie. a finalized buffer can have no more commands appended to 697e102996Smaya * it. 707e102996Smaya */ 717e102996Smayastruct msm_cmd { 727ec681f3Smrg struct fd_bo *ring_bo; 737ec681f3Smrg unsigned size; 747ec681f3Smrg DECLARE_ARRAY(struct drm_msm_gem_submit_reloc, relocs); 757e102996Smaya}; 767e102996Smaya 777e102996Smayastatic struct msm_cmd * 787e102996Smayacmd_new(struct fd_bo *ring_bo) 797e102996Smaya{ 807ec681f3Smrg struct msm_cmd *cmd = malloc(sizeof(*cmd)); 817ec681f3Smrg cmd->ring_bo = fd_bo_ref(ring_bo); 827ec681f3Smrg cmd->size = 0; 837ec681f3Smrg cmd->nr_relocs = cmd->max_relocs = 0; 847ec681f3Smrg cmd->relocs = NULL; 857ec681f3Smrg return cmd; 867e102996Smaya} 877e102996Smaya 887e102996Smayastatic void 897e102996Smayacmd_free(struct msm_cmd *cmd) 907e102996Smaya{ 917ec681f3Smrg fd_bo_del(cmd->ring_bo); 927ec681f3Smrg free(cmd->relocs); 937ec681f3Smrg free(cmd); 947e102996Smaya} 957e102996Smaya 967e102996Smayastruct msm_ringbuffer { 977ec681f3Smrg struct fd_ringbuffer base; 987ec681f3Smrg 997ec681f3Smrg /* for FD_RINGBUFFER_STREAMING rb's which are sub-allocated */ 1007ec681f3Smrg unsigned offset; 1017ec681f3Smrg 1027ec681f3Smrg union { 1037ec681f3Smrg /* for _FD_RINGBUFFER_OBJECT case: */ 1047ec681f3Smrg struct { 1057ec681f3Smrg struct fd_pipe *pipe; 1067ec681f3Smrg DECLARE_ARRAY(struct fd_bo *, reloc_bos); 1077ec681f3Smrg struct set *ring_set; 1087ec681f3Smrg }; 1097ec681f3Smrg /* for other cases: */ 1107ec681f3Smrg struct { 1117ec681f3Smrg struct fd_submit *submit; 1127ec681f3Smrg DECLARE_ARRAY(struct msm_cmd *, cmds); 1137ec681f3Smrg }; 1147ec681f3Smrg } u; 1157ec681f3Smrg 1167ec681f3Smrg struct msm_cmd *cmd; /* current cmd */ 1177ec681f3Smrg struct fd_bo *ring_bo; 1187e102996Smaya}; 1197e102996SmayaFD_DEFINE_CAST(fd_ringbuffer, msm_ringbuffer); 1207e102996Smaya 1217e102996Smayastatic void finalize_current_cmd(struct fd_ringbuffer *ring); 1227ec681f3Smrgstatic struct fd_ringbuffer * 1237ec681f3Smrgmsm_ringbuffer_init(struct msm_ringbuffer *msm_ring, uint32_t size, 1247ec681f3Smrg enum fd_ringbuffer_flags flags); 1257e102996Smaya 1267e102996Smaya/* add (if needed) bo to submit and return index: */ 1277e102996Smayastatic uint32_t 1287ec681f3Smrgappend_bo(struct msm_submit *submit, struct fd_bo *bo) 1297e102996Smaya{ 1307ec681f3Smrg struct msm_bo *msm_bo = to_msm_bo(bo); 1317ec681f3Smrg uint32_t idx; 1327ec681f3Smrg 1337ec681f3Smrg /* NOTE: it is legal to use the same bo on different threads for 1347ec681f3Smrg * different submits. But it is not legal to use the same submit 1357ec681f3Smrg * from given threads. 1367ec681f3Smrg */ 1377ec681f3Smrg idx = READ_ONCE(msm_bo->idx); 1387ec681f3Smrg 1397ec681f3Smrg if (unlikely((idx >= submit->nr_submit_bos) || 1407ec681f3Smrg (submit->submit_bos[idx].handle != bo->handle))) { 1417ec681f3Smrg uint32_t hash = _mesa_hash_pointer(bo); 1427ec681f3Smrg struct hash_entry *entry; 1437ec681f3Smrg 1447ec681f3Smrg entry = _mesa_hash_table_search_pre_hashed(submit->bo_table, hash, bo); 1457ec681f3Smrg if (entry) { 1467ec681f3Smrg /* found */ 1477ec681f3Smrg idx = (uint32_t)(uintptr_t)entry->data; 1487ec681f3Smrg } else { 1497ec681f3Smrg idx = APPEND( 1507ec681f3Smrg submit, submit_bos, 1517ec681f3Smrg (struct drm_msm_gem_submit_bo){ 1527ec681f3Smrg .flags = bo->reloc_flags & (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE), 1537ec681f3Smrg .handle = bo->handle, 1547ec681f3Smrg .presumed = 0, 1557ec681f3Smrg }); 1567ec681f3Smrg APPEND(submit, bos, fd_bo_ref(bo)); 1577ec681f3Smrg 1587ec681f3Smrg _mesa_hash_table_insert_pre_hashed(submit->bo_table, hash, bo, 1597ec681f3Smrg (void *)(uintptr_t)idx); 1607ec681f3Smrg } 1617ec681f3Smrg msm_bo->idx = idx; 1627ec681f3Smrg } 1637ec681f3Smrg 1647ec681f3Smrg return idx; 1657e102996Smaya} 1667e102996Smaya 1677e102996Smayastatic void 1687e102996Smayaappend_ring(struct set *set, struct fd_ringbuffer *ring) 1697e102996Smaya{ 1707ec681f3Smrg uint32_t hash = _mesa_hash_pointer(ring); 1717e102996Smaya 1727ec681f3Smrg if (!_mesa_set_search_pre_hashed(set, hash, ring)) { 1737ec681f3Smrg fd_ringbuffer_ref(ring); 1747ec681f3Smrg _mesa_set_add_pre_hashed(set, hash, ring); 1757ec681f3Smrg } 1767e102996Smaya} 1777e102996Smaya 1787e102996Smayastatic void 1797e102996Smayamsm_submit_suballoc_ring_bo(struct fd_submit *submit, 1807ec681f3Smrg struct msm_ringbuffer *msm_ring, uint32_t size) 1817e102996Smaya{ 1827ec681f3Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 1837ec681f3Smrg unsigned suballoc_offset = 0; 1847ec681f3Smrg struct fd_bo *suballoc_bo = NULL; 1857e102996Smaya 1867ec681f3Smrg if (msm_submit->suballoc_ring) { 1877ec681f3Smrg struct msm_ringbuffer *suballoc_ring = 1887ec681f3Smrg to_msm_ringbuffer(msm_submit->suballoc_ring); 1897e102996Smaya 1907ec681f3Smrg suballoc_bo = suballoc_ring->ring_bo; 1917ec681f3Smrg suballoc_offset = 1927ec681f3Smrg fd_ringbuffer_size(msm_submit->suballoc_ring) + suballoc_ring->offset; 1937e102996Smaya 1947ec681f3Smrg suballoc_offset = align(suballoc_offset, 0x10); 1957e102996Smaya 1967ec681f3Smrg if ((size + suballoc_offset) > suballoc_bo->size) { 1977ec681f3Smrg suballoc_bo = NULL; 1987ec681f3Smrg } 1997ec681f3Smrg } 2007e102996Smaya 2017ec681f3Smrg if (!suballoc_bo) { 2027ec681f3Smrg // TODO possibly larger size for streaming bo? 2037ec681f3Smrg msm_ring->ring_bo = fd_bo_new_ring(submit->pipe->dev, 0x8000); 2047ec681f3Smrg msm_ring->offset = 0; 2057ec681f3Smrg } else { 2067ec681f3Smrg msm_ring->ring_bo = fd_bo_ref(suballoc_bo); 2077ec681f3Smrg msm_ring->offset = suballoc_offset; 2087ec681f3Smrg } 2097e102996Smaya 2107ec681f3Smrg struct fd_ringbuffer *old_suballoc_ring = msm_submit->suballoc_ring; 2117e102996Smaya 2127ec681f3Smrg msm_submit->suballoc_ring = fd_ringbuffer_ref(&msm_ring->base); 2137e102996Smaya 2147ec681f3Smrg if (old_suballoc_ring) 2157ec681f3Smrg fd_ringbuffer_del(old_suballoc_ring); 2167e102996Smaya} 2177e102996Smaya 2187e102996Smayastatic struct fd_ringbuffer * 2197e102996Smayamsm_submit_new_ringbuffer(struct fd_submit *submit, uint32_t size, 2207ec681f3Smrg enum fd_ringbuffer_flags flags) 2217e102996Smaya{ 2227ec681f3Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 2237ec681f3Smrg struct msm_ringbuffer *msm_ring; 2247e102996Smaya 2257ec681f3Smrg msm_ring = slab_alloc_st(&msm_submit->ring_pool); 2267e102996Smaya 2277ec681f3Smrg msm_ring->u.submit = submit; 2287e102996Smaya 2297ec681f3Smrg /* NOTE: needs to be before _suballoc_ring_bo() since it could 2307ec681f3Smrg * increment the refcnt of the current ring 2317ec681f3Smrg */ 2327ec681f3Smrg msm_ring->base.refcnt = 1; 2337e102996Smaya 2347ec681f3Smrg if (flags & FD_RINGBUFFER_STREAMING) { 2357ec681f3Smrg msm_submit_suballoc_ring_bo(submit, msm_ring, size); 2367ec681f3Smrg } else { 2377ec681f3Smrg if (flags & FD_RINGBUFFER_GROWABLE) 2387ec681f3Smrg size = INIT_SIZE; 2397e102996Smaya 2407ec681f3Smrg msm_ring->offset = 0; 2417ec681f3Smrg msm_ring->ring_bo = fd_bo_new_ring(submit->pipe->dev, size); 2427ec681f3Smrg } 2437e102996Smaya 2447ec681f3Smrg if (!msm_ringbuffer_init(msm_ring, size, flags)) 2457ec681f3Smrg return NULL; 2467e102996Smaya 2477ec681f3Smrg return &msm_ring->base; 2487e102996Smaya} 2497e102996Smaya 2507e102996Smayastatic struct drm_msm_gem_submit_reloc * 2517e102996Smayahandle_stateobj_relocs(struct msm_submit *submit, struct msm_ringbuffer *ring) 2527e102996Smaya{ 2537ec681f3Smrg struct msm_cmd *cmd = ring->cmd; 2547ec681f3Smrg struct drm_msm_gem_submit_reloc *relocs; 2557e102996Smaya 2567ec681f3Smrg relocs = malloc(cmd->nr_relocs * sizeof(*relocs)); 2577e102996Smaya 2587ec681f3Smrg for (unsigned i = 0; i < cmd->nr_relocs; i++) { 2597ec681f3Smrg unsigned idx = cmd->relocs[i].reloc_idx; 2607ec681f3Smrg struct fd_bo *bo = ring->u.reloc_bos[idx]; 2617e102996Smaya 2627ec681f3Smrg relocs[i] = cmd->relocs[i]; 2637ec681f3Smrg relocs[i].reloc_idx = append_bo(submit, bo); 2647ec681f3Smrg } 2657e102996Smaya 2667ec681f3Smrg return relocs; 2677e102996Smaya} 2687e102996Smaya 2697e102996Smayastatic int 2707e102996Smayamsm_submit_flush(struct fd_submit *submit, int in_fence_fd, 2717ec681f3Smrg struct fd_submit_fence *out_fence) 2727e102996Smaya{ 2737ec681f3Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 2747ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(submit->pipe); 2757ec681f3Smrg struct drm_msm_gem_submit req = { 2767ec681f3Smrg .flags = msm_pipe->pipe, 2777ec681f3Smrg .queueid = msm_pipe->queue_id, 2787ec681f3Smrg }; 2797ec681f3Smrg int ret; 2807ec681f3Smrg 2817ec681f3Smrg finalize_current_cmd(submit->primary); 2827ec681f3Smrg append_ring(msm_submit->ring_set, submit->primary); 2837ec681f3Smrg 2847ec681f3Smrg unsigned nr_cmds = 0; 2857ec681f3Smrg unsigned nr_objs = 0; 2867ec681f3Smrg 2877ec681f3Smrg set_foreach (msm_submit->ring_set, entry) { 2887ec681f3Smrg struct fd_ringbuffer *ring = (void *)entry->key; 2897ec681f3Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 2907ec681f3Smrg nr_cmds += 1; 2917ec681f3Smrg nr_objs += 1; 2927ec681f3Smrg } else { 2937ec681f3Smrg if (ring != submit->primary) 2947ec681f3Smrg finalize_current_cmd(ring); 2957ec681f3Smrg nr_cmds += to_msm_ringbuffer(ring)->u.nr_cmds; 2967ec681f3Smrg } 2977ec681f3Smrg } 2987ec681f3Smrg 2997ec681f3Smrg void *obj_relocs[nr_objs]; 3007ec681f3Smrg struct drm_msm_gem_submit_cmd cmds[nr_cmds]; 3017ec681f3Smrg unsigned i = 0, o = 0; 3027ec681f3Smrg 3037ec681f3Smrg set_foreach (msm_submit->ring_set, entry) { 3047ec681f3Smrg struct fd_ringbuffer *ring = (void *)entry->key; 3057ec681f3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 3067ec681f3Smrg 3077ec681f3Smrg debug_assert(i < nr_cmds); 3087ec681f3Smrg 3097ec681f3Smrg // TODO handle relocs: 3107ec681f3Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 3117ec681f3Smrg 3127ec681f3Smrg debug_assert(o < nr_objs); 3137ec681f3Smrg 3147ec681f3Smrg void *relocs = handle_stateobj_relocs(msm_submit, msm_ring); 3157ec681f3Smrg obj_relocs[o++] = relocs; 3167ec681f3Smrg 3177ec681f3Smrg cmds[i].type = MSM_SUBMIT_CMD_IB_TARGET_BUF; 3187ec681f3Smrg cmds[i].submit_idx = append_bo(msm_submit, msm_ring->ring_bo); 3197ec681f3Smrg cmds[i].submit_offset = msm_ring->offset; 3207ec681f3Smrg cmds[i].size = offset_bytes(ring->cur, ring->start); 3217ec681f3Smrg cmds[i].pad = 0; 3227ec681f3Smrg cmds[i].nr_relocs = msm_ring->cmd->nr_relocs; 3237ec681f3Smrg cmds[i].relocs = VOID2U64(relocs); 3247ec681f3Smrg 3257ec681f3Smrg i++; 3267ec681f3Smrg } else { 3277ec681f3Smrg for (unsigned j = 0; j < msm_ring->u.nr_cmds; j++) { 3287ec681f3Smrg if (ring->flags & FD_RINGBUFFER_PRIMARY) { 3297ec681f3Smrg cmds[i].type = MSM_SUBMIT_CMD_BUF; 3307ec681f3Smrg } else { 3317ec681f3Smrg cmds[i].type = MSM_SUBMIT_CMD_IB_TARGET_BUF; 3327ec681f3Smrg } 3337ec681f3Smrg cmds[i].submit_idx = 3347ec681f3Smrg append_bo(msm_submit, msm_ring->u.cmds[j]->ring_bo); 3357ec681f3Smrg cmds[i].submit_offset = msm_ring->offset; 3367ec681f3Smrg cmds[i].size = msm_ring->u.cmds[j]->size; 3377ec681f3Smrg cmds[i].pad = 0; 3387ec681f3Smrg cmds[i].nr_relocs = msm_ring->u.cmds[j]->nr_relocs; 3397ec681f3Smrg cmds[i].relocs = VOID2U64(msm_ring->u.cmds[j]->relocs); 3407ec681f3Smrg 3417ec681f3Smrg i++; 3427ec681f3Smrg } 3437ec681f3Smrg } 3447ec681f3Smrg } 3457ec681f3Smrg 3467ec681f3Smrg simple_mtx_lock(&table_lock); 3477ec681f3Smrg for (unsigned j = 0; j < msm_submit->nr_bos; j++) { 3487ec681f3Smrg fd_bo_add_fence(msm_submit->bos[j], submit->pipe, submit->fence); 3497ec681f3Smrg } 3507ec681f3Smrg simple_mtx_unlock(&table_lock); 3517ec681f3Smrg 3527ec681f3Smrg if (in_fence_fd != -1) { 3537ec681f3Smrg req.flags |= MSM_SUBMIT_FENCE_FD_IN | MSM_SUBMIT_NO_IMPLICIT; 3547ec681f3Smrg req.fence_fd = in_fence_fd; 3557ec681f3Smrg } 3567ec681f3Smrg 3577ec681f3Smrg if (out_fence && out_fence->use_fence_fd) { 3587ec681f3Smrg req.flags |= MSM_SUBMIT_FENCE_FD_OUT; 3597ec681f3Smrg } 3607ec681f3Smrg 3617ec681f3Smrg /* needs to be after get_cmd() as that could create bos/cmds table: */ 3627ec681f3Smrg req.bos = VOID2U64(msm_submit->submit_bos), 3637ec681f3Smrg req.nr_bos = msm_submit->nr_submit_bos; 3647ec681f3Smrg req.cmds = VOID2U64(cmds), req.nr_cmds = nr_cmds; 3657ec681f3Smrg 3667ec681f3Smrg DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos); 3677ec681f3Smrg 3687ec681f3Smrg ret = drmCommandWriteRead(submit->pipe->dev->fd, DRM_MSM_GEM_SUBMIT, &req, 3697ec681f3Smrg sizeof(req)); 3707ec681f3Smrg if (ret) { 3717ec681f3Smrg ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); 3727ec681f3Smrg msm_dump_submit(&req); 3737ec681f3Smrg } else if (!ret && out_fence) { 3747ec681f3Smrg out_fence->fence.kfence = req.fence; 3757ec681f3Smrg out_fence->fence.ufence = submit->fence; 3767ec681f3Smrg out_fence->fence_fd = req.fence_fd; 3777ec681f3Smrg } 3787ec681f3Smrg 3797ec681f3Smrg for (unsigned o = 0; o < nr_objs; o++) 3807ec681f3Smrg free(obj_relocs[o]); 3817ec681f3Smrg 3827ec681f3Smrg return ret; 3837e102996Smaya} 3847e102996Smaya 3857e102996Smayastatic void 3867e102996Smayaunref_rings(struct set_entry *entry) 3877e102996Smaya{ 3887ec681f3Smrg struct fd_ringbuffer *ring = (void *)entry->key; 3897ec681f3Smrg fd_ringbuffer_del(ring); 3907e102996Smaya} 3917e102996Smaya 3927e102996Smayastatic void 3937e102996Smayamsm_submit_destroy(struct fd_submit *submit) 3947e102996Smaya{ 3957ec681f3Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 3967e102996Smaya 3977ec681f3Smrg if (msm_submit->suballoc_ring) 3987ec681f3Smrg fd_ringbuffer_del(msm_submit->suballoc_ring); 3997e102996Smaya 4007ec681f3Smrg _mesa_hash_table_destroy(msm_submit->bo_table, NULL); 4017ec681f3Smrg _mesa_set_destroy(msm_submit->ring_set, unref_rings); 4027e102996Smaya 4037ec681f3Smrg // TODO it would be nice to have a way to debug_assert() if all 4047ec681f3Smrg // rb's haven't been free'd back to the slab, because that is 4057ec681f3Smrg // an indication that we are leaking bo's 4067ec681f3Smrg slab_destroy(&msm_submit->ring_pool); 4077e102996Smaya 4087ec681f3Smrg for (unsigned i = 0; i < msm_submit->nr_bos; i++) 4097ec681f3Smrg fd_bo_del(msm_submit->bos[i]); 4107e102996Smaya 4117ec681f3Smrg free(msm_submit->submit_bos); 4127ec681f3Smrg free(msm_submit->bos); 4137ec681f3Smrg free(msm_submit); 4147e102996Smaya} 4157e102996Smaya 4167e102996Smayastatic const struct fd_submit_funcs submit_funcs = { 4177ec681f3Smrg .new_ringbuffer = msm_submit_new_ringbuffer, 4187ec681f3Smrg .flush = msm_submit_flush, 4197ec681f3Smrg .destroy = msm_submit_destroy, 4207e102996Smaya}; 4217e102996Smaya 4227e102996Smayastruct fd_submit * 4237e102996Smayamsm_submit_new(struct fd_pipe *pipe) 4247e102996Smaya{ 4257ec681f3Smrg struct msm_submit *msm_submit = calloc(1, sizeof(*msm_submit)); 4267ec681f3Smrg struct fd_submit *submit; 4277e102996Smaya 4287ec681f3Smrg msm_submit->bo_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, 4297ec681f3Smrg _mesa_key_pointer_equal); 4307ec681f3Smrg msm_submit->ring_set = 4317ec681f3Smrg _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); 4327ec681f3Smrg // TODO tune size: 4337ec681f3Smrg slab_create(&msm_submit->ring_pool, sizeof(struct msm_ringbuffer), 16); 4347ec681f3Smrg 4357ec681f3Smrg submit = &msm_submit->base; 4367ec681f3Smrg submit->funcs = &submit_funcs; 4377ec681f3Smrg 4387ec681f3Smrg return submit; 4397ec681f3Smrg} 4407e102996Smaya 4417e102996Smayastatic void 4427e102996Smayafinalize_current_cmd(struct fd_ringbuffer *ring) 4437e102996Smaya{ 4447ec681f3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 4457e102996Smaya 4467ec681f3Smrg debug_assert(!(ring->flags & _FD_RINGBUFFER_OBJECT)); 4477e102996Smaya 4487ec681f3Smrg if (!msm_ring->cmd) 4497ec681f3Smrg return; 4507e102996Smaya 4517ec681f3Smrg debug_assert(msm_ring->cmd->ring_bo == msm_ring->ring_bo); 4527e102996Smaya 4537ec681f3Smrg msm_ring->cmd->size = offset_bytes(ring->cur, ring->start); 4547ec681f3Smrg APPEND(&msm_ring->u, cmds, msm_ring->cmd); 4557ec681f3Smrg msm_ring->cmd = NULL; 4567e102996Smaya} 4577e102996Smaya 4587e102996Smayastatic void 4597e102996Smayamsm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size) 4607e102996Smaya{ 4617ec681f3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 4627ec681f3Smrg struct fd_pipe *pipe = msm_ring->u.submit->pipe; 4637e102996Smaya 4647ec681f3Smrg debug_assert(ring->flags & FD_RINGBUFFER_GROWABLE); 4657e102996Smaya 4667ec681f3Smrg finalize_current_cmd(ring); 4677e102996Smaya 4687ec681f3Smrg fd_bo_del(msm_ring->ring_bo); 4697ec681f3Smrg msm_ring->ring_bo = fd_bo_new_ring(pipe->dev, size); 4707ec681f3Smrg msm_ring->cmd = cmd_new(msm_ring->ring_bo); 4717e102996Smaya 4727ec681f3Smrg ring->start = fd_bo_map(msm_ring->ring_bo); 4737ec681f3Smrg ring->end = &(ring->start[size / 4]); 4747ec681f3Smrg ring->cur = ring->start; 4757ec681f3Smrg ring->size = size; 4767e102996Smaya} 4777e102996Smaya 4787e102996Smayastatic void 4797e102996Smayamsm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, 4807ec681f3Smrg const struct fd_reloc *reloc) 4817e102996Smaya{ 4827ec681f3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 4837ec681f3Smrg struct fd_pipe *pipe; 4847ec681f3Smrg unsigned reloc_idx; 4857ec681f3Smrg 4867ec681f3Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 4877ec681f3Smrg unsigned idx = APPEND(&msm_ring->u, reloc_bos, fd_bo_ref(reloc->bo)); 4887ec681f3Smrg 4897ec681f3Smrg /* this gets fixed up at submit->flush() time, since this state- 4907ec681f3Smrg * object rb can be used with many different submits 4917ec681f3Smrg */ 4927ec681f3Smrg reloc_idx = idx; 4937ec681f3Smrg 4947ec681f3Smrg pipe = msm_ring->u.pipe; 4957ec681f3Smrg } else { 4967ec681f3Smrg struct msm_submit *msm_submit = to_msm_submit(msm_ring->u.submit); 4977ec681f3Smrg 4987ec681f3Smrg reloc_idx = append_bo(msm_submit, reloc->bo); 4997ec681f3Smrg 5007ec681f3Smrg pipe = msm_ring->u.submit->pipe; 5017ec681f3Smrg } 5027ec681f3Smrg 5037ec681f3Smrg APPEND(msm_ring->cmd, relocs, 5047ec681f3Smrg (struct drm_msm_gem_submit_reloc){ 5057ec681f3Smrg .reloc_idx = reloc_idx, 5067ec681f3Smrg .reloc_offset = reloc->offset, 5077ec681f3Smrg .or = reloc->orlo, 5087ec681f3Smrg .shift = reloc->shift, 5097ec681f3Smrg .submit_offset = 5107ec681f3Smrg offset_bytes(ring->cur, ring->start) + msm_ring->offset, 5117ec681f3Smrg }); 5127ec681f3Smrg 5137ec681f3Smrg ring->cur++; 5147ec681f3Smrg 5157ec681f3Smrg if (fd_dev_64b(&pipe->dev_id)) { 5167ec681f3Smrg APPEND(msm_ring->cmd, relocs, 5177ec681f3Smrg (struct drm_msm_gem_submit_reloc){ 5187ec681f3Smrg .reloc_idx = reloc_idx, 5197ec681f3Smrg .reloc_offset = reloc->offset, 5207ec681f3Smrg .or = reloc->orhi, 5217ec681f3Smrg .shift = reloc->shift - 32, 5227ec681f3Smrg .submit_offset = 5237ec681f3Smrg offset_bytes(ring->cur, ring->start) + msm_ring->offset, 5247ec681f3Smrg }); 5257ec681f3Smrg 5267ec681f3Smrg ring->cur++; 5277ec681f3Smrg } 5287e102996Smaya} 5297e102996Smaya 5307e102996Smayastatic void 5317e102996Smayaappend_stateobj_rings(struct msm_submit *submit, struct fd_ringbuffer *target) 5327e102996Smaya{ 5337ec681f3Smrg struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target); 5347e102996Smaya 5357ec681f3Smrg debug_assert(target->flags & _FD_RINGBUFFER_OBJECT); 5367e102996Smaya 5377ec681f3Smrg set_foreach (msm_target->u.ring_set, entry) { 5387ec681f3Smrg struct fd_ringbuffer *ring = (void *)entry->key; 5397e102996Smaya 5407ec681f3Smrg append_ring(submit->ring_set, ring); 5417e102996Smaya 5427ec681f3Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 5437ec681f3Smrg append_stateobj_rings(submit, ring); 5447ec681f3Smrg } 5457ec681f3Smrg } 5467e102996Smaya} 5477e102996Smaya 5487e102996Smayastatic uint32_t 5497e102996Smayamsm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 5507ec681f3Smrg struct fd_ringbuffer *target, uint32_t cmd_idx) 5517e102996Smaya{ 5527ec681f3Smrg struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target); 5537ec681f3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 5547ec681f3Smrg struct fd_bo *bo; 5557ec681f3Smrg uint32_t size; 5567ec681f3Smrg 5577ec681f3Smrg if ((target->flags & FD_RINGBUFFER_GROWABLE) && 5587ec681f3Smrg (cmd_idx < msm_target->u.nr_cmds)) { 5597ec681f3Smrg bo = msm_target->u.cmds[cmd_idx]->ring_bo; 5607ec681f3Smrg size = msm_target->u.cmds[cmd_idx]->size; 5617ec681f3Smrg } else { 5627ec681f3Smrg bo = msm_target->ring_bo; 5637ec681f3Smrg size = offset_bytes(target->cur, target->start); 5647ec681f3Smrg } 5657ec681f3Smrg 5667ec681f3Smrg msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){ 5677ec681f3Smrg .bo = bo, 5687ec681f3Smrg .iova = bo->iova + msm_target->offset, 5697ec681f3Smrg .offset = msm_target->offset, 5707ec681f3Smrg }); 5717ec681f3Smrg 5727ec681f3Smrg if (!size) 5737ec681f3Smrg return 0; 5747ec681f3Smrg 5757ec681f3Smrg if ((target->flags & _FD_RINGBUFFER_OBJECT) && 5767ec681f3Smrg !(ring->flags & _FD_RINGBUFFER_OBJECT)) { 5777ec681f3Smrg struct msm_submit *msm_submit = to_msm_submit(msm_ring->u.submit); 5787ec681f3Smrg 5797ec681f3Smrg append_stateobj_rings(msm_submit, target); 5807ec681f3Smrg } 5817ec681f3Smrg 5827ec681f3Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 5837ec681f3Smrg append_ring(msm_ring->u.ring_set, target); 5847ec681f3Smrg } else { 5857ec681f3Smrg struct msm_submit *msm_submit = to_msm_submit(msm_ring->u.submit); 5867ec681f3Smrg append_ring(msm_submit->ring_set, target); 5877ec681f3Smrg } 5887ec681f3Smrg 5897ec681f3Smrg return size; 5907e102996Smaya} 5917e102996Smaya 5927e102996Smayastatic uint32_t 5937e102996Smayamsm_ringbuffer_cmd_count(struct fd_ringbuffer *ring) 5947e102996Smaya{ 5957ec681f3Smrg if (ring->flags & FD_RINGBUFFER_GROWABLE) 5967ec681f3Smrg return to_msm_ringbuffer(ring)->u.nr_cmds + 1; 5977ec681f3Smrg return 1; 5987ec681f3Smrg} 5997ec681f3Smrg 6007ec681f3Smrgstatic bool 6017ec681f3Smrgmsm_ringbuffer_check_size(struct fd_ringbuffer *ring) 6027ec681f3Smrg{ 6037ec681f3Smrg assert(!(ring->flags & _FD_RINGBUFFER_OBJECT)); 6047ec681f3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 6057ec681f3Smrg struct fd_submit *submit = msm_ring->u.submit; 6067ec681f3Smrg struct fd_pipe *pipe = submit->pipe; 6077ec681f3Smrg 6087ec681f3Smrg if ((fd_device_version(pipe->dev) < FD_VERSION_UNLIMITED_CMDS) && 6097ec681f3Smrg ((ring->cur - ring->start) > (ring->size / 4 - 0x1000))) { 6107ec681f3Smrg return false; 6117ec681f3Smrg } 6127ec681f3Smrg 6137ec681f3Smrg if (to_msm_submit(submit)->nr_bos > MAX_ARRAY_SIZE/2) { 6147ec681f3Smrg return false; 6157ec681f3Smrg } 6167ec681f3Smrg 6177ec681f3Smrg return true; 6187e102996Smaya} 6197e102996Smaya 6207e102996Smayastatic void 6217e102996Smayamsm_ringbuffer_destroy(struct fd_ringbuffer *ring) 6227e102996Smaya{ 6237ec681f3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 6247e102996Smaya 6257ec681f3Smrg fd_bo_del(msm_ring->ring_bo); 6267ec681f3Smrg if (msm_ring->cmd) 6277ec681f3Smrg cmd_free(msm_ring->cmd); 6287e102996Smaya 6297ec681f3Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 6307ec681f3Smrg for (unsigned i = 0; i < msm_ring->u.nr_reloc_bos; i++) { 6317ec681f3Smrg fd_bo_del(msm_ring->u.reloc_bos[i]); 6327ec681f3Smrg } 6337e102996Smaya 6347ec681f3Smrg _mesa_set_destroy(msm_ring->u.ring_set, unref_rings); 6357e102996Smaya 6367ec681f3Smrg free(msm_ring->u.reloc_bos); 6377ec681f3Smrg free(msm_ring); 6387ec681f3Smrg } else { 6397ec681f3Smrg struct fd_submit *submit = msm_ring->u.submit; 6407e102996Smaya 6417ec681f3Smrg for (unsigned i = 0; i < msm_ring->u.nr_cmds; i++) { 6427ec681f3Smrg cmd_free(msm_ring->u.cmds[i]); 6437ec681f3Smrg } 6447e102996Smaya 6457ec681f3Smrg free(msm_ring->u.cmds); 6467ec681f3Smrg slab_free_st(&to_msm_submit(submit)->ring_pool, msm_ring); 6477ec681f3Smrg } 6487e102996Smaya} 6497e102996Smaya 6507e102996Smayastatic const struct fd_ringbuffer_funcs ring_funcs = { 6517ec681f3Smrg .grow = msm_ringbuffer_grow, 6527ec681f3Smrg .emit_reloc = msm_ringbuffer_emit_reloc, 6537ec681f3Smrg .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, 6547ec681f3Smrg .cmd_count = msm_ringbuffer_cmd_count, 6557ec681f3Smrg .check_size = msm_ringbuffer_check_size, 6567ec681f3Smrg .destroy = msm_ringbuffer_destroy, 6577e102996Smaya}; 6587e102996Smaya 6597e102996Smayastatic inline struct fd_ringbuffer * 6607e102996Smayamsm_ringbuffer_init(struct msm_ringbuffer *msm_ring, uint32_t size, 6617ec681f3Smrg enum fd_ringbuffer_flags flags) 6627e102996Smaya{ 6637ec681f3Smrg struct fd_ringbuffer *ring = &msm_ring->base; 6647e102996Smaya 6657ec681f3Smrg debug_assert(msm_ring->ring_bo); 6667e102996Smaya 6677ec681f3Smrg uint8_t *base = fd_bo_map(msm_ring->ring_bo); 6687ec681f3Smrg ring->start = (void *)(base + msm_ring->offset); 6697ec681f3Smrg ring->end = &(ring->start[size / 4]); 6707ec681f3Smrg ring->cur = ring->start; 6717e102996Smaya 6727ec681f3Smrg ring->size = size; 6737ec681f3Smrg ring->flags = flags; 6747e102996Smaya 6757ec681f3Smrg ring->funcs = &ring_funcs; 6767e102996Smaya 6777ec681f3Smrg msm_ring->u.cmds = NULL; 6787ec681f3Smrg msm_ring->u.nr_cmds = msm_ring->u.max_cmds = 0; 6797e102996Smaya 6807ec681f3Smrg msm_ring->cmd = cmd_new(msm_ring->ring_bo); 6817e102996Smaya 6827ec681f3Smrg return ring; 6837e102996Smaya} 6847e102996Smaya 6857e102996Smayastruct fd_ringbuffer * 6867e102996Smayamsm_ringbuffer_new_object(struct fd_pipe *pipe, uint32_t size) 6877e102996Smaya{ 6887ec681f3Smrg struct msm_ringbuffer *msm_ring = malloc(sizeof(*msm_ring)); 6897e102996Smaya 6907ec681f3Smrg msm_ring->u.pipe = pipe; 6917ec681f3Smrg msm_ring->offset = 0; 6927ec681f3Smrg msm_ring->ring_bo = fd_bo_new_ring(pipe->dev, size); 6937ec681f3Smrg msm_ring->base.refcnt = 1; 6947e102996Smaya 6957ec681f3Smrg msm_ring->u.reloc_bos = NULL; 6967ec681f3Smrg msm_ring->u.nr_reloc_bos = msm_ring->u.max_reloc_bos = 0; 6977e102996Smaya 6987ec681f3Smrg msm_ring->u.ring_set = 6997ec681f3Smrg _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); 7007e102996Smaya 7017ec681f3Smrg return msm_ringbuffer_init(msm_ring, size, _FD_RINGBUFFER_OBJECT); 7027e102996Smaya} 703