1b8e80941Smrg/* 2b8e80941Smrg * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21b8e80941Smrg * SOFTWARE. 22b8e80941Smrg * 23b8e80941Smrg * Authors: 24b8e80941Smrg * Rob Clark <robclark@freedesktop.org> 25b8e80941Smrg */ 26b8e80941Smrg 27b8e80941Smrg#include <assert.h> 28b8e80941Smrg#include <inttypes.h> 29b8e80941Smrg 30b8e80941Smrg#include "util/hash_table.h" 31b8e80941Smrg#include "util/set.h" 32b8e80941Smrg#include "util/slab.h" 33b8e80941Smrg 34b8e80941Smrg#include "drm/freedreno_ringbuffer.h" 35b8e80941Smrg#include "msm_priv.h" 36b8e80941Smrg 37b8e80941Smrg/* The legacy implementation of submit/ringbuffer, which still does the 38b8e80941Smrg * traditional reloc and cmd tracking 39b8e80941Smrg */ 40b8e80941Smrg 41b8e80941Smrg 42b8e80941Smrg#define INIT_SIZE 0x1000 43b8e80941Smrg 44b8e80941Smrgstatic pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; 45b8e80941Smrg 46b8e80941Smrg 47b8e80941Smrgstruct msm_submit { 48b8e80941Smrg struct fd_submit base; 49b8e80941Smrg 50b8e80941Smrg DECLARE_ARRAY(struct drm_msm_gem_submit_bo, submit_bos); 51b8e80941Smrg DECLARE_ARRAY(struct fd_bo *, bos); 52b8e80941Smrg 53b8e80941Smrg unsigned seqno; 54b8e80941Smrg 55b8e80941Smrg /* maps fd_bo to idx in bos table: */ 56b8e80941Smrg struct hash_table *bo_table; 57b8e80941Smrg 58b8e80941Smrg struct slab_mempool ring_pool; 59b8e80941Smrg 60b8e80941Smrg /* hash-set of associated rings: */ 61b8e80941Smrg struct set *ring_set; 62b8e80941Smrg 63b8e80941Smrg struct fd_ringbuffer *primary; 64b8e80941Smrg 65b8e80941Smrg /* Allow for sub-allocation of stateobj ring buffers (ie. sharing 66b8e80941Smrg * the same underlying bo).. 67b8e80941Smrg * 68b8e80941Smrg * We also rely on previous stateobj having been fully constructed 69b8e80941Smrg * so we can reclaim extra space at it's end. 70b8e80941Smrg */ 71b8e80941Smrg struct fd_ringbuffer *suballoc_ring; 72b8e80941Smrg}; 73b8e80941SmrgFD_DEFINE_CAST(fd_submit, msm_submit); 74b8e80941Smrg 75b8e80941Smrg/* for FD_RINGBUFFER_GROWABLE rb's, tracks the 'finalized' cmdstream buffers 76b8e80941Smrg * and sizes. Ie. a finalized buffer can have no more commands appended to 77b8e80941Smrg * it. 78b8e80941Smrg */ 79b8e80941Smrgstruct msm_cmd { 80b8e80941Smrg struct fd_bo *ring_bo; 81b8e80941Smrg unsigned size; 82b8e80941Smrg DECLARE_ARRAY(struct drm_msm_gem_submit_reloc, relocs); 83b8e80941Smrg}; 84b8e80941Smrg 85b8e80941Smrgstatic struct msm_cmd * 86b8e80941Smrgcmd_new(struct fd_bo *ring_bo) 87b8e80941Smrg{ 88b8e80941Smrg struct msm_cmd *cmd = malloc(sizeof(*cmd)); 89b8e80941Smrg cmd->ring_bo = fd_bo_ref(ring_bo); 90b8e80941Smrg cmd->size = 0; 91b8e80941Smrg cmd->nr_relocs = cmd->max_relocs = 0; 92b8e80941Smrg cmd->relocs = NULL; 93b8e80941Smrg return cmd; 94b8e80941Smrg} 95b8e80941Smrg 96b8e80941Smrgstatic void 97b8e80941Smrgcmd_free(struct msm_cmd *cmd) 98b8e80941Smrg{ 99b8e80941Smrg fd_bo_del(cmd->ring_bo); 100b8e80941Smrg free(cmd->relocs); 101b8e80941Smrg free(cmd); 102b8e80941Smrg} 103b8e80941Smrg 104b8e80941Smrg/* for _FD_RINGBUFFER_OBJECT rb's we need to track the bo's and flags to 105b8e80941Smrg * later copy into the submit when the stateobj rb is later referenced by 106b8e80941Smrg * a regular rb: 107b8e80941Smrg */ 108b8e80941Smrgstruct msm_reloc_bo { 109b8e80941Smrg struct fd_bo *bo; 110b8e80941Smrg unsigned flags; 111b8e80941Smrg}; 112b8e80941Smrg 113b8e80941Smrgstruct msm_ringbuffer { 114b8e80941Smrg struct fd_ringbuffer base; 115b8e80941Smrg 116b8e80941Smrg /* for FD_RINGBUFFER_STREAMING rb's which are sub-allocated */ 117b8e80941Smrg unsigned offset; 118b8e80941Smrg 119b8e80941Smrg union { 120b8e80941Smrg /* for _FD_RINGBUFFER_OBJECT case: */ 121b8e80941Smrg struct { 122b8e80941Smrg struct fd_pipe *pipe; 123b8e80941Smrg DECLARE_ARRAY(struct msm_reloc_bo, reloc_bos); 124b8e80941Smrg struct set *ring_set; 125b8e80941Smrg }; 126b8e80941Smrg /* for other cases: */ 127b8e80941Smrg struct { 128b8e80941Smrg struct fd_submit *submit; 129b8e80941Smrg DECLARE_ARRAY(struct msm_cmd *, cmds); 130b8e80941Smrg }; 131b8e80941Smrg } u; 132b8e80941Smrg 133b8e80941Smrg struct msm_cmd *cmd; /* current cmd */ 134b8e80941Smrg struct fd_bo *ring_bo; 135b8e80941Smrg}; 136b8e80941SmrgFD_DEFINE_CAST(fd_ringbuffer, msm_ringbuffer); 137b8e80941Smrg 138b8e80941Smrgstatic void finalize_current_cmd(struct fd_ringbuffer *ring); 139b8e80941Smrgstatic struct fd_ringbuffer * msm_ringbuffer_init( 140b8e80941Smrg struct msm_ringbuffer *msm_ring, 141b8e80941Smrg uint32_t size, enum fd_ringbuffer_flags flags); 142b8e80941Smrg 143b8e80941Smrg/* add (if needed) bo to submit and return index: */ 144b8e80941Smrgstatic uint32_t 145b8e80941Smrgappend_bo(struct msm_submit *submit, struct fd_bo *bo, uint32_t flags) 146b8e80941Smrg{ 147b8e80941Smrg struct msm_bo *msm_bo = to_msm_bo(bo); 148b8e80941Smrg uint32_t idx; 149b8e80941Smrg pthread_mutex_lock(&idx_lock); 150b8e80941Smrg if (likely(msm_bo->current_submit_seqno == submit->seqno)) { 151b8e80941Smrg idx = msm_bo->idx; 152b8e80941Smrg } else { 153b8e80941Smrg uint32_t hash = _mesa_hash_pointer(bo); 154b8e80941Smrg struct hash_entry *entry; 155b8e80941Smrg 156b8e80941Smrg entry = _mesa_hash_table_search_pre_hashed(submit->bo_table, hash, bo); 157b8e80941Smrg if (entry) { 158b8e80941Smrg /* found */ 159b8e80941Smrg idx = (uint32_t)(uintptr_t)entry->data; 160b8e80941Smrg } else { 161b8e80941Smrg idx = APPEND(submit, submit_bos); 162b8e80941Smrg idx = APPEND(submit, bos); 163b8e80941Smrg 164b8e80941Smrg submit->submit_bos[idx].flags = 0; 165b8e80941Smrg submit->submit_bos[idx].handle = bo->handle; 166b8e80941Smrg submit->submit_bos[idx].presumed = 0; 167b8e80941Smrg 168b8e80941Smrg submit->bos[idx] = fd_bo_ref(bo); 169b8e80941Smrg 170b8e80941Smrg _mesa_hash_table_insert_pre_hashed(submit->bo_table, hash, bo, 171b8e80941Smrg (void *)(uintptr_t)idx); 172b8e80941Smrg } 173b8e80941Smrg msm_bo->current_submit_seqno = submit->seqno; 174b8e80941Smrg msm_bo->idx = idx; 175b8e80941Smrg } 176b8e80941Smrg pthread_mutex_unlock(&idx_lock); 177b8e80941Smrg if (flags & FD_RELOC_READ) 178b8e80941Smrg submit->submit_bos[idx].flags |= MSM_SUBMIT_BO_READ; 179b8e80941Smrg if (flags & FD_RELOC_WRITE) 180b8e80941Smrg submit->submit_bos[idx].flags |= MSM_SUBMIT_BO_WRITE; 181b8e80941Smrg return idx; 182b8e80941Smrg} 183b8e80941Smrg 184b8e80941Smrgstatic void 185b8e80941Smrgappend_ring(struct set *set, struct fd_ringbuffer *ring) 186b8e80941Smrg{ 187b8e80941Smrg uint32_t hash = _mesa_hash_pointer(ring); 188b8e80941Smrg 189b8e80941Smrg if (!_mesa_set_search_pre_hashed(set, hash, ring)) { 190b8e80941Smrg fd_ringbuffer_ref(ring); 191b8e80941Smrg _mesa_set_add_pre_hashed(set, hash, ring); 192b8e80941Smrg } 193b8e80941Smrg} 194b8e80941Smrg 195b8e80941Smrgstatic void 196b8e80941Smrgmsm_submit_suballoc_ring_bo(struct fd_submit *submit, 197b8e80941Smrg struct msm_ringbuffer *msm_ring, uint32_t size) 198b8e80941Smrg{ 199b8e80941Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 200b8e80941Smrg unsigned suballoc_offset = 0; 201b8e80941Smrg struct fd_bo *suballoc_bo = NULL; 202b8e80941Smrg 203b8e80941Smrg if (msm_submit->suballoc_ring) { 204b8e80941Smrg struct msm_ringbuffer *suballoc_ring = 205b8e80941Smrg to_msm_ringbuffer(msm_submit->suballoc_ring); 206b8e80941Smrg 207b8e80941Smrg suballoc_bo = suballoc_ring->ring_bo; 208b8e80941Smrg suballoc_offset = fd_ringbuffer_size(msm_submit->suballoc_ring) + 209b8e80941Smrg suballoc_ring->offset; 210b8e80941Smrg 211b8e80941Smrg suballoc_offset = align(suballoc_offset, 0x10); 212b8e80941Smrg 213b8e80941Smrg if ((size + suballoc_offset) > suballoc_bo->size) { 214b8e80941Smrg suballoc_bo = NULL; 215b8e80941Smrg } 216b8e80941Smrg } 217b8e80941Smrg 218b8e80941Smrg if (!suballoc_bo) { 219b8e80941Smrg // TODO possibly larger size for streaming bo? 220b8e80941Smrg msm_ring->ring_bo = fd_bo_new_ring( 221b8e80941Smrg submit->pipe->dev, 0x8000, 0); 222b8e80941Smrg msm_ring->offset = 0; 223b8e80941Smrg } else { 224b8e80941Smrg msm_ring->ring_bo = fd_bo_ref(suballoc_bo); 225b8e80941Smrg msm_ring->offset = suballoc_offset; 226b8e80941Smrg } 227b8e80941Smrg 228b8e80941Smrg struct fd_ringbuffer *old_suballoc_ring = msm_submit->suballoc_ring; 229b8e80941Smrg 230b8e80941Smrg msm_submit->suballoc_ring = fd_ringbuffer_ref(&msm_ring->base); 231b8e80941Smrg 232b8e80941Smrg if (old_suballoc_ring) 233b8e80941Smrg fd_ringbuffer_del(old_suballoc_ring); 234b8e80941Smrg} 235b8e80941Smrg 236b8e80941Smrgstatic struct fd_ringbuffer * 237b8e80941Smrgmsm_submit_new_ringbuffer(struct fd_submit *submit, uint32_t size, 238b8e80941Smrg enum fd_ringbuffer_flags flags) 239b8e80941Smrg{ 240b8e80941Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 241b8e80941Smrg struct msm_ringbuffer *msm_ring; 242b8e80941Smrg 243b8e80941Smrg msm_ring = slab_alloc_st(&msm_submit->ring_pool); 244b8e80941Smrg 245b8e80941Smrg msm_ring->u.submit = submit; 246b8e80941Smrg 247b8e80941Smrg /* NOTE: needs to be before _suballoc_ring_bo() since it could 248b8e80941Smrg * increment the refcnt of the current ring 249b8e80941Smrg */ 250b8e80941Smrg msm_ring->base.refcnt = 1; 251b8e80941Smrg 252b8e80941Smrg if (flags & FD_RINGBUFFER_STREAMING) { 253b8e80941Smrg msm_submit_suballoc_ring_bo(submit, msm_ring, size); 254b8e80941Smrg } else { 255b8e80941Smrg if (flags & FD_RINGBUFFER_GROWABLE) 256b8e80941Smrg size = INIT_SIZE; 257b8e80941Smrg 258b8e80941Smrg msm_ring->offset = 0; 259b8e80941Smrg msm_ring->ring_bo = fd_bo_new_ring(submit->pipe->dev, size, 0); 260b8e80941Smrg } 261b8e80941Smrg 262b8e80941Smrg if (!msm_ringbuffer_init(msm_ring, size, flags)) 263b8e80941Smrg return NULL; 264b8e80941Smrg 265b8e80941Smrg if (flags & FD_RINGBUFFER_PRIMARY) { 266b8e80941Smrg debug_assert(!msm_submit->primary); 267b8e80941Smrg msm_submit->primary = fd_ringbuffer_ref(&msm_ring->base); 268b8e80941Smrg } 269b8e80941Smrg 270b8e80941Smrg return &msm_ring->base; 271b8e80941Smrg} 272b8e80941Smrg 273b8e80941Smrgstatic struct drm_msm_gem_submit_reloc * 274b8e80941Smrghandle_stateobj_relocs(struct msm_submit *submit, struct msm_ringbuffer *ring) 275b8e80941Smrg{ 276b8e80941Smrg struct msm_cmd *cmd = ring->cmd; 277b8e80941Smrg struct drm_msm_gem_submit_reloc *relocs; 278b8e80941Smrg 279b8e80941Smrg relocs = malloc(cmd->nr_relocs * sizeof(*relocs)); 280b8e80941Smrg 281b8e80941Smrg for (unsigned i = 0; i < cmd->nr_relocs; i++) { 282b8e80941Smrg unsigned idx = cmd->relocs[i].reloc_idx; 283b8e80941Smrg struct fd_bo *bo = ring->u.reloc_bos[idx].bo; 284b8e80941Smrg unsigned flags = 0; 285b8e80941Smrg 286b8e80941Smrg if (ring->u.reloc_bos[idx].flags & MSM_SUBMIT_BO_READ) 287b8e80941Smrg flags |= FD_RELOC_READ; 288b8e80941Smrg if (ring->u.reloc_bos[idx].flags & MSM_SUBMIT_BO_WRITE) 289b8e80941Smrg flags |= FD_RELOC_WRITE; 290b8e80941Smrg 291b8e80941Smrg relocs[i] = cmd->relocs[i]; 292b8e80941Smrg relocs[i].reloc_idx = append_bo(submit, bo, flags); 293b8e80941Smrg } 294b8e80941Smrg 295b8e80941Smrg return relocs; 296b8e80941Smrg} 297b8e80941Smrg 298b8e80941Smrgstatic int 299b8e80941Smrgmsm_submit_flush(struct fd_submit *submit, int in_fence_fd, 300b8e80941Smrg int *out_fence_fd, uint32_t *out_fence) 301b8e80941Smrg{ 302b8e80941Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 303b8e80941Smrg struct msm_pipe *msm_pipe = to_msm_pipe(submit->pipe); 304b8e80941Smrg struct drm_msm_gem_submit req = { 305b8e80941Smrg .flags = msm_pipe->pipe, 306b8e80941Smrg .queueid = msm_pipe->queue_id, 307b8e80941Smrg }; 308b8e80941Smrg int ret; 309b8e80941Smrg 310b8e80941Smrg debug_assert(msm_submit->primary); 311b8e80941Smrg 312b8e80941Smrg finalize_current_cmd(msm_submit->primary); 313b8e80941Smrg append_ring(msm_submit->ring_set, msm_submit->primary); 314b8e80941Smrg 315b8e80941Smrg unsigned nr_cmds = 0; 316b8e80941Smrg unsigned nr_objs = 0; 317b8e80941Smrg 318b8e80941Smrg set_foreach(msm_submit->ring_set, entry) { 319b8e80941Smrg struct fd_ringbuffer *ring = (void *)entry->key; 320b8e80941Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 321b8e80941Smrg nr_cmds += 1; 322b8e80941Smrg nr_objs += 1; 323b8e80941Smrg } else { 324b8e80941Smrg if (ring != msm_submit->primary) 325b8e80941Smrg finalize_current_cmd(ring); 326b8e80941Smrg nr_cmds += to_msm_ringbuffer(ring)->u.nr_cmds; 327b8e80941Smrg } 328b8e80941Smrg } 329b8e80941Smrg 330b8e80941Smrg void *obj_relocs[nr_objs]; 331b8e80941Smrg struct drm_msm_gem_submit_cmd cmds[nr_cmds]; 332b8e80941Smrg unsigned i = 0, o = 0; 333b8e80941Smrg 334b8e80941Smrg set_foreach(msm_submit->ring_set, entry) { 335b8e80941Smrg struct fd_ringbuffer *ring = (void *)entry->key; 336b8e80941Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 337b8e80941Smrg 338b8e80941Smrg debug_assert(i < nr_cmds); 339b8e80941Smrg 340b8e80941Smrg // TODO handle relocs: 341b8e80941Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 342b8e80941Smrg 343b8e80941Smrg debug_assert(o < nr_objs); 344b8e80941Smrg 345b8e80941Smrg void *relocs = handle_stateobj_relocs(msm_submit, msm_ring); 346b8e80941Smrg obj_relocs[o++] = relocs; 347b8e80941Smrg 348b8e80941Smrg cmds[i].type = MSM_SUBMIT_CMD_IB_TARGET_BUF; 349b8e80941Smrg cmds[i].submit_idx = 350b8e80941Smrg append_bo(msm_submit, msm_ring->ring_bo, FD_RELOC_READ); 351b8e80941Smrg cmds[i].submit_offset = msm_ring->offset; 352b8e80941Smrg cmds[i].size = offset_bytes(ring->cur, ring->start); 353b8e80941Smrg cmds[i].pad = 0; 354b8e80941Smrg cmds[i].nr_relocs = msm_ring->cmd->nr_relocs; 355b8e80941Smrg cmds[i].relocs = VOID2U64(relocs); 356b8e80941Smrg 357b8e80941Smrg i++; 358b8e80941Smrg } else { 359b8e80941Smrg for (unsigned j = 0; j < msm_ring->u.nr_cmds; j++) { 360b8e80941Smrg if (ring->flags & FD_RINGBUFFER_PRIMARY) { 361b8e80941Smrg cmds[i].type = MSM_SUBMIT_CMD_BUF; 362b8e80941Smrg } else { 363b8e80941Smrg cmds[i].type = MSM_SUBMIT_CMD_IB_TARGET_BUF; 364b8e80941Smrg } 365b8e80941Smrg cmds[i].submit_idx = append_bo(msm_submit, 366b8e80941Smrg msm_ring->u.cmds[j]->ring_bo, FD_RELOC_READ); 367b8e80941Smrg cmds[i].submit_offset = msm_ring->offset; 368b8e80941Smrg cmds[i].size = msm_ring->u.cmds[j]->size; 369b8e80941Smrg cmds[i].pad = 0; 370b8e80941Smrg cmds[i].nr_relocs = msm_ring->u.cmds[j]->nr_relocs; 371b8e80941Smrg cmds[i].relocs = VOID2U64(msm_ring->u.cmds[j]->relocs); 372b8e80941Smrg 373b8e80941Smrg i++; 374b8e80941Smrg } 375b8e80941Smrg } 376b8e80941Smrg } 377b8e80941Smrg 378b8e80941Smrg if (in_fence_fd != -1) { 379b8e80941Smrg req.flags |= MSM_SUBMIT_FENCE_FD_IN | MSM_SUBMIT_NO_IMPLICIT; 380b8e80941Smrg req.fence_fd = in_fence_fd; 381b8e80941Smrg } 382b8e80941Smrg 383b8e80941Smrg if (out_fence_fd) { 384b8e80941Smrg req.flags |= MSM_SUBMIT_FENCE_FD_OUT; 385b8e80941Smrg } 386b8e80941Smrg 387b8e80941Smrg /* needs to be after get_cmd() as that could create bos/cmds table: */ 388b8e80941Smrg req.bos = VOID2U64(msm_submit->submit_bos), 389b8e80941Smrg req.nr_bos = msm_submit->nr_submit_bos; 390b8e80941Smrg req.cmds = VOID2U64(cmds), 391b8e80941Smrg req.nr_cmds = nr_cmds; 392b8e80941Smrg 393b8e80941Smrg DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos); 394b8e80941Smrg 395b8e80941Smrg ret = drmCommandWriteRead(submit->pipe->dev->fd, DRM_MSM_GEM_SUBMIT, 396b8e80941Smrg &req, sizeof(req)); 397b8e80941Smrg if (ret) { 398b8e80941Smrg ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); 399b8e80941Smrg msm_dump_submit(&req); 400b8e80941Smrg } else if (!ret) { 401b8e80941Smrg if (out_fence) 402b8e80941Smrg *out_fence = req.fence; 403b8e80941Smrg 404b8e80941Smrg if (out_fence_fd) 405b8e80941Smrg *out_fence_fd = req.fence_fd; 406b8e80941Smrg } 407b8e80941Smrg 408b8e80941Smrg for (unsigned o = 0; o < nr_objs; o++) 409b8e80941Smrg free(obj_relocs[o]); 410b8e80941Smrg 411b8e80941Smrg return ret; 412b8e80941Smrg} 413b8e80941Smrg 414b8e80941Smrgstatic void 415b8e80941Smrgunref_rings(struct set_entry *entry) 416b8e80941Smrg{ 417b8e80941Smrg struct fd_ringbuffer *ring = (void *)entry->key; 418b8e80941Smrg fd_ringbuffer_del(ring); 419b8e80941Smrg} 420b8e80941Smrg 421b8e80941Smrgstatic void 422b8e80941Smrgmsm_submit_destroy(struct fd_submit *submit) 423b8e80941Smrg{ 424b8e80941Smrg struct msm_submit *msm_submit = to_msm_submit(submit); 425b8e80941Smrg 426b8e80941Smrg if (msm_submit->primary) 427b8e80941Smrg fd_ringbuffer_del(msm_submit->primary); 428b8e80941Smrg if (msm_submit->suballoc_ring) 429b8e80941Smrg fd_ringbuffer_del(msm_submit->suballoc_ring); 430b8e80941Smrg 431b8e80941Smrg _mesa_hash_table_destroy(msm_submit->bo_table, NULL); 432b8e80941Smrg _mesa_set_destroy(msm_submit->ring_set, unref_rings); 433b8e80941Smrg 434b8e80941Smrg // TODO it would be nice to have a way to debug_assert() if all 435b8e80941Smrg // rb's haven't been free'd back to the slab, because that is 436b8e80941Smrg // an indication that we are leaking bo's 437b8e80941Smrg slab_destroy(&msm_submit->ring_pool); 438b8e80941Smrg 439b8e80941Smrg for (unsigned i = 0; i < msm_submit->nr_bos; i++) 440b8e80941Smrg fd_bo_del(msm_submit->bos[i]); 441b8e80941Smrg 442b8e80941Smrg free(msm_submit->submit_bos); 443b8e80941Smrg free(msm_submit->bos); 444b8e80941Smrg free(msm_submit); 445b8e80941Smrg} 446b8e80941Smrg 447b8e80941Smrgstatic const struct fd_submit_funcs submit_funcs = { 448b8e80941Smrg .new_ringbuffer = msm_submit_new_ringbuffer, 449b8e80941Smrg .flush = msm_submit_flush, 450b8e80941Smrg .destroy = msm_submit_destroy, 451b8e80941Smrg}; 452b8e80941Smrg 453b8e80941Smrgstruct fd_submit * 454b8e80941Smrgmsm_submit_new(struct fd_pipe *pipe) 455b8e80941Smrg{ 456b8e80941Smrg struct msm_submit *msm_submit = calloc(1, sizeof(*msm_submit)); 457b8e80941Smrg struct fd_submit *submit; 458b8e80941Smrg static unsigned submit_cnt = 0; 459b8e80941Smrg 460b8e80941Smrg msm_submit->seqno = ++submit_cnt; 461b8e80941Smrg msm_submit->bo_table = _mesa_hash_table_create(NULL, 462b8e80941Smrg _mesa_hash_pointer, _mesa_key_pointer_equal); 463b8e80941Smrg msm_submit->ring_set = _mesa_set_create(NULL, 464b8e80941Smrg _mesa_hash_pointer, _mesa_key_pointer_equal); 465b8e80941Smrg // TODO tune size: 466b8e80941Smrg slab_create(&msm_submit->ring_pool, sizeof(struct msm_ringbuffer), 16); 467b8e80941Smrg 468b8e80941Smrg submit = &msm_submit->base; 469b8e80941Smrg submit->pipe = pipe; 470b8e80941Smrg submit->funcs = &submit_funcs; 471b8e80941Smrg 472b8e80941Smrg return submit; 473b8e80941Smrg} 474b8e80941Smrg 475b8e80941Smrg 476b8e80941Smrgstatic void 477b8e80941Smrgfinalize_current_cmd(struct fd_ringbuffer *ring) 478b8e80941Smrg{ 479b8e80941Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 480b8e80941Smrg 481b8e80941Smrg debug_assert(!(ring->flags & _FD_RINGBUFFER_OBJECT)); 482b8e80941Smrg 483b8e80941Smrg if (!msm_ring->cmd) 484b8e80941Smrg return; 485b8e80941Smrg 486b8e80941Smrg debug_assert(msm_ring->cmd->ring_bo == msm_ring->ring_bo); 487b8e80941Smrg 488b8e80941Smrg unsigned idx = APPEND(&msm_ring->u, cmds); 489b8e80941Smrg 490b8e80941Smrg msm_ring->u.cmds[idx] = msm_ring->cmd; 491b8e80941Smrg msm_ring->cmd = NULL; 492b8e80941Smrg 493b8e80941Smrg msm_ring->u.cmds[idx]->size = offset_bytes(ring->cur, ring->start); 494b8e80941Smrg} 495b8e80941Smrg 496b8e80941Smrgstatic void 497b8e80941Smrgmsm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size) 498b8e80941Smrg{ 499b8e80941Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 500b8e80941Smrg struct fd_pipe *pipe = msm_ring->u.submit->pipe; 501b8e80941Smrg 502b8e80941Smrg debug_assert(ring->flags & FD_RINGBUFFER_GROWABLE); 503b8e80941Smrg 504b8e80941Smrg finalize_current_cmd(ring); 505b8e80941Smrg 506b8e80941Smrg fd_bo_del(msm_ring->ring_bo); 507b8e80941Smrg msm_ring->ring_bo = fd_bo_new_ring(pipe->dev, size, 0); 508b8e80941Smrg msm_ring->cmd = cmd_new(msm_ring->ring_bo); 509b8e80941Smrg 510b8e80941Smrg ring->start = fd_bo_map(msm_ring->ring_bo); 511b8e80941Smrg ring->end = &(ring->start[size/4]); 512b8e80941Smrg ring->cur = ring->start; 513b8e80941Smrg ring->size = size; 514b8e80941Smrg} 515b8e80941Smrg 516b8e80941Smrgstatic void 517b8e80941Smrgmsm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, 518b8e80941Smrg const struct fd_reloc *reloc) 519b8e80941Smrg{ 520b8e80941Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 521b8e80941Smrg struct fd_pipe *pipe; 522b8e80941Smrg unsigned reloc_idx; 523b8e80941Smrg 524b8e80941Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 525b8e80941Smrg unsigned idx = APPEND(&msm_ring->u, reloc_bos); 526b8e80941Smrg 527b8e80941Smrg msm_ring->u.reloc_bos[idx].bo = fd_bo_ref(reloc->bo); 528b8e80941Smrg msm_ring->u.reloc_bos[idx].flags = reloc->flags; 529b8e80941Smrg 530b8e80941Smrg /* this gets fixed up at submit->flush() time, since this state- 531b8e80941Smrg * object rb can be used with many different submits 532b8e80941Smrg */ 533b8e80941Smrg reloc_idx = idx; 534b8e80941Smrg 535b8e80941Smrg pipe = msm_ring->u.pipe; 536b8e80941Smrg } else { 537b8e80941Smrg struct msm_submit *msm_submit = 538b8e80941Smrg to_msm_submit(msm_ring->u.submit); 539b8e80941Smrg 540b8e80941Smrg reloc_idx = append_bo(msm_submit, reloc->bo, reloc->flags); 541b8e80941Smrg 542b8e80941Smrg pipe = msm_ring->u.submit->pipe; 543b8e80941Smrg } 544b8e80941Smrg 545b8e80941Smrg struct drm_msm_gem_submit_reloc *r; 546b8e80941Smrg unsigned idx = APPEND(msm_ring->cmd, relocs); 547b8e80941Smrg 548b8e80941Smrg r = &msm_ring->cmd->relocs[idx]; 549b8e80941Smrg 550b8e80941Smrg r->reloc_idx = reloc_idx; 551b8e80941Smrg r->reloc_offset = reloc->offset; 552b8e80941Smrg r->or = reloc->or; 553b8e80941Smrg r->shift = reloc->shift; 554b8e80941Smrg r->submit_offset = offset_bytes(ring->cur, ring->start) + 555b8e80941Smrg msm_ring->offset; 556b8e80941Smrg 557b8e80941Smrg ring->cur++; 558b8e80941Smrg 559b8e80941Smrg if (pipe->gpu_id >= 500) { 560b8e80941Smrg idx = APPEND(msm_ring->cmd, relocs); 561b8e80941Smrg r = &msm_ring->cmd->relocs[idx]; 562b8e80941Smrg 563b8e80941Smrg r->reloc_idx = reloc_idx; 564b8e80941Smrg r->reloc_offset = reloc->offset; 565b8e80941Smrg r->or = reloc->orhi; 566b8e80941Smrg r->shift = reloc->shift - 32; 567b8e80941Smrg r->submit_offset = offset_bytes(ring->cur, ring->start) + 568b8e80941Smrg msm_ring->offset; 569b8e80941Smrg 570b8e80941Smrg ring->cur++; 571b8e80941Smrg } 572b8e80941Smrg} 573b8e80941Smrg 574b8e80941Smrgstatic void 575b8e80941Smrgappend_stateobj_rings(struct msm_submit *submit, struct fd_ringbuffer *target) 576b8e80941Smrg{ 577b8e80941Smrg struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target); 578b8e80941Smrg 579b8e80941Smrg debug_assert(target->flags & _FD_RINGBUFFER_OBJECT); 580b8e80941Smrg 581b8e80941Smrg set_foreach(msm_target->u.ring_set, entry) { 582b8e80941Smrg struct fd_ringbuffer *ring = (void *)entry->key; 583b8e80941Smrg 584b8e80941Smrg append_ring(submit->ring_set, ring); 585b8e80941Smrg 586b8e80941Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 587b8e80941Smrg append_stateobj_rings(submit, ring); 588b8e80941Smrg } 589b8e80941Smrg } 590b8e80941Smrg} 591b8e80941Smrg 592b8e80941Smrgstatic uint32_t 593b8e80941Smrgmsm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 594b8e80941Smrg struct fd_ringbuffer *target, uint32_t cmd_idx) 595b8e80941Smrg{ 596b8e80941Smrg struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target); 597b8e80941Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 598b8e80941Smrg struct fd_bo *bo; 599b8e80941Smrg uint32_t size; 600b8e80941Smrg 601b8e80941Smrg if ((target->flags & FD_RINGBUFFER_GROWABLE) && 602b8e80941Smrg (cmd_idx < msm_target->u.nr_cmds)) { 603b8e80941Smrg bo = msm_target->u.cmds[cmd_idx]->ring_bo; 604b8e80941Smrg size = msm_target->u.cmds[cmd_idx]->size; 605b8e80941Smrg } else { 606b8e80941Smrg bo = msm_target->ring_bo; 607b8e80941Smrg size = offset_bytes(target->cur, target->start); 608b8e80941Smrg } 609b8e80941Smrg 610b8e80941Smrg msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){ 611b8e80941Smrg .bo = bo, 612b8e80941Smrg .flags = FD_RELOC_READ, 613b8e80941Smrg .offset = msm_target->offset, 614b8e80941Smrg }); 615b8e80941Smrg 616b8e80941Smrg if ((target->flags & _FD_RINGBUFFER_OBJECT) && 617b8e80941Smrg !(ring->flags & _FD_RINGBUFFER_OBJECT)) { 618b8e80941Smrg struct msm_submit *msm_submit = to_msm_submit(msm_ring->u.submit); 619b8e80941Smrg 620b8e80941Smrg append_stateobj_rings(msm_submit, target); 621b8e80941Smrg } 622b8e80941Smrg 623b8e80941Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 624b8e80941Smrg append_ring(msm_ring->u.ring_set, target); 625b8e80941Smrg } else { 626b8e80941Smrg struct msm_submit *msm_submit = to_msm_submit(msm_ring->u.submit); 627b8e80941Smrg append_ring(msm_submit->ring_set, target); 628b8e80941Smrg } 629b8e80941Smrg 630b8e80941Smrg return size; 631b8e80941Smrg} 632b8e80941Smrg 633b8e80941Smrgstatic uint32_t 634b8e80941Smrgmsm_ringbuffer_cmd_count(struct fd_ringbuffer *ring) 635b8e80941Smrg{ 636b8e80941Smrg if (ring->flags & FD_RINGBUFFER_GROWABLE) 637b8e80941Smrg return to_msm_ringbuffer(ring)->u.nr_cmds + 1; 638b8e80941Smrg return 1; 639b8e80941Smrg} 640b8e80941Smrg 641b8e80941Smrgstatic void 642b8e80941Smrgmsm_ringbuffer_destroy(struct fd_ringbuffer *ring) 643b8e80941Smrg{ 644b8e80941Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 645b8e80941Smrg 646b8e80941Smrg fd_bo_del(msm_ring->ring_bo); 647b8e80941Smrg if (msm_ring->cmd) 648b8e80941Smrg cmd_free(msm_ring->cmd); 649b8e80941Smrg 650b8e80941Smrg if (ring->flags & _FD_RINGBUFFER_OBJECT) { 651b8e80941Smrg for (unsigned i = 0; i < msm_ring->u.nr_reloc_bos; i++) { 652b8e80941Smrg fd_bo_del(msm_ring->u.reloc_bos[i].bo); 653b8e80941Smrg } 654b8e80941Smrg 655b8e80941Smrg _mesa_set_destroy(msm_ring->u.ring_set, unref_rings); 656b8e80941Smrg 657b8e80941Smrg free(msm_ring->u.reloc_bos); 658b8e80941Smrg free(msm_ring); 659b8e80941Smrg } else { 660b8e80941Smrg struct fd_submit *submit = msm_ring->u.submit; 661b8e80941Smrg 662b8e80941Smrg for (unsigned i = 0; i < msm_ring->u.nr_cmds; i++) { 663b8e80941Smrg cmd_free(msm_ring->u.cmds[i]); 664b8e80941Smrg } 665b8e80941Smrg 666b8e80941Smrg free(msm_ring->u.cmds); 667b8e80941Smrg slab_free_st(&to_msm_submit(submit)->ring_pool, msm_ring); 668b8e80941Smrg } 669b8e80941Smrg} 670b8e80941Smrg 671b8e80941Smrgstatic const struct fd_ringbuffer_funcs ring_funcs = { 672b8e80941Smrg .grow = msm_ringbuffer_grow, 673b8e80941Smrg .emit_reloc = msm_ringbuffer_emit_reloc, 674b8e80941Smrg .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, 675b8e80941Smrg .cmd_count = msm_ringbuffer_cmd_count, 676b8e80941Smrg .destroy = msm_ringbuffer_destroy, 677b8e80941Smrg}; 678b8e80941Smrg 679b8e80941Smrgstatic inline struct fd_ringbuffer * 680b8e80941Smrgmsm_ringbuffer_init(struct msm_ringbuffer *msm_ring, uint32_t size, 681b8e80941Smrg enum fd_ringbuffer_flags flags) 682b8e80941Smrg{ 683b8e80941Smrg struct fd_ringbuffer *ring = &msm_ring->base; 684b8e80941Smrg 685b8e80941Smrg debug_assert(msm_ring->ring_bo); 686b8e80941Smrg 687b8e80941Smrg uint8_t *base = fd_bo_map(msm_ring->ring_bo); 688b8e80941Smrg ring->start = (void *)(base + msm_ring->offset); 689b8e80941Smrg ring->end = &(ring->start[size/4]); 690b8e80941Smrg ring->cur = ring->start; 691b8e80941Smrg 692b8e80941Smrg ring->size = size; 693b8e80941Smrg ring->flags = flags; 694b8e80941Smrg 695b8e80941Smrg ring->funcs = &ring_funcs; 696b8e80941Smrg 697b8e80941Smrg msm_ring->u.cmds = NULL; 698b8e80941Smrg msm_ring->u.nr_cmds = msm_ring->u.max_cmds = 0; 699b8e80941Smrg 700b8e80941Smrg msm_ring->cmd = cmd_new(msm_ring->ring_bo); 701b8e80941Smrg 702b8e80941Smrg return ring; 703b8e80941Smrg} 704b8e80941Smrg 705b8e80941Smrgstruct fd_ringbuffer * 706b8e80941Smrgmsm_ringbuffer_new_object(struct fd_pipe *pipe, uint32_t size) 707b8e80941Smrg{ 708b8e80941Smrg struct msm_ringbuffer *msm_ring = malloc(sizeof(*msm_ring)); 709b8e80941Smrg 710b8e80941Smrg msm_ring->u.pipe = pipe; 711b8e80941Smrg msm_ring->offset = 0; 712b8e80941Smrg msm_ring->ring_bo = fd_bo_new_ring(pipe->dev, size, 0); 713b8e80941Smrg msm_ring->base.refcnt = 1; 714b8e80941Smrg 715b8e80941Smrg msm_ring->u.reloc_bos = NULL; 716b8e80941Smrg msm_ring->u.nr_reloc_bos = msm_ring->u.max_reloc_bos = 0; 717b8e80941Smrg 718b8e80941Smrg msm_ring->u.ring_set = _mesa_set_create(NULL, 719b8e80941Smrg _mesa_hash_pointer, _mesa_key_pointer_equal); 720b8e80941Smrg 721b8e80941Smrg return msm_ringbuffer_init(msm_ring, size, _FD_RINGBUFFER_OBJECT); 722b8e80941Smrg} 723