msm_ringbuffer.c revision d8807b2f
1e88f27b3Smrg/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2e88f27b3Smrg 3e88f27b3Smrg/* 4e88f27b3Smrg * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org> 5e88f27b3Smrg * 6e88f27b3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7e88f27b3Smrg * copy of this software and associated documentation files (the "Software"), 8e88f27b3Smrg * to deal in the Software without restriction, including without limitation 9e88f27b3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10e88f27b3Smrg * and/or sell copies of the Software, and to permit persons to whom the 11e88f27b3Smrg * Software is furnished to do so, subject to the following conditions: 12e88f27b3Smrg * 13e88f27b3Smrg * The above copyright notice and this permission notice (including the next 14e88f27b3Smrg * paragraph) shall be included in all copies or substantial portions of the 15e88f27b3Smrg * Software. 16e88f27b3Smrg * 17e88f27b3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18e88f27b3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19e88f27b3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20e88f27b3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21e88f27b3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22e88f27b3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23e88f27b3Smrg * SOFTWARE. 24e88f27b3Smrg * 25e88f27b3Smrg * Authors: 26e88f27b3Smrg * Rob Clark <robclark@freedesktop.org> 27e88f27b3Smrg */ 28e88f27b3Smrg 29baaff307Smrg#ifdef HAVE_CONFIG_H 30baaff307Smrg# include <config.h> 31baaff307Smrg#endif 32baaff307Smrg 33e88f27b3Smrg#include <assert.h> 343f012e29Smrg#include <inttypes.h> 35e88f27b3Smrg 36e88f27b3Smrg#include "freedreno_ringbuffer.h" 37e88f27b3Smrg#include "msm_priv.h" 38e88f27b3Smrg 393f012e29Smrg/* represents a single cmd buffer in the submit ioctl. Each cmd buffer has 403f012e29Smrg * a backing bo, and a reloc table. 413f012e29Smrg */ 423f012e29Smrgstruct msm_cmd { 433f012e29Smrg struct list_head list; 443f012e29Smrg 453f012e29Smrg struct fd_ringbuffer *ring; 46e88f27b3Smrg struct fd_bo *ring_bo; 47e88f27b3Smrg 483f012e29Smrg /* reloc's table: */ 493f012e29Smrg struct drm_msm_gem_submit_reloc *relocs; 503f012e29Smrg uint32_t nr_relocs, max_relocs; 513f012e29Smrg 523f012e29Smrg uint32_t size; 533f012e29Smrg}; 543f012e29Smrg 553f012e29Smrgstruct msm_ringbuffer { 563f012e29Smrg struct fd_ringbuffer base; 57e88f27b3Smrg 583f012e29Smrg /* submit ioctl related tables: 593f012e29Smrg * Note that bos and cmds are tracked by the parent ringbuffer, since 603f012e29Smrg * that is global to the submit ioctl call. The reloc's table is tracked 613f012e29Smrg * per cmd-buffer. 623f012e29Smrg */ 633f012e29Smrg struct { 643f012e29Smrg /* bo's table: */ 653f012e29Smrg struct drm_msm_gem_submit_bo *bos; 663f012e29Smrg uint32_t nr_bos, max_bos; 673f012e29Smrg 683f012e29Smrg /* cmd's table: */ 693f012e29Smrg struct drm_msm_gem_submit_cmd *cmds; 703f012e29Smrg uint32_t nr_cmds, max_cmds; 713f012e29Smrg } submit; 723f012e29Smrg 733f012e29Smrg /* should have matching entries in submit.bos: */ 743f012e29Smrg /* Note, only in parent ringbuffer */ 753f012e29Smrg struct fd_bo **bos; 76e88f27b3Smrg uint32_t nr_bos, max_bos; 77e88f27b3Smrg 783f012e29Smrg /* should have matching entries in submit.cmds: */ 793f012e29Smrg struct msm_cmd **cmds; 80e88f27b3Smrg uint32_t nr_cmds, max_cmds; 81e88f27b3Smrg 823f012e29Smrg /* List of physical cmdstream buffers (msm_cmd) assocated with this 833f012e29Smrg * logical fd_ringbuffer. 843f012e29Smrg * 853f012e29Smrg * Note that this is different from msm_ringbuffer::cmds (which 863f012e29Smrg * shadows msm_ringbuffer::submit::cmds for tracking submit ioctl 873f012e29Smrg * related stuff, and *only* is tracked in the parent ringbuffer. 883f012e29Smrg * And only has "completed" cmd buffers (ie. we already know the 893f012e29Smrg * size) added via get_cmd(). 903f012e29Smrg */ 913f012e29Smrg struct list_head cmd_list; 923f012e29Smrg 933f012e29Smrg int is_growable; 943f012e29Smrg unsigned cmd_count; 953f012e29Smrg 963f012e29Smrg unsigned seqno; 973f012e29Smrg 983f012e29Smrg /* maps fd_bo to idx: */ 993f012e29Smrg void *bo_table; 100e88f27b3Smrg}; 101e88f27b3Smrg 1023f012e29Smrgstatic inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x) 1033f012e29Smrg{ 1043f012e29Smrg return (struct msm_ringbuffer *)x; 1053f012e29Smrg} 1063f012e29Smrg 1073f012e29Smrg#define INIT_SIZE 0x1000 1083f012e29Smrg 1093f012e29Smrgstatic pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; 1103f012e29Smrgdrm_private extern pthread_mutex_t table_lock; 1113f012e29Smrg 1123f012e29Smrgstatic void ring_bo_del(struct fd_device *dev, struct fd_bo *bo) 1133f012e29Smrg{ 1143f012e29Smrg int ret; 1153f012e29Smrg 1163f012e29Smrg pthread_mutex_lock(&table_lock); 1173f012e29Smrg ret = fd_bo_cache_free(&to_msm_device(dev)->ring_cache, bo); 1183f012e29Smrg pthread_mutex_unlock(&table_lock); 1193f012e29Smrg 1203f012e29Smrg if (ret == 0) 1213f012e29Smrg return; 1223f012e29Smrg 1233f012e29Smrg fd_bo_del(bo); 1243f012e29Smrg} 1253f012e29Smrg 1263f012e29Smrgstatic struct fd_bo * ring_bo_new(struct fd_device *dev, uint32_t size) 1273f012e29Smrg{ 1283f012e29Smrg struct fd_bo *bo; 1293f012e29Smrg 1303f012e29Smrg bo = fd_bo_cache_alloc(&to_msm_device(dev)->ring_cache, &size, 0); 1313f012e29Smrg if (bo) 1323f012e29Smrg return bo; 1333f012e29Smrg 1343f012e29Smrg bo = fd_bo_new(dev, size, 0); 1353f012e29Smrg if (!bo) 1363f012e29Smrg return NULL; 1373f012e29Smrg 1383f012e29Smrg /* keep ringbuffer bo's out of the normal bo cache: */ 1393f012e29Smrg bo->bo_reuse = FALSE; 1403f012e29Smrg 1413f012e29Smrg return bo; 1423f012e29Smrg} 1433f012e29Smrg 1443f012e29Smrgstatic void ring_cmd_del(struct msm_cmd *cmd) 1453f012e29Smrg{ 1463f012e29Smrg if (cmd->ring_bo) 1473f012e29Smrg ring_bo_del(cmd->ring->pipe->dev, cmd->ring_bo); 1483f012e29Smrg list_del(&cmd->list); 1493f012e29Smrg to_msm_ringbuffer(cmd->ring)->cmd_count--; 1503f012e29Smrg free(cmd->relocs); 1513f012e29Smrg free(cmd); 1523f012e29Smrg} 1533f012e29Smrg 1543f012e29Smrgstatic struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size) 1553f012e29Smrg{ 1563f012e29Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 1573f012e29Smrg struct msm_cmd *cmd = calloc(1, sizeof(*cmd)); 1583f012e29Smrg 1593f012e29Smrg if (!cmd) 1603f012e29Smrg return NULL; 1613f012e29Smrg 1623f012e29Smrg cmd->ring = ring; 1633f012e29Smrg cmd->ring_bo = ring_bo_new(ring->pipe->dev, size); 1643f012e29Smrg if (!cmd->ring_bo) 1653f012e29Smrg goto fail; 1663f012e29Smrg 1673f012e29Smrg list_addtail(&cmd->list, &msm_ring->cmd_list); 1683f012e29Smrg msm_ring->cmd_count++; 1693f012e29Smrg 1703f012e29Smrg return cmd; 1713f012e29Smrg 1723f012e29Smrgfail: 1733f012e29Smrg ring_cmd_del(cmd); 1743f012e29Smrg return NULL; 1753f012e29Smrg} 1763f012e29Smrg 177e88f27b3Smrgstatic void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz) 178e88f27b3Smrg{ 179e88f27b3Smrg if ((nr + 1) > *max) { 180e88f27b3Smrg if ((*max * 2) < (nr + 1)) 181e88f27b3Smrg *max = nr + 5; 182e88f27b3Smrg else 183e88f27b3Smrg *max = *max * 2; 184e88f27b3Smrg ptr = realloc(ptr, *max * sz); 185e88f27b3Smrg } 186e88f27b3Smrg return ptr; 187e88f27b3Smrg} 188e88f27b3Smrg 189e88f27b3Smrg#define APPEND(x, name) ({ \ 190e88f27b3Smrg (x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \ 191e88f27b3Smrg (x)->nr_ ## name ++; \ 192e88f27b3Smrg}) 193e88f27b3Smrg 1943f012e29Smrgstatic struct msm_cmd *current_cmd(struct fd_ringbuffer *ring) 195e88f27b3Smrg{ 1963f012e29Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 1973f012e29Smrg assert(!LIST_IS_EMPTY(&msm_ring->cmd_list)); 1983f012e29Smrg return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list); 1993f012e29Smrg} 2003f012e29Smrg 2013f012e29Smrgstatic uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo) 2023f012e29Smrg{ 2033f012e29Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 2043f012e29Smrg uint32_t idx; 2053f012e29Smrg 2063f012e29Smrg idx = APPEND(&msm_ring->submit, bos); 2073f012e29Smrg idx = APPEND(msm_ring, bos); 2083f012e29Smrg 2093f012e29Smrg msm_ring->submit.bos[idx].flags = 0; 2103f012e29Smrg msm_ring->submit.bos[idx].handle = bo->handle; 2113f012e29Smrg msm_ring->submit.bos[idx].presumed = to_msm_bo(bo)->presumed; 2123f012e29Smrg 2133f012e29Smrg msm_ring->bos[idx] = fd_bo_ref(bo); 2143f012e29Smrg 2153f012e29Smrg return idx; 216e88f27b3Smrg} 217e88f27b3Smrg 218e88f27b3Smrg/* add (if needed) bo, return idx: */ 219e88f27b3Smrgstatic uint32_t bo2idx(struct fd_ringbuffer *ring, struct fd_bo *bo, uint32_t flags) 220e88f27b3Smrg{ 221e88f27b3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 222e88f27b3Smrg struct msm_bo *msm_bo = to_msm_bo(bo); 223e88f27b3Smrg uint32_t idx; 2243f012e29Smrg pthread_mutex_lock(&idx_lock); 2253f012e29Smrg if (msm_bo->current_ring_seqno == msm_ring->seqno) { 2263f012e29Smrg idx = msm_bo->idx; 227e88f27b3Smrg } else { 2283f012e29Smrg void *val; 2293f012e29Smrg 2303f012e29Smrg if (!msm_ring->bo_table) 2313f012e29Smrg msm_ring->bo_table = drmHashCreate(); 2323f012e29Smrg 2333f012e29Smrg if (!drmHashLookup(msm_ring->bo_table, bo->handle, &val)) { 2343f012e29Smrg /* found */ 2353f012e29Smrg idx = (uint32_t)(uintptr_t)val; 2363f012e29Smrg } else { 2373f012e29Smrg idx = append_bo(ring, bo); 2383f012e29Smrg val = (void *)(uintptr_t)idx; 2393f012e29Smrg drmHashInsert(msm_ring->bo_table, bo->handle, val); 2403f012e29Smrg } 2413f012e29Smrg msm_bo->current_ring_seqno = msm_ring->seqno; 2423f012e29Smrg msm_bo->idx = idx; 243e88f27b3Smrg } 2443f012e29Smrg pthread_mutex_unlock(&idx_lock); 245e88f27b3Smrg if (flags & FD_RELOC_READ) 2463f012e29Smrg msm_ring->submit.bos[idx].flags |= MSM_SUBMIT_BO_READ; 247e88f27b3Smrg if (flags & FD_RELOC_WRITE) 2483f012e29Smrg msm_ring->submit.bos[idx].flags |= MSM_SUBMIT_BO_WRITE; 249e88f27b3Smrg return idx; 250e88f27b3Smrg} 251e88f27b3Smrg 252e88f27b3Smrgstatic int check_cmd_bo(struct fd_ringbuffer *ring, 253e88f27b3Smrg struct drm_msm_gem_submit_cmd *cmd, struct fd_bo *bo) 254e88f27b3Smrg{ 255e88f27b3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 2563f012e29Smrg return msm_ring->submit.bos[cmd->submit_idx].handle == bo->handle; 257e88f27b3Smrg} 258e88f27b3Smrg 2593f012e29Smrg/* Ensure that submit has corresponding entry in cmds table for the 2603f012e29Smrg * target cmdstream buffer: 2613f012e29Smrg */ 2623f012e29Smrgstatic void get_cmd(struct fd_ringbuffer *ring, struct msm_cmd *target_cmd, 263e88f27b3Smrg uint32_t submit_offset, uint32_t size, uint32_t type) 264e88f27b3Smrg{ 265e88f27b3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 2663f012e29Smrg struct drm_msm_gem_submit_cmd *cmd; 267e88f27b3Smrg uint32_t i; 268e88f27b3Smrg 269e88f27b3Smrg /* figure out if we already have a cmd buf: */ 2703f012e29Smrg for (i = 0; i < msm_ring->submit.nr_cmds; i++) { 2713f012e29Smrg cmd = &msm_ring->submit.cmds[i]; 272e88f27b3Smrg if ((cmd->submit_offset == submit_offset) && 273e88f27b3Smrg (cmd->size == size) && 274e88f27b3Smrg (cmd->type == type) && 2753f012e29Smrg check_cmd_bo(ring, cmd, target_cmd->ring_bo)) 2763f012e29Smrg return; 277e88f27b3Smrg } 278e88f27b3Smrg 279e88f27b3Smrg /* create cmd buf if not: */ 2803f012e29Smrg i = APPEND(&msm_ring->submit, cmds); 2813f012e29Smrg APPEND(msm_ring, cmds); 2823f012e29Smrg msm_ring->cmds[i] = target_cmd; 2833f012e29Smrg cmd = &msm_ring->submit.cmds[i]; 2843f012e29Smrg cmd->type = type; 2853f012e29Smrg cmd->submit_idx = bo2idx(ring, target_cmd->ring_bo, FD_RELOC_READ); 2863f012e29Smrg cmd->submit_offset = submit_offset; 2873f012e29Smrg cmd->size = size; 2883f012e29Smrg cmd->pad = 0; 2893f012e29Smrg 2903f012e29Smrg target_cmd->size = size; 291e88f27b3Smrg} 292e88f27b3Smrg 293e88f27b3Smrgstatic void * msm_ringbuffer_hostptr(struct fd_ringbuffer *ring) 294e88f27b3Smrg{ 2953f012e29Smrg return fd_bo_map(current_cmd(ring)->ring_bo); 296e88f27b3Smrg} 297e88f27b3Smrg 2983f012e29Smrgstatic uint32_t find_next_reloc_idx(struct msm_cmd *msm_cmd, 299e88f27b3Smrg uint32_t start, uint32_t offset) 300e88f27b3Smrg{ 301e88f27b3Smrg uint32_t i; 302e88f27b3Smrg 303e88f27b3Smrg /* a binary search would be more clever.. */ 3043f012e29Smrg for (i = start; i < msm_cmd->nr_relocs; i++) { 3053f012e29Smrg struct drm_msm_gem_submit_reloc *reloc = &msm_cmd->relocs[i]; 306e88f27b3Smrg if (reloc->submit_offset >= offset) 307e88f27b3Smrg return i; 308e88f27b3Smrg } 309e88f27b3Smrg 310e88f27b3Smrg return i; 311e88f27b3Smrg} 312e88f27b3Smrg 3133f012e29Smrgstatic void delete_cmds(struct msm_ringbuffer *msm_ring) 3143f012e29Smrg{ 3153f012e29Smrg struct msm_cmd *cmd, *tmp; 3163f012e29Smrg 3173f012e29Smrg LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &msm_ring->cmd_list, list) { 3183f012e29Smrg ring_cmd_del(cmd); 3193f012e29Smrg } 3203f012e29Smrg} 3213f012e29Smrg 322857b0bc6Smrgstatic void flush_reset(struct fd_ringbuffer *ring) 323857b0bc6Smrg{ 324857b0bc6Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 325857b0bc6Smrg unsigned i; 326857b0bc6Smrg 3273f012e29Smrg for (i = 0; i < msm_ring->nr_bos; i++) { 3283f012e29Smrg struct msm_bo *msm_bo = to_msm_bo(msm_ring->bos[i]); 3293f012e29Smrg msm_bo->current_ring_seqno = 0; 3303f012e29Smrg fd_bo_del(&msm_bo->base); 3313f012e29Smrg } 3323f012e29Smrg 333857b0bc6Smrg /* for each of the cmd buffers, clear their reloc's: */ 3343f012e29Smrg for (i = 0; i < msm_ring->submit.nr_cmds; i++) { 3353f012e29Smrg struct msm_cmd *target_cmd = msm_ring->cmds[i]; 3363f012e29Smrg target_cmd->nr_relocs = 0; 337857b0bc6Smrg } 338857b0bc6Smrg 3393f012e29Smrg msm_ring->submit.nr_cmds = 0; 3403f012e29Smrg msm_ring->submit.nr_bos = 0; 341857b0bc6Smrg msm_ring->nr_cmds = 0; 342857b0bc6Smrg msm_ring->nr_bos = 0; 3433f012e29Smrg 3443f012e29Smrg if (msm_ring->bo_table) { 3453f012e29Smrg drmHashDestroy(msm_ring->bo_table); 3463f012e29Smrg msm_ring->bo_table = NULL; 3473f012e29Smrg } 3483f012e29Smrg 3493f012e29Smrg if (msm_ring->is_growable) { 3503f012e29Smrg delete_cmds(msm_ring); 3513f012e29Smrg } else { 3523f012e29Smrg /* in old mode, just reset the # of relocs: */ 3533f012e29Smrg current_cmd(ring)->nr_relocs = 0; 3543f012e29Smrg } 3553f012e29Smrg} 3563f012e29Smrg 3573f012e29Smrgstatic void finalize_current_cmd(struct fd_ringbuffer *ring, uint32_t *last_start) 3583f012e29Smrg{ 3593f012e29Smrg uint32_t submit_offset, size, type; 3603f012e29Smrg struct fd_ringbuffer *parent; 3613f012e29Smrg 3623f012e29Smrg if (ring->parent) { 3633f012e29Smrg parent = ring->parent; 3643f012e29Smrg type = MSM_SUBMIT_CMD_IB_TARGET_BUF; 3653f012e29Smrg } else { 3663f012e29Smrg parent = ring; 3673f012e29Smrg type = MSM_SUBMIT_CMD_BUF; 3683f012e29Smrg } 3693f012e29Smrg 3703f012e29Smrg submit_offset = offset_bytes(last_start, ring->start); 3713f012e29Smrg size = offset_bytes(ring->cur, last_start); 3723f012e29Smrg 3733f012e29Smrg get_cmd(parent, current_cmd(ring), submit_offset, size, type); 3743f012e29Smrg} 3753f012e29Smrg 3763f012e29Smrgstatic void dump_submit(struct msm_ringbuffer *msm_ring) 3773f012e29Smrg{ 3783f012e29Smrg uint32_t i, j; 3793f012e29Smrg 3803f012e29Smrg for (i = 0; i < msm_ring->submit.nr_bos; i++) { 3813f012e29Smrg struct drm_msm_gem_submit_bo *bo = &msm_ring->submit.bos[i]; 3823f012e29Smrg ERROR_MSG(" bos[%d]: handle=%u, flags=%x", i, bo->handle, bo->flags); 3833f012e29Smrg } 3843f012e29Smrg for (i = 0; i < msm_ring->submit.nr_cmds; i++) { 3853f012e29Smrg struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i]; 3863f012e29Smrg struct drm_msm_gem_submit_reloc *relocs = U642VOID(cmd->relocs); 3873f012e29Smrg ERROR_MSG(" cmd[%d]: type=%u, submit_idx=%u, submit_offset=%u, size=%u", 3883f012e29Smrg i, cmd->type, cmd->submit_idx, cmd->submit_offset, cmd->size); 3893f012e29Smrg for (j = 0; j < cmd->nr_relocs; j++) { 3903f012e29Smrg struct drm_msm_gem_submit_reloc *r = &relocs[j]; 3913f012e29Smrg ERROR_MSG(" reloc[%d]: submit_offset=%u, or=%08x, shift=%d, reloc_idx=%u" 3923f012e29Smrg ", reloc_offset=%"PRIu64, j, r->submit_offset, r->or, r->shift, 3933f012e29Smrg r->reloc_idx, r->reloc_offset); 3943f012e29Smrg } 3953f012e29Smrg } 396857b0bc6Smrg} 397857b0bc6Smrg 398037b3c26Smrgstatic int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start, 399037b3c26Smrg int in_fence_fd, int *out_fence_fd) 400e88f27b3Smrg{ 401e88f27b3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 402e88f27b3Smrg struct drm_msm_gem_submit req = { 403037b3c26Smrg .flags = to_msm_pipe(ring->pipe)->pipe, 404e88f27b3Smrg }; 4053f012e29Smrg uint32_t i; 4063f012e29Smrg int ret; 407e88f27b3Smrg 408037b3c26Smrg if (in_fence_fd != -1) { 409037b3c26Smrg req.flags |= MSM_SUBMIT_FENCE_FD_IN | MSM_SUBMIT_NO_IMPLICIT; 410037b3c26Smrg req.fence_fd = in_fence_fd; 411037b3c26Smrg } 412037b3c26Smrg 413037b3c26Smrg if (out_fence_fd) { 414037b3c26Smrg req.flags |= MSM_SUBMIT_FENCE_FD_OUT; 415037b3c26Smrg } 416037b3c26Smrg 4173f012e29Smrg finalize_current_cmd(ring, last_start); 418e88f27b3Smrg 419e88f27b3Smrg /* needs to be after get_cmd() as that could create bos/cmds table: */ 4203f012e29Smrg req.bos = VOID2U64(msm_ring->submit.bos), 4213f012e29Smrg req.nr_bos = msm_ring->submit.nr_bos; 4223f012e29Smrg req.cmds = VOID2U64(msm_ring->submit.cmds), 4233f012e29Smrg req.nr_cmds = msm_ring->submit.nr_cmds; 424e88f27b3Smrg 425e88f27b3Smrg /* for each of the cmd's fix up their reloc's: */ 4263f012e29Smrg for (i = 0; i < msm_ring->submit.nr_cmds; i++) { 4273f012e29Smrg struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i]; 4283f012e29Smrg struct msm_cmd *msm_cmd = msm_ring->cmds[i]; 4293f012e29Smrg uint32_t a = find_next_reloc_idx(msm_cmd, 0, cmd->submit_offset); 4303f012e29Smrg uint32_t b = find_next_reloc_idx(msm_cmd, a, cmd->submit_offset + cmd->size); 4313f012e29Smrg cmd->relocs = VOID2U64(&msm_cmd->relocs[a]); 432e88f27b3Smrg cmd->nr_relocs = (b > a) ? b - a : 0; 433e88f27b3Smrg } 434e88f27b3Smrg 4353f012e29Smrg DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos); 436e88f27b3Smrg 437e88f27b3Smrg ret = drmCommandWriteRead(ring->pipe->dev->fd, DRM_MSM_GEM_SUBMIT, 438e88f27b3Smrg &req, sizeof(req)); 439857b0bc6Smrg if (ret) { 440e88f27b3Smrg ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); 4413f012e29Smrg dump_submit(msm_ring); 4423f012e29Smrg } else if (!ret) { 443857b0bc6Smrg /* update timestamp on all rings associated with submit: */ 4443f012e29Smrg for (i = 0; i < msm_ring->submit.nr_cmds; i++) { 4453f012e29Smrg struct msm_cmd *msm_cmd = msm_ring->cmds[i]; 4463f012e29Smrg msm_cmd->ring->last_timestamp = req.fence; 447857b0bc6Smrg } 448037b3c26Smrg 449037b3c26Smrg if (out_fence_fd) { 450037b3c26Smrg *out_fence_fd = req.fence_fd; 451037b3c26Smrg } 452857b0bc6Smrg } 453e88f27b3Smrg 454857b0bc6Smrg flush_reset(ring); 455e88f27b3Smrg 456e88f27b3Smrg return ret; 457e88f27b3Smrg} 458e88f27b3Smrg 4593f012e29Smrgstatic void msm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size) 4603f012e29Smrg{ 4613f012e29Smrg assert(to_msm_ringbuffer(ring)->is_growable); 4623f012e29Smrg finalize_current_cmd(ring, ring->last_start); 4633f012e29Smrg ring_cmd_new(ring, size); 4643f012e29Smrg} 4653f012e29Smrg 466857b0bc6Smrgstatic void msm_ringbuffer_reset(struct fd_ringbuffer *ring) 467857b0bc6Smrg{ 468857b0bc6Smrg flush_reset(ring); 469857b0bc6Smrg} 470857b0bc6Smrg 471e88f27b3Smrgstatic void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, 472e88f27b3Smrg const struct fd_reloc *r) 473e88f27b3Smrg{ 474e88f27b3Smrg struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring; 475e88f27b3Smrg struct msm_bo *msm_bo = to_msm_bo(r->bo); 476e88f27b3Smrg struct drm_msm_gem_submit_reloc *reloc; 4773f012e29Smrg struct msm_cmd *cmd = current_cmd(ring); 4783f012e29Smrg uint32_t idx = APPEND(cmd, relocs); 479e88f27b3Smrg uint32_t addr; 480e88f27b3Smrg 4813f012e29Smrg reloc = &cmd->relocs[idx]; 482e88f27b3Smrg 483e88f27b3Smrg reloc->reloc_idx = bo2idx(parent, r->bo, r->flags); 484e88f27b3Smrg reloc->reloc_offset = r->offset; 485e88f27b3Smrg reloc->or = r->or; 486e88f27b3Smrg reloc->shift = r->shift; 487e88f27b3Smrg reloc->submit_offset = offset_bytes(ring->cur, ring->start); 488e88f27b3Smrg 489e88f27b3Smrg addr = msm_bo->presumed; 490037b3c26Smrg if (reloc->shift < 0) 491037b3c26Smrg addr >>= -reloc->shift; 492e88f27b3Smrg else 493037b3c26Smrg addr <<= reloc->shift; 494e88f27b3Smrg (*ring->cur++) = addr | r->or; 495037b3c26Smrg 496037b3c26Smrg if (ring->pipe->gpu_id >= 500) { 497037b3c26Smrg struct drm_msm_gem_submit_reloc *reloc_hi; 498037b3c26Smrg 499d8807b2fSmrg /* NOTE: grab reloc_idx *before* APPEND() since that could 500d8807b2fSmrg * realloc() meaning that 'reloc' ptr is no longer valid: 501d8807b2fSmrg */ 502d8807b2fSmrg uint32_t reloc_idx = reloc->reloc_idx; 503d8807b2fSmrg 504037b3c26Smrg idx = APPEND(cmd, relocs); 505037b3c26Smrg 506037b3c26Smrg reloc_hi = &cmd->relocs[idx]; 507037b3c26Smrg 508d8807b2fSmrg reloc_hi->reloc_idx = reloc_idx; 509037b3c26Smrg reloc_hi->reloc_offset = r->offset; 510037b3c26Smrg reloc_hi->or = r->orhi; 511037b3c26Smrg reloc_hi->shift = r->shift - 32; 512037b3c26Smrg reloc_hi->submit_offset = offset_bytes(ring->cur, ring->start); 513037b3c26Smrg 514037b3c26Smrg addr = msm_bo->presumed >> 32; 515037b3c26Smrg if (reloc_hi->shift < 0) 516037b3c26Smrg addr >>= -reloc_hi->shift; 517037b3c26Smrg else 518037b3c26Smrg addr <<= reloc_hi->shift; 519037b3c26Smrg (*ring->cur++) = addr | r->orhi; 520037b3c26Smrg } 521e88f27b3Smrg} 522e88f27b3Smrg 5233f012e29Smrgstatic uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 5243f012e29Smrg struct fd_ringbuffer *target, uint32_t cmd_idx, 5253f012e29Smrg uint32_t submit_offset, uint32_t size) 526e88f27b3Smrg{ 5273f012e29Smrg struct msm_cmd *cmd = NULL; 5283f012e29Smrg uint32_t idx = 0; 5293f012e29Smrg 5303f012e29Smrg LIST_FOR_EACH_ENTRY(cmd, &to_msm_ringbuffer(target)->cmd_list, list) { 5313f012e29Smrg if (idx == cmd_idx) 5323f012e29Smrg break; 5333f012e29Smrg idx++; 5343f012e29Smrg } 535e88f27b3Smrg 5363f012e29Smrg assert(cmd && (idx == cmd_idx)); 537e88f27b3Smrg 5383f012e29Smrg if (idx < (to_msm_ringbuffer(target)->cmd_count - 1)) { 5393f012e29Smrg /* All but the last cmd buffer is fully "baked" (ie. already has 5403f012e29Smrg * done get_cmd() to add it to the cmds table). But in this case, 5413f012e29Smrg * the size we get is invalid (since it is calculated from the 5423f012e29Smrg * last cmd buffer): 5433f012e29Smrg */ 5443f012e29Smrg size = cmd->size; 5453f012e29Smrg } else { 5463f012e29Smrg get_cmd(ring, cmd, submit_offset, size, MSM_SUBMIT_CMD_IB_TARGET_BUF); 5473f012e29Smrg } 548e88f27b3Smrg 549e88f27b3Smrg msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){ 5503f012e29Smrg .bo = cmd->ring_bo, 551e88f27b3Smrg .flags = FD_RELOC_READ, 552e88f27b3Smrg .offset = submit_offset, 553e88f27b3Smrg }); 5543f012e29Smrg 5553f012e29Smrg return size; 5563f012e29Smrg} 5573f012e29Smrg 5583f012e29Smrgstatic uint32_t msm_ringbuffer_cmd_count(struct fd_ringbuffer *ring) 5593f012e29Smrg{ 5603f012e29Smrg return to_msm_ringbuffer(ring)->cmd_count; 561e88f27b3Smrg} 562e88f27b3Smrg 563e88f27b3Smrgstatic void msm_ringbuffer_destroy(struct fd_ringbuffer *ring) 564e88f27b3Smrg{ 565e88f27b3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 5663f012e29Smrg 5673f012e29Smrg flush_reset(ring); 5683f012e29Smrg delete_cmds(msm_ring); 5693f012e29Smrg 5703f012e29Smrg free(msm_ring->submit.cmds); 5713f012e29Smrg free(msm_ring->submit.bos); 5723f012e29Smrg free(msm_ring->bos); 5733f012e29Smrg free(msm_ring->cmds); 574e88f27b3Smrg free(msm_ring); 575e88f27b3Smrg} 576e88f27b3Smrg 5773f012e29Smrgstatic const struct fd_ringbuffer_funcs funcs = { 578e88f27b3Smrg .hostptr = msm_ringbuffer_hostptr, 579e88f27b3Smrg .flush = msm_ringbuffer_flush, 5803f012e29Smrg .grow = msm_ringbuffer_grow, 581857b0bc6Smrg .reset = msm_ringbuffer_reset, 582e88f27b3Smrg .emit_reloc = msm_ringbuffer_emit_reloc, 583e88f27b3Smrg .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, 5843f012e29Smrg .cmd_count = msm_ringbuffer_cmd_count, 585e88f27b3Smrg .destroy = msm_ringbuffer_destroy, 586e88f27b3Smrg}; 587e88f27b3Smrg 588e6188e58Smrgdrm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe, 589e88f27b3Smrg uint32_t size) 590e88f27b3Smrg{ 591e88f27b3Smrg struct msm_ringbuffer *msm_ring; 592d8807b2fSmrg struct fd_ringbuffer *ring; 593e88f27b3Smrg 594e88f27b3Smrg msm_ring = calloc(1, sizeof(*msm_ring)); 595e88f27b3Smrg if (!msm_ring) { 596e88f27b3Smrg ERROR_MSG("allocation failed"); 597d8807b2fSmrg return NULL; 598e88f27b3Smrg } 599e88f27b3Smrg 6003f012e29Smrg if (size == 0) { 6013f012e29Smrg assert(pipe->dev->version >= FD_VERSION_UNLIMITED_CMDS); 6023f012e29Smrg size = INIT_SIZE; 6033f012e29Smrg msm_ring->is_growable = TRUE; 6043f012e29Smrg } 6053f012e29Smrg 6063f012e29Smrg list_inithead(&msm_ring->cmd_list); 6073f012e29Smrg msm_ring->seqno = ++to_msm_device(pipe->dev)->ring_cnt; 6083f012e29Smrg 609e88f27b3Smrg ring = &msm_ring->base; 610e88f27b3Smrg ring->funcs = &funcs; 6113f012e29Smrg ring->size = size; 6123f012e29Smrg ring->pipe = pipe; /* needed in ring_cmd_new() */ 613e88f27b3Smrg 6143f012e29Smrg ring_cmd_new(ring, size); 615e88f27b3Smrg 616e88f27b3Smrg return ring; 617e88f27b3Smrg} 618