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