17e102996Smaya/* 27e102996Smaya * Copyright (C) 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> 297ec681f3Smrg#include <pthread.h> 307e102996Smaya 317e102996Smaya#include "util/hash_table.h" 327ec681f3Smrg#include "util/os_file.h" 337e102996Smaya#include "util/slab.h" 347e102996Smaya 357e102996Smaya#include "drm/freedreno_ringbuffer.h" 367e102996Smaya#include "msm_priv.h" 377e102996Smaya 387e102996Smaya/* A "softpin" implementation of submit/ringbuffer, which lowers CPU overhead 397e102996Smaya * by avoiding the additional tracking necessary to build cmds/relocs tables 407e102996Smaya * (but still builds a bos table) 417e102996Smaya */ 427e102996Smaya 437e102996Smaya#define INIT_SIZE 0x1000 447e102996Smaya 457ec681f3Smrg#define SUBALLOC_SIZE (32 * 1024) 467ec681f3Smrg 477ec681f3Smrg/* In the pipe->flush() path, we don't have a util_queue_fence we can wait on, 487ec681f3Smrg * instead use a condition-variable. Note that pipe->flush() is not expected 497ec681f3Smrg * to be a common/hot path. 507ec681f3Smrg */ 517ec681f3Smrgstatic pthread_cond_t flush_cnd = PTHREAD_COND_INITIALIZER; 527ec681f3Smrgstatic pthread_mutex_t flush_mtx = PTHREAD_MUTEX_INITIALIZER; 537e102996Smaya 547e102996Smaya 557e102996Smayastruct msm_submit_sp { 567ec681f3Smrg struct fd_submit base; 577ec681f3Smrg 587ec681f3Smrg DECLARE_ARRAY(struct fd_bo *, bos); 597e102996Smaya 607ec681f3Smrg /* maps fd_bo to idx in bos table: */ 617ec681f3Smrg struct hash_table *bo_table; 627e102996Smaya 637ec681f3Smrg struct slab_child_pool ring_pool; 647e102996Smaya 657ec681f3Smrg /* Allow for sub-allocation of stateobj ring buffers (ie. sharing 667ec681f3Smrg * the same underlying bo).. 677ec681f3Smrg * 687ec681f3Smrg * We also rely on previous stateobj having been fully constructed 697ec681f3Smrg * so we can reclaim extra space at it's end. 707ec681f3Smrg */ 717ec681f3Smrg struct fd_ringbuffer *suballoc_ring; 727e102996Smaya 737ec681f3Smrg /* Flush args, potentially attached to the last submit in the list 747ec681f3Smrg * of submits to merge: 757ec681f3Smrg */ 767ec681f3Smrg int in_fence_fd; 777ec681f3Smrg struct fd_submit_fence *out_fence; 787e102996Smaya 797ec681f3Smrg /* State for enqueued submits: 807ec681f3Smrg */ 817ec681f3Smrg struct list_head submit_list; /* includes this submit as last element */ 827e102996Smaya 837ec681f3Smrg /* Used in case out_fence==NULL: */ 847ec681f3Smrg struct util_queue_fence fence; 857e102996Smaya}; 867e102996SmayaFD_DEFINE_CAST(fd_submit, msm_submit_sp); 877e102996Smaya 887e102996Smaya/* for FD_RINGBUFFER_GROWABLE rb's, tracks the 'finalized' cmdstream buffers 897e102996Smaya * and sizes. Ie. a finalized buffer can have no more commands appended to 907e102996Smaya * it. 917e102996Smaya */ 927e102996Smayastruct msm_cmd_sp { 937ec681f3Smrg struct fd_bo *ring_bo; 947ec681f3Smrg unsigned size; 957e102996Smaya}; 967e102996Smaya 977e102996Smayastruct msm_ringbuffer_sp { 987ec681f3Smrg struct fd_ringbuffer base; 997ec681f3Smrg 1007ec681f3Smrg /* for FD_RINGBUFFER_STREAMING rb's which are sub-allocated */ 1017ec681f3Smrg unsigned offset; 1027ec681f3Smrg 1037ec681f3Smrg union { 1047ec681f3Smrg /* for _FD_RINGBUFFER_OBJECT case, the array of BOs referenced from 1057ec681f3Smrg * this one 1067ec681f3Smrg */ 1077ec681f3Smrg struct { 1087ec681f3Smrg struct fd_pipe *pipe; 1097ec681f3Smrg DECLARE_ARRAY(struct fd_bo *, reloc_bos); 1107ec681f3Smrg }; 1117ec681f3Smrg /* for other cases: */ 1127ec681f3Smrg struct { 1137ec681f3Smrg struct fd_submit *submit; 1147ec681f3Smrg DECLARE_ARRAY(struct msm_cmd_sp, cmds); 1157ec681f3Smrg }; 1167ec681f3Smrg } u; 1177ec681f3Smrg 1187ec681f3Smrg struct fd_bo *ring_bo; 1197e102996Smaya}; 1207e102996SmayaFD_DEFINE_CAST(fd_ringbuffer, msm_ringbuffer_sp); 1217e102996Smaya 1227e102996Smayastatic void finalize_current_cmd(struct fd_ringbuffer *ring); 1237ec681f3Smrgstatic struct fd_ringbuffer * 1247ec681f3Smrgmsm_ringbuffer_sp_init(struct msm_ringbuffer_sp *msm_ring, uint32_t size, 1257ec681f3Smrg enum fd_ringbuffer_flags flags); 1267e102996Smaya 1277e102996Smaya/* add (if needed) bo to submit and return index: */ 1287e102996Smayastatic uint32_t 1297ec681f3Smrgmsm_submit_append_bo(struct msm_submit_sp *submit, struct fd_bo *bo) 1307e102996Smaya{ 1317ec681f3Smrg struct msm_bo *msm_bo = to_msm_bo(bo); 1327ec681f3Smrg uint32_t idx; 1337ec681f3Smrg 1347ec681f3Smrg /* NOTE: it is legal to use the same bo on different threads for 1357ec681f3Smrg * different submits. But it is not legal to use the same submit 1367ec681f3Smrg * from different threads. 1377ec681f3Smrg */ 1387ec681f3Smrg idx = READ_ONCE(msm_bo->idx); 1397ec681f3Smrg 1407ec681f3Smrg if (unlikely((idx >= submit->nr_bos) || (submit->bos[idx] != bo))) { 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(submit, bos, fd_bo_ref(bo)); 1507ec681f3Smrg 1517ec681f3Smrg _mesa_hash_table_insert_pre_hashed(submit->bo_table, hash, bo, 1527ec681f3Smrg (void *)(uintptr_t)idx); 1537ec681f3Smrg } 1547ec681f3Smrg msm_bo->idx = idx; 1557ec681f3Smrg } 1567ec681f3Smrg 1577ec681f3Smrg return idx; 1587e102996Smaya} 1597e102996Smaya 1607e102996Smayastatic void 1617e102996Smayamsm_submit_suballoc_ring_bo(struct fd_submit *submit, 1627ec681f3Smrg struct msm_ringbuffer_sp *msm_ring, uint32_t size) 1637e102996Smaya{ 1647ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(submit); 1657ec681f3Smrg unsigned suballoc_offset = 0; 1667ec681f3Smrg struct fd_bo *suballoc_bo = NULL; 1677e102996Smaya 1687ec681f3Smrg if (msm_submit->suballoc_ring) { 1697ec681f3Smrg struct msm_ringbuffer_sp *suballoc_ring = 1707ec681f3Smrg to_msm_ringbuffer_sp(msm_submit->suballoc_ring); 1717e102996Smaya 1727ec681f3Smrg suballoc_bo = suballoc_ring->ring_bo; 1737ec681f3Smrg suballoc_offset = 1747ec681f3Smrg fd_ringbuffer_size(msm_submit->suballoc_ring) + suballoc_ring->offset; 1757e102996Smaya 1767ec681f3Smrg suballoc_offset = align(suballoc_offset, 0x10); 1777e102996Smaya 1787ec681f3Smrg if ((size + suballoc_offset) > suballoc_bo->size) { 1797ec681f3Smrg suballoc_bo = NULL; 1807ec681f3Smrg } 1817ec681f3Smrg } 1827e102996Smaya 1837ec681f3Smrg if (!suballoc_bo) { 1847ec681f3Smrg // TODO possibly larger size for streaming bo? 1857ec681f3Smrg msm_ring->ring_bo = fd_bo_new_ring(submit->pipe->dev, SUBALLOC_SIZE); 1867ec681f3Smrg msm_ring->offset = 0; 1877ec681f3Smrg } else { 1887ec681f3Smrg msm_ring->ring_bo = fd_bo_ref(suballoc_bo); 1897ec681f3Smrg msm_ring->offset = suballoc_offset; 1907ec681f3Smrg } 1917e102996Smaya 1927ec681f3Smrg struct fd_ringbuffer *old_suballoc_ring = msm_submit->suballoc_ring; 1937e102996Smaya 1947ec681f3Smrg msm_submit->suballoc_ring = fd_ringbuffer_ref(&msm_ring->base); 1957e102996Smaya 1967ec681f3Smrg if (old_suballoc_ring) 1977ec681f3Smrg fd_ringbuffer_del(old_suballoc_ring); 1987e102996Smaya} 1997e102996Smaya 2007e102996Smayastatic struct fd_ringbuffer * 2017e102996Smayamsm_submit_sp_new_ringbuffer(struct fd_submit *submit, uint32_t size, 2027ec681f3Smrg enum fd_ringbuffer_flags flags) 2037e102996Smaya{ 2047ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(submit); 2057ec681f3Smrg struct msm_ringbuffer_sp *msm_ring; 2067e102996Smaya 2077ec681f3Smrg msm_ring = slab_alloc(&msm_submit->ring_pool); 2087e102996Smaya 2097ec681f3Smrg msm_ring->u.submit = submit; 2107e102996Smaya 2117ec681f3Smrg /* NOTE: needs to be before _suballoc_ring_bo() since it could 2127ec681f3Smrg * increment the refcnt of the current ring 2137ec681f3Smrg */ 2147ec681f3Smrg msm_ring->base.refcnt = 1; 2157e102996Smaya 2167ec681f3Smrg if (flags & FD_RINGBUFFER_STREAMING) { 2177ec681f3Smrg msm_submit_suballoc_ring_bo(submit, msm_ring, size); 2187ec681f3Smrg } else { 2197ec681f3Smrg if (flags & FD_RINGBUFFER_GROWABLE) 2207ec681f3Smrg size = INIT_SIZE; 2217e102996Smaya 2227ec681f3Smrg msm_ring->offset = 0; 2237ec681f3Smrg msm_ring->ring_bo = fd_bo_new_ring(submit->pipe->dev, size); 2247ec681f3Smrg } 2257e102996Smaya 2267ec681f3Smrg if (!msm_ringbuffer_sp_init(msm_ring, size, flags)) 2277ec681f3Smrg return NULL; 2287ec681f3Smrg 2297ec681f3Smrg return &msm_ring->base; 2307ec681f3Smrg} 2317e102996Smaya 2327ec681f3Smrg/** 2337ec681f3Smrg * Prepare submit for flush, always done synchronously. 2347ec681f3Smrg * 2357ec681f3Smrg * 1) Finalize primary ringbuffer, at this point no more cmdstream may 2367ec681f3Smrg * be written into it, since from the PoV of the upper level driver 2377ec681f3Smrg * the submit is flushed, even if deferred 2387ec681f3Smrg * 2) Add cmdstream bos to bos table 2397ec681f3Smrg * 3) Update bo fences 2407ec681f3Smrg */ 2417ec681f3Smrgstatic bool 2427ec681f3Smrgmsm_submit_sp_flush_prep(struct fd_submit *submit, int in_fence_fd, 2437ec681f3Smrg struct fd_submit_fence *out_fence) 2447ec681f3Smrg{ 2457ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(submit); 2467ec681f3Smrg bool has_shared = false; 2477e102996Smaya 2487ec681f3Smrg finalize_current_cmd(submit->primary); 2497ec681f3Smrg 2507ec681f3Smrg struct msm_ringbuffer_sp *primary = 2517ec681f3Smrg to_msm_ringbuffer_sp(submit->primary); 2527ec681f3Smrg 2537ec681f3Smrg for (unsigned i = 0; i < primary->u.nr_cmds; i++) 2547ec681f3Smrg msm_submit_append_bo(msm_submit, primary->u.cmds[i].ring_bo); 2557ec681f3Smrg 2567ec681f3Smrg simple_mtx_lock(&table_lock); 2577ec681f3Smrg for (unsigned i = 0; i < msm_submit->nr_bos; i++) { 2587ec681f3Smrg fd_bo_add_fence(msm_submit->bos[i], submit->pipe, submit->fence); 2597ec681f3Smrg has_shared |= msm_submit->bos[i]->shared; 2607ec681f3Smrg } 2617ec681f3Smrg simple_mtx_unlock(&table_lock); 2627ec681f3Smrg 2637ec681f3Smrg msm_submit->out_fence = out_fence; 2647ec681f3Smrg msm_submit->in_fence_fd = (in_fence_fd == -1) ? 2657ec681f3Smrg -1 : os_dupfd_cloexec(in_fence_fd); 2667ec681f3Smrg 2677ec681f3Smrg return has_shared; 2687e102996Smaya} 2697e102996Smaya 2707e102996Smayastatic int 2717ec681f3Smrgflush_submit_list(struct list_head *submit_list) 2727e102996Smaya{ 2737ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(last_submit(submit_list)); 2747ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(msm_submit->base.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 unsigned nr_cmds = 0; 2827ec681f3Smrg 2837ec681f3Smrg /* Determine the number of extra cmds's from deferred submits that 2847ec681f3Smrg * we will be merging in: 2857ec681f3Smrg */ 2867ec681f3Smrg foreach_submit (submit, submit_list) { 2877ec681f3Smrg assert(submit->pipe == &msm_pipe->base); 2887ec681f3Smrg nr_cmds += to_msm_ringbuffer_sp(submit->primary)->u.nr_cmds; 2897ec681f3Smrg } 2907ec681f3Smrg 2917ec681f3Smrg struct drm_msm_gem_submit_cmd cmds[nr_cmds]; 2927ec681f3Smrg 2937ec681f3Smrg unsigned cmd_idx = 0; 2947ec681f3Smrg 2957ec681f3Smrg /* Build up the table of cmds, and for all but the last submit in the 2967ec681f3Smrg * list, merge their bo tables into the last submit. 2977ec681f3Smrg */ 2987ec681f3Smrg foreach_submit_safe (submit, submit_list) { 2997ec681f3Smrg struct msm_ringbuffer_sp *deferred_primary = 3007ec681f3Smrg to_msm_ringbuffer_sp(submit->primary); 3017ec681f3Smrg 3027ec681f3Smrg for (unsigned i = 0; i < deferred_primary->u.nr_cmds; i++) { 3037ec681f3Smrg cmds[cmd_idx].type = MSM_SUBMIT_CMD_BUF; 3047ec681f3Smrg cmds[cmd_idx].submit_idx = 3057ec681f3Smrg msm_submit_append_bo(msm_submit, deferred_primary->u.cmds[i].ring_bo); 3067ec681f3Smrg cmds[cmd_idx].submit_offset = deferred_primary->offset; 3077ec681f3Smrg cmds[cmd_idx].size = deferred_primary->u.cmds[i].size; 3087ec681f3Smrg cmds[cmd_idx].pad = 0; 3097ec681f3Smrg cmds[cmd_idx].nr_relocs = 0; 3107ec681f3Smrg 3117ec681f3Smrg cmd_idx++; 3127ec681f3Smrg } 3137ec681f3Smrg 3147ec681f3Smrg /* We are merging all the submits in the list into the last submit, 3157ec681f3Smrg * so the remainder of the loop body doesn't apply to the last submit 3167ec681f3Smrg */ 3177ec681f3Smrg if (submit == last_submit(submit_list)) { 3187ec681f3Smrg DEBUG_MSG("merged %u submits", cmd_idx); 3197ec681f3Smrg break; 3207ec681f3Smrg } 3217ec681f3Smrg 3227ec681f3Smrg struct msm_submit_sp *msm_deferred_submit = to_msm_submit_sp(submit); 3237ec681f3Smrg for (unsigned i = 0; i < msm_deferred_submit->nr_bos; i++) { 3247ec681f3Smrg /* Note: if bo is used in both the current submit and the deferred 3257ec681f3Smrg * submit being merged, we expect to hit the fast-path as we add it 3267ec681f3Smrg * to the current submit: 3277ec681f3Smrg */ 3287ec681f3Smrg msm_submit_append_bo(msm_submit, msm_deferred_submit->bos[i]); 3297ec681f3Smrg } 3307ec681f3Smrg 3317ec681f3Smrg /* Now that the cmds/bos have been transfered over to the current submit, 3327ec681f3Smrg * we can remove the deferred submit from the list and drop it's reference 3337ec681f3Smrg */ 3347ec681f3Smrg list_del(&submit->node); 3357ec681f3Smrg fd_submit_del(submit); 3367ec681f3Smrg } 3377ec681f3Smrg 3387ec681f3Smrg if (msm_submit->in_fence_fd != -1) { 3397ec681f3Smrg req.flags |= MSM_SUBMIT_FENCE_FD_IN; 3407ec681f3Smrg req.fence_fd = msm_submit->in_fence_fd; 3417ec681f3Smrg msm_pipe->no_implicit_sync = true; 3427ec681f3Smrg } 3437ec681f3Smrg 3447ec681f3Smrg if (msm_pipe->no_implicit_sync) { 3457ec681f3Smrg req.flags |= MSM_SUBMIT_NO_IMPLICIT; 3467ec681f3Smrg } 3477ec681f3Smrg 3487ec681f3Smrg if (msm_submit->out_fence && msm_submit->out_fence->use_fence_fd) { 3497ec681f3Smrg req.flags |= MSM_SUBMIT_FENCE_FD_OUT; 3507ec681f3Smrg } 3517ec681f3Smrg 3527ec681f3Smrg /* Needs to be after get_cmd() as that could create bos/cmds table: 3537ec681f3Smrg * 3547ec681f3Smrg * NOTE allocate on-stack in the common case, but with an upper- 3557ec681f3Smrg * bound to limit on-stack allocation to 4k: 3567ec681f3Smrg */ 3577ec681f3Smrg const unsigned bo_limit = sizeof(struct drm_msm_gem_submit_bo) / 4096; 3587ec681f3Smrg bool bos_on_stack = msm_submit->nr_bos < bo_limit; 3597ec681f3Smrg struct drm_msm_gem_submit_bo 3607ec681f3Smrg _submit_bos[bos_on_stack ? msm_submit->nr_bos : 0]; 3617ec681f3Smrg struct drm_msm_gem_submit_bo *submit_bos; 3627ec681f3Smrg if (bos_on_stack) { 3637ec681f3Smrg submit_bos = _submit_bos; 3647ec681f3Smrg } else { 3657ec681f3Smrg submit_bos = malloc(msm_submit->nr_bos * sizeof(submit_bos[0])); 3667ec681f3Smrg } 3677ec681f3Smrg 3687ec681f3Smrg for (unsigned i = 0; i < msm_submit->nr_bos; i++) { 3697ec681f3Smrg submit_bos[i].flags = msm_submit->bos[i]->reloc_flags; 3707ec681f3Smrg submit_bos[i].handle = msm_submit->bos[i]->handle; 3717ec681f3Smrg submit_bos[i].presumed = 0; 3727ec681f3Smrg } 3737ec681f3Smrg 3747ec681f3Smrg req.bos = VOID2U64(submit_bos); 3757ec681f3Smrg req.nr_bos = msm_submit->nr_bos; 3767ec681f3Smrg req.cmds = VOID2U64(cmds); 3777ec681f3Smrg req.nr_cmds = nr_cmds; 3787ec681f3Smrg 3797ec681f3Smrg DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos); 3807ec681f3Smrg 3817ec681f3Smrg ret = drmCommandWriteRead(msm_pipe->base.dev->fd, DRM_MSM_GEM_SUBMIT, &req, 3827ec681f3Smrg sizeof(req)); 3837ec681f3Smrg if (ret) { 3847ec681f3Smrg ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); 3857ec681f3Smrg msm_dump_submit(&req); 3867ec681f3Smrg } else if (!ret && msm_submit->out_fence) { 3877ec681f3Smrg msm_submit->out_fence->fence.kfence = req.fence; 3887ec681f3Smrg msm_submit->out_fence->fence.ufence = msm_submit->base.fence; 3897ec681f3Smrg msm_submit->out_fence->fence_fd = req.fence_fd; 3907ec681f3Smrg } 3917ec681f3Smrg 3927ec681f3Smrg if (!bos_on_stack) 3937ec681f3Smrg free(submit_bos); 3947ec681f3Smrg 3957ec681f3Smrg pthread_mutex_lock(&flush_mtx); 3967ec681f3Smrg assert(fd_fence_before(msm_pipe->last_submit_fence, msm_submit->base.fence)); 3977ec681f3Smrg msm_pipe->last_submit_fence = msm_submit->base.fence; 3987ec681f3Smrg pthread_cond_broadcast(&flush_cnd); 3997ec681f3Smrg pthread_mutex_unlock(&flush_mtx); 4007ec681f3Smrg 4017ec681f3Smrg if (msm_submit->in_fence_fd != -1) 4027ec681f3Smrg close(msm_submit->in_fence_fd); 4037ec681f3Smrg 4047ec681f3Smrg return ret; 4057e102996Smaya} 4067e102996Smaya 4077e102996Smayastatic void 4087ec681f3Smrgmsm_submit_sp_flush_execute(void *job, void *gdata, int thread_index) 4097e102996Smaya{ 4107ec681f3Smrg struct fd_submit *submit = job; 4117ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(submit); 4127e102996Smaya 4137ec681f3Smrg flush_submit_list(&msm_submit->submit_list); 4147e102996Smaya 4157ec681f3Smrg DEBUG_MSG("finish: %u", submit->fence); 4167ec681f3Smrg} 4177e102996Smaya 4187ec681f3Smrgstatic void 4197ec681f3Smrgmsm_submit_sp_flush_cleanup(void *job, void *gdata, int thread_index) 4207ec681f3Smrg{ 4217ec681f3Smrg struct fd_submit *submit = job; 4227ec681f3Smrg fd_submit_del(submit); 4237e102996Smaya} 4247e102996Smaya 4257ec681f3Smrgstatic int 4267ec681f3Smrgenqueue_submit_list(struct list_head *submit_list) 4277ec681f3Smrg{ 4287ec681f3Smrg struct fd_submit *submit = last_submit(submit_list); 4297ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(submit); 4307ec681f3Smrg struct msm_device *msm_dev = to_msm_device(submit->pipe->dev); 4317ec681f3Smrg 4327ec681f3Smrg list_replace(submit_list, &msm_submit->submit_list); 4337ec681f3Smrg list_inithead(submit_list); 4347ec681f3Smrg 4357ec681f3Smrg struct util_queue_fence *fence; 4367ec681f3Smrg if (msm_submit->out_fence) { 4377ec681f3Smrg fence = &msm_submit->out_fence->ready; 4387ec681f3Smrg } else { 4397ec681f3Smrg util_queue_fence_init(&msm_submit->fence); 4407ec681f3Smrg fence = &msm_submit->fence; 4417ec681f3Smrg } 4427ec681f3Smrg 4437ec681f3Smrg DEBUG_MSG("enqueue: %u", submit->fence); 4447ec681f3Smrg 4457ec681f3Smrg util_queue_add_job(&msm_dev->submit_queue, 4467ec681f3Smrg submit, fence, 4477ec681f3Smrg msm_submit_sp_flush_execute, 4487ec681f3Smrg msm_submit_sp_flush_cleanup, 4497ec681f3Smrg 0); 4507ec681f3Smrg 4517ec681f3Smrg return 0; 4527ec681f3Smrg} 4537e102996Smaya 4547ec681f3Smrgstatic bool 4557ec681f3Smrgshould_defer(struct fd_submit *submit) 4567e102996Smaya{ 4577ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(submit); 4587e102996Smaya 4597ec681f3Smrg /* if too many bo's, it may not be worth the CPU cost of submit merging: */ 4607ec681f3Smrg if (msm_submit->nr_bos > 30) 4617ec681f3Smrg return false; 4627e102996Smaya 4637ec681f3Smrg /* On the kernel side, with 32K ringbuffer, we have an upper limit of 2k 4647ec681f3Smrg * cmds before we exceed the size of the ringbuffer, which results in 4657ec681f3Smrg * deadlock writing into the RB (ie. kernel doesn't finish writing into 4667ec681f3Smrg * the RB so it doesn't kick the GPU to start consuming from the RB) 4677ec681f3Smrg */ 4687ec681f3Smrg if (submit->pipe->dev->deferred_cmds > 128) 4697ec681f3Smrg return false; 4707e102996Smaya 4717ec681f3Smrg return true; 4727e102996Smaya} 4737e102996Smaya 4747ec681f3Smrgstatic int 4757ec681f3Smrgmsm_submit_sp_flush(struct fd_submit *submit, int in_fence_fd, 4767ec681f3Smrg struct fd_submit_fence *out_fence) 4777e102996Smaya{ 4787ec681f3Smrg struct fd_device *dev = submit->pipe->dev; 4797ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(submit->pipe); 4807ec681f3Smrg 4817ec681f3Smrg /* Acquire lock before flush_prep() because it is possible to race between 4827ec681f3Smrg * this and pipe->flush(): 4837ec681f3Smrg */ 4847ec681f3Smrg simple_mtx_lock(&dev->submit_lock); 4857ec681f3Smrg 4867ec681f3Smrg /* If there are deferred submits from another fd_pipe, flush them now, 4877ec681f3Smrg * since we can't merge submits from different submitqueue's (ie. they 4887ec681f3Smrg * could have different priority, etc) 4897ec681f3Smrg */ 4907ec681f3Smrg if (!list_is_empty(&dev->deferred_submits) && 4917ec681f3Smrg (last_submit(&dev->deferred_submits)->pipe != submit->pipe)) { 4927ec681f3Smrg struct list_head submit_list; 4937ec681f3Smrg 4947ec681f3Smrg list_replace(&dev->deferred_submits, &submit_list); 4957ec681f3Smrg list_inithead(&dev->deferred_submits); 4967ec681f3Smrg dev->deferred_cmds = 0; 4977e102996Smaya 4987ec681f3Smrg enqueue_submit_list(&submit_list); 4997ec681f3Smrg } 5007e102996Smaya 5017ec681f3Smrg list_addtail(&fd_submit_ref(submit)->node, &dev->deferred_submits); 5027ec681f3Smrg 5037ec681f3Smrg bool has_shared = msm_submit_sp_flush_prep(submit, in_fence_fd, out_fence); 5047ec681f3Smrg 5057ec681f3Smrg assert(fd_fence_before(msm_pipe->last_enqueue_fence, submit->fence)); 5067ec681f3Smrg msm_pipe->last_enqueue_fence = submit->fence; 5077ec681f3Smrg 5087ec681f3Smrg /* If we don't need an out-fence, we can defer the submit. 5097ec681f3Smrg * 5107ec681f3Smrg * TODO we could defer submits with in-fence as well.. if we took our own 5117ec681f3Smrg * reference to the fd, and merged all the in-fence-fd's when we flush the 5127ec681f3Smrg * deferred submits 5137ec681f3Smrg */ 5147ec681f3Smrg if ((in_fence_fd == -1) && !out_fence && !has_shared && should_defer(submit)) { 5157ec681f3Smrg DEBUG_MSG("defer: %u", submit->fence); 5167ec681f3Smrg dev->deferred_cmds += fd_ringbuffer_cmd_count(submit->primary); 5177ec681f3Smrg assert(dev->deferred_cmds == fd_dev_count_deferred_cmds(dev)); 5187ec681f3Smrg simple_mtx_unlock(&dev->submit_lock); 5197ec681f3Smrg 5207ec681f3Smrg return 0; 5217ec681f3Smrg } 5227ec681f3Smrg 5237ec681f3Smrg struct list_head submit_list; 5247ec681f3Smrg 5257ec681f3Smrg list_replace(&dev->deferred_submits, &submit_list); 5267ec681f3Smrg list_inithead(&dev->deferred_submits); 5277ec681f3Smrg dev->deferred_cmds = 0; 5287ec681f3Smrg 5297ec681f3Smrg simple_mtx_unlock(&dev->submit_lock); 5307ec681f3Smrg 5317ec681f3Smrg return enqueue_submit_list(&submit_list); 5327e102996Smaya} 5337e102996Smaya 5347ec681f3Smrgvoid 5357ec681f3Smrgmsm_pipe_sp_flush(struct fd_pipe *pipe, uint32_t fence) 5367e102996Smaya{ 5377ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 5387ec681f3Smrg struct fd_device *dev = pipe->dev; 5397ec681f3Smrg struct list_head submit_list; 5407ec681f3Smrg 5417ec681f3Smrg DEBUG_MSG("flush: %u", fence); 5427ec681f3Smrg 5437ec681f3Smrg list_inithead(&submit_list); 5447ec681f3Smrg 5457ec681f3Smrg simple_mtx_lock(&dev->submit_lock); 5467e102996Smaya 5477ec681f3Smrg assert(!fd_fence_after(fence, msm_pipe->last_enqueue_fence)); 5487e102996Smaya 5497ec681f3Smrg foreach_submit_safe (deferred_submit, &dev->deferred_submits) { 5507ec681f3Smrg /* We should never have submits from multiple pipes in the deferred 5517ec681f3Smrg * list. If we did, we couldn't compare their fence to our fence, 5527ec681f3Smrg * since each fd_pipe is an independent timeline. 5537ec681f3Smrg */ 5547ec681f3Smrg if (deferred_submit->pipe != pipe) 5557ec681f3Smrg break; 5567e102996Smaya 5577ec681f3Smrg if (fd_fence_after(deferred_submit->fence, fence)) 5587ec681f3Smrg break; 5597e102996Smaya 5607ec681f3Smrg list_del(&deferred_submit->node); 5617ec681f3Smrg list_addtail(&deferred_submit->node, &submit_list); 5627ec681f3Smrg dev->deferred_cmds -= fd_ringbuffer_cmd_count(deferred_submit->primary); 5637ec681f3Smrg } 5647ec681f3Smrg 5657ec681f3Smrg assert(dev->deferred_cmds == fd_dev_count_deferred_cmds(dev)); 5667ec681f3Smrg 5677ec681f3Smrg simple_mtx_unlock(&dev->submit_lock); 5687ec681f3Smrg 5697ec681f3Smrg if (list_is_empty(&submit_list)) 5707ec681f3Smrg goto flush_sync; 5717ec681f3Smrg 5727ec681f3Smrg enqueue_submit_list(&submit_list); 5737ec681f3Smrg 5747ec681f3Smrgflush_sync: 5757ec681f3Smrg /* Once we are sure that we've enqueued at least up to the requested 5767ec681f3Smrg * submit, we need to be sure that submitq has caught up and flushed 5777ec681f3Smrg * them to the kernel 5787ec681f3Smrg */ 5797ec681f3Smrg pthread_mutex_lock(&flush_mtx); 5807ec681f3Smrg while (fd_fence_before(msm_pipe->last_submit_fence, fence)) { 5817ec681f3Smrg pthread_cond_wait(&flush_cnd, &flush_mtx); 5827ec681f3Smrg } 5837ec681f3Smrg pthread_mutex_unlock(&flush_mtx); 5847e102996Smaya} 5857e102996Smaya 5867e102996Smayastatic void 5877ec681f3Smrgmsm_submit_sp_destroy(struct fd_submit *submit) 5887e102996Smaya{ 5897ec681f3Smrg struct msm_submit_sp *msm_submit = to_msm_submit_sp(submit); 5907e102996Smaya 5917ec681f3Smrg if (msm_submit->suballoc_ring) 5927ec681f3Smrg fd_ringbuffer_del(msm_submit->suballoc_ring); 5937e102996Smaya 5947ec681f3Smrg _mesa_hash_table_destroy(msm_submit->bo_table, NULL); 5957e102996Smaya 5967ec681f3Smrg // TODO it would be nice to have a way to debug_assert() if all 5977ec681f3Smrg // rb's haven't been free'd back to the slab, because that is 5987ec681f3Smrg // an indication that we are leaking bo's 5997ec681f3Smrg slab_destroy_child(&msm_submit->ring_pool); 6007e102996Smaya 6017ec681f3Smrg for (unsigned i = 0; i < msm_submit->nr_bos; i++) 6027ec681f3Smrg fd_bo_del(msm_submit->bos[i]); 6037e102996Smaya 6047ec681f3Smrg free(msm_submit->bos); 6057ec681f3Smrg free(msm_submit); 6067ec681f3Smrg} 6077e102996Smaya 6087ec681f3Smrgstatic const struct fd_submit_funcs submit_funcs = { 6097ec681f3Smrg .new_ringbuffer = msm_submit_sp_new_ringbuffer, 6107ec681f3Smrg .flush = msm_submit_sp_flush, 6117ec681f3Smrg .destroy = msm_submit_sp_destroy, 6127ec681f3Smrg}; 6137e102996Smaya 6147ec681f3Smrgstruct fd_submit * 6157ec681f3Smrgmsm_submit_sp_new(struct fd_pipe *pipe) 6167ec681f3Smrg{ 6177ec681f3Smrg struct msm_submit_sp *msm_submit = calloc(1, sizeof(*msm_submit)); 6187ec681f3Smrg struct fd_submit *submit; 6197e102996Smaya 6207ec681f3Smrg msm_submit->bo_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, 6217ec681f3Smrg _mesa_key_pointer_equal); 6227e102996Smaya 6237ec681f3Smrg slab_create_child(&msm_submit->ring_pool, &to_msm_pipe(pipe)->ring_pool); 6247e102996Smaya 6257ec681f3Smrg submit = &msm_submit->base; 6267ec681f3Smrg submit->funcs = &submit_funcs; 6277e102996Smaya 6287ec681f3Smrg return submit; 6297e102996Smaya} 6307e102996Smaya 6317ec681f3Smrgvoid 6327ec681f3Smrgmsm_pipe_sp_ringpool_init(struct msm_pipe *msm_pipe) 6337e102996Smaya{ 6347ec681f3Smrg // TODO tune size: 6357ec681f3Smrg slab_create_parent(&msm_pipe->ring_pool, sizeof(struct msm_ringbuffer_sp), 6367ec681f3Smrg 16); 6377e102996Smaya} 6387e102996Smaya 6397ec681f3Smrgvoid 6407ec681f3Smrgmsm_pipe_sp_ringpool_fini(struct msm_pipe *msm_pipe) 6417e102996Smaya{ 6427ec681f3Smrg if (msm_pipe->ring_pool.num_elements) 6437ec681f3Smrg slab_destroy_parent(&msm_pipe->ring_pool); 6447e102996Smaya} 6457e102996Smaya 6467e102996Smayastatic void 6477ec681f3Smrgfinalize_current_cmd(struct fd_ringbuffer *ring) 6487e102996Smaya{ 6497ec681f3Smrg debug_assert(!(ring->flags & _FD_RINGBUFFER_OBJECT)); 6507ec681f3Smrg 6517ec681f3Smrg struct msm_ringbuffer_sp *msm_ring = to_msm_ringbuffer_sp(ring); 6527ec681f3Smrg APPEND(&msm_ring->u, cmds, 6537ec681f3Smrg (struct msm_cmd_sp){ 6547ec681f3Smrg .ring_bo = fd_bo_ref(msm_ring->ring_bo), 6557ec681f3Smrg .size = offset_bytes(ring->cur, ring->start), 6567ec681f3Smrg }); 6577ec681f3Smrg} 6587e102996Smaya 6597ec681f3Smrgstatic void 6607ec681f3Smrgmsm_ringbuffer_sp_grow(struct fd_ringbuffer *ring, uint32_t size) 6617ec681f3Smrg{ 6627ec681f3Smrg struct msm_ringbuffer_sp *msm_ring = to_msm_ringbuffer_sp(ring); 6637ec681f3Smrg struct fd_pipe *pipe = msm_ring->u.submit->pipe; 6647e102996Smaya 6657ec681f3Smrg debug_assert(ring->flags & FD_RINGBUFFER_GROWABLE); 6667e102996Smaya 6677ec681f3Smrg finalize_current_cmd(ring); 6687e102996Smaya 6697ec681f3Smrg fd_bo_del(msm_ring->ring_bo); 6707ec681f3Smrg msm_ring->ring_bo = fd_bo_new_ring(pipe->dev, size); 6717e102996Smaya 6727ec681f3Smrg ring->start = fd_bo_map(msm_ring->ring_bo); 6737ec681f3Smrg ring->end = &(ring->start[size / 4]); 6747ec681f3Smrg ring->cur = ring->start; 6757ec681f3Smrg ring->size = size; 6767e102996Smaya} 6777e102996Smaya 6787ec681f3Smrgstatic inline bool 6797ec681f3Smrgmsm_ringbuffer_references_bo(struct fd_ringbuffer *ring, struct fd_bo *bo) 6807ec681f3Smrg{ 6817ec681f3Smrg struct msm_ringbuffer_sp *msm_ring = to_msm_ringbuffer_sp(ring); 6827e102996Smaya 6837ec681f3Smrg for (int i = 0; i < msm_ring->u.nr_reloc_bos; i++) { 6847ec681f3Smrg if (msm_ring->u.reloc_bos[i] == bo) 6857ec681f3Smrg return true; 6867ec681f3Smrg } 6877ec681f3Smrg return false; 6887ec681f3Smrg} 6897ec681f3Smrg 6907ec681f3Smrg#define PTRSZ 64 6917ec681f3Smrg#include "msm_ringbuffer_sp.h" 6927ec681f3Smrg#undef PTRSZ 6937ec681f3Smrg#define PTRSZ 32 6947ec681f3Smrg#include "msm_ringbuffer_sp.h" 6957ec681f3Smrg#undef PTRSZ 6967ec681f3Smrg 6977ec681f3Smrgstatic uint32_t 6987ec681f3Smrgmsm_ringbuffer_sp_cmd_count(struct fd_ringbuffer *ring) 6997ec681f3Smrg{ 7007ec681f3Smrg if (ring->flags & FD_RINGBUFFER_GROWABLE) 7017ec681f3Smrg return to_msm_ringbuffer_sp(ring)->u.nr_cmds + 1; 7027ec681f3Smrg return 1; 7037ec681f3Smrg} 7047ec681f3Smrg 7057ec681f3Smrgstatic bool 7067ec681f3Smrgmsm_ringbuffer_sp_check_size(struct fd_ringbuffer *ring) 7077ec681f3Smrg{ 7087ec681f3Smrg assert(!(ring->flags & _FD_RINGBUFFER_OBJECT)); 7097ec681f3Smrg struct msm_ringbuffer_sp *msm_ring = to_msm_ringbuffer_sp(ring); 7107ec681f3Smrg struct fd_submit *submit = msm_ring->u.submit; 7117ec681f3Smrg 7127ec681f3Smrg if (to_msm_submit_sp(submit)->nr_bos > MAX_ARRAY_SIZE/2) { 7137ec681f3Smrg return false; 7147ec681f3Smrg } 7157ec681f3Smrg 7167ec681f3Smrg return true; 7177ec681f3Smrg} 7187ec681f3Smrg 7197ec681f3Smrgstatic void 7207ec681f3Smrgmsm_ringbuffer_sp_destroy(struct fd_ringbuffer *ring) 7217e102996Smaya{ 7227ec681f3Smrg struct msm_ringbuffer_sp *msm_ring = to_msm_ringbuffer_sp(ring); 7237e102996Smaya 7247ec681f3Smrg fd_bo_del(msm_ring->ring_bo); 7257e102996Smaya 7267ec681f3Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 7277ec681f3Smrg for (unsigned i = 0; i < msm_ring->u.nr_reloc_bos; i++) { 7287ec681f3Smrg fd_bo_del(msm_ring->u.reloc_bos[i]); 7297ec681f3Smrg } 7307ec681f3Smrg free(msm_ring->u.reloc_bos); 7317e102996Smaya 7327ec681f3Smrg free(msm_ring); 7337ec681f3Smrg } else { 7347ec681f3Smrg struct fd_submit *submit = msm_ring->u.submit; 7357e102996Smaya 7367ec681f3Smrg for (unsigned i = 0; i < msm_ring->u.nr_cmds; i++) { 7377ec681f3Smrg fd_bo_del(msm_ring->u.cmds[i].ring_bo); 7387ec681f3Smrg } 7397ec681f3Smrg free(msm_ring->u.cmds); 7407e102996Smaya 7417ec681f3Smrg slab_free(&to_msm_submit_sp(submit)->ring_pool, msm_ring); 7427ec681f3Smrg } 7437ec681f3Smrg} 7447ec681f3Smrg 7457ec681f3Smrgstatic const struct fd_ringbuffer_funcs ring_funcs_nonobj_32 = { 7467ec681f3Smrg .grow = msm_ringbuffer_sp_grow, 7477ec681f3Smrg .emit_reloc = msm_ringbuffer_sp_emit_reloc_nonobj_32, 7487ec681f3Smrg .emit_reloc_ring = msm_ringbuffer_sp_emit_reloc_ring_32, 7497ec681f3Smrg .cmd_count = msm_ringbuffer_sp_cmd_count, 7507ec681f3Smrg .check_size = msm_ringbuffer_sp_check_size, 7517ec681f3Smrg .destroy = msm_ringbuffer_sp_destroy, 7527ec681f3Smrg}; 7537e102996Smaya 7547ec681f3Smrgstatic const struct fd_ringbuffer_funcs ring_funcs_obj_32 = { 7557ec681f3Smrg .grow = msm_ringbuffer_sp_grow, 7567ec681f3Smrg .emit_reloc = msm_ringbuffer_sp_emit_reloc_obj_32, 7577ec681f3Smrg .emit_reloc_ring = msm_ringbuffer_sp_emit_reloc_ring_32, 7587ec681f3Smrg .cmd_count = msm_ringbuffer_sp_cmd_count, 7597ec681f3Smrg .destroy = msm_ringbuffer_sp_destroy, 7607ec681f3Smrg}; 7617e102996Smaya 7627ec681f3Smrgstatic const struct fd_ringbuffer_funcs ring_funcs_nonobj_64 = { 7637ec681f3Smrg .grow = msm_ringbuffer_sp_grow, 7647ec681f3Smrg .emit_reloc = msm_ringbuffer_sp_emit_reloc_nonobj_64, 7657ec681f3Smrg .emit_reloc_ring = msm_ringbuffer_sp_emit_reloc_ring_64, 7667ec681f3Smrg .cmd_count = msm_ringbuffer_sp_cmd_count, 7677ec681f3Smrg .check_size = msm_ringbuffer_sp_check_size, 7687ec681f3Smrg .destroy = msm_ringbuffer_sp_destroy, 7697ec681f3Smrg}; 7707ec681f3Smrg 7717ec681f3Smrgstatic const struct fd_ringbuffer_funcs ring_funcs_obj_64 = { 7727ec681f3Smrg .grow = msm_ringbuffer_sp_grow, 7737ec681f3Smrg .emit_reloc = msm_ringbuffer_sp_emit_reloc_obj_64, 7747ec681f3Smrg .emit_reloc_ring = msm_ringbuffer_sp_emit_reloc_ring_64, 7757ec681f3Smrg .cmd_count = msm_ringbuffer_sp_cmd_count, 7767ec681f3Smrg .destroy = msm_ringbuffer_sp_destroy, 7777ec681f3Smrg}; 7787ec681f3Smrg 7797ec681f3Smrgstatic inline struct fd_ringbuffer * 7807ec681f3Smrgmsm_ringbuffer_sp_init(struct msm_ringbuffer_sp *msm_ring, uint32_t size, 7817ec681f3Smrg enum fd_ringbuffer_flags flags) 7827ec681f3Smrg{ 7837ec681f3Smrg struct fd_ringbuffer *ring = &msm_ring->base; 7847ec681f3Smrg 7857ec681f3Smrg /* We don't do any translation from internal FD_RELOC flags to MSM flags. */ 7867ec681f3Smrg STATIC_ASSERT(FD_RELOC_READ == MSM_SUBMIT_BO_READ); 7877ec681f3Smrg STATIC_ASSERT(FD_RELOC_WRITE == MSM_SUBMIT_BO_WRITE); 7887ec681f3Smrg STATIC_ASSERT(FD_RELOC_DUMP == MSM_SUBMIT_BO_DUMP); 7897ec681f3Smrg 7907ec681f3Smrg debug_assert(msm_ring->ring_bo); 7917ec681f3Smrg 7927ec681f3Smrg uint8_t *base = fd_bo_map(msm_ring->ring_bo); 7937ec681f3Smrg ring->start = (void *)(base + msm_ring->offset); 7947ec681f3Smrg ring->end = &(ring->start[size / 4]); 7957ec681f3Smrg ring->cur = ring->start; 7967ec681f3Smrg 7977ec681f3Smrg ring->size = size; 7987ec681f3Smrg ring->flags = flags; 7997ec681f3Smrg 8007ec681f3Smrg if (flags & _FD_RINGBUFFER_OBJECT) { 8017ec681f3Smrg if (fd_dev_64b(&msm_ring->u.pipe->dev_id)) { 8027ec681f3Smrg ring->funcs = &ring_funcs_obj_64; 8037ec681f3Smrg } else { 8047ec681f3Smrg ring->funcs = &ring_funcs_obj_32; 8057ec681f3Smrg } 8067ec681f3Smrg } else { 8077ec681f3Smrg if (fd_dev_64b(&msm_ring->u.submit->pipe->dev_id)) { 8087ec681f3Smrg ring->funcs = &ring_funcs_nonobj_64; 8097ec681f3Smrg } else { 8107ec681f3Smrg ring->funcs = &ring_funcs_nonobj_32; 8117ec681f3Smrg } 8127ec681f3Smrg } 8137ec681f3Smrg 8147ec681f3Smrg // TODO initializing these could probably be conditional on flags 8157ec681f3Smrg // since unneed for FD_RINGBUFFER_STAGING case.. 8167ec681f3Smrg msm_ring->u.cmds = NULL; 8177ec681f3Smrg msm_ring->u.nr_cmds = msm_ring->u.max_cmds = 0; 8187ec681f3Smrg 8197ec681f3Smrg msm_ring->u.reloc_bos = NULL; 8207ec681f3Smrg msm_ring->u.nr_reloc_bos = msm_ring->u.max_reloc_bos = 0; 8217ec681f3Smrg 8227ec681f3Smrg return ring; 8237e102996Smaya} 8247e102996Smaya 8257e102996Smayastruct fd_ringbuffer * 8267e102996Smayamsm_ringbuffer_sp_new_object(struct fd_pipe *pipe, uint32_t size) 8277e102996Smaya{ 8287ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 8297ec681f3Smrg struct msm_ringbuffer_sp *msm_ring = malloc(sizeof(*msm_ring)); 8307ec681f3Smrg 8317ec681f3Smrg /* Lock access to the msm_pipe->suballoc_* since ringbuffer object allocation 8327ec681f3Smrg * can happen both on the frontend (most CSOs) and the driver thread (a6xx 8337ec681f3Smrg * cached tex state, for example) 8347ec681f3Smrg */ 8357ec681f3Smrg static simple_mtx_t suballoc_lock = _SIMPLE_MTX_INITIALIZER_NP; 8367ec681f3Smrg simple_mtx_lock(&suballoc_lock); 8377ec681f3Smrg 8387ec681f3Smrg /* Maximum known alignment requirement is a6xx's TEX_CONST at 16 dwords */ 8397ec681f3Smrg msm_ring->offset = align(msm_pipe->suballoc_offset, 64); 8407ec681f3Smrg if (!msm_pipe->suballoc_bo || 8417ec681f3Smrg msm_ring->offset + size > fd_bo_size(msm_pipe->suballoc_bo)) { 8427ec681f3Smrg if (msm_pipe->suballoc_bo) 8437ec681f3Smrg fd_bo_del(msm_pipe->suballoc_bo); 8447ec681f3Smrg msm_pipe->suballoc_bo = 8457ec681f3Smrg fd_bo_new_ring(pipe->dev, MAX2(SUBALLOC_SIZE, align(size, 4096))); 8467ec681f3Smrg msm_ring->offset = 0; 8477ec681f3Smrg } 8487ec681f3Smrg 8497ec681f3Smrg msm_ring->u.pipe = pipe; 8507ec681f3Smrg msm_ring->ring_bo = fd_bo_ref(msm_pipe->suballoc_bo); 8517ec681f3Smrg msm_ring->base.refcnt = 1; 8527ec681f3Smrg 8537ec681f3Smrg msm_pipe->suballoc_offset = msm_ring->offset + size; 8547ec681f3Smrg 8557ec681f3Smrg simple_mtx_unlock(&suballoc_lock); 8567ec681f3Smrg 8577ec681f3Smrg return msm_ringbuffer_sp_init(msm_ring, size, _FD_RINGBUFFER_OBJECT); 8587e102996Smaya} 859