msm_ringbuffer.c revision 3f012e29
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 398e88f27b3Smrgstatic int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start) 399e88f27b3Smrg{ 400e88f27b3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 401e88f27b3Smrg struct drm_msm_gem_submit req = { 402e88f27b3Smrg .pipe = to_msm_pipe(ring->pipe)->pipe, 403e88f27b3Smrg }; 4043f012e29Smrg uint32_t i; 4053f012e29Smrg int ret; 406e88f27b3Smrg 4073f012e29Smrg finalize_current_cmd(ring, last_start); 408e88f27b3Smrg 409e88f27b3Smrg /* needs to be after get_cmd() as that could create bos/cmds table: */ 4103f012e29Smrg req.bos = VOID2U64(msm_ring->submit.bos), 4113f012e29Smrg req.nr_bos = msm_ring->submit.nr_bos; 4123f012e29Smrg req.cmds = VOID2U64(msm_ring->submit.cmds), 4133f012e29Smrg req.nr_cmds = msm_ring->submit.nr_cmds; 414e88f27b3Smrg 415e88f27b3Smrg /* for each of the cmd's fix up their reloc's: */ 4163f012e29Smrg for (i = 0; i < msm_ring->submit.nr_cmds; i++) { 4173f012e29Smrg struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i]; 4183f012e29Smrg struct msm_cmd *msm_cmd = msm_ring->cmds[i]; 4193f012e29Smrg uint32_t a = find_next_reloc_idx(msm_cmd, 0, cmd->submit_offset); 4203f012e29Smrg uint32_t b = find_next_reloc_idx(msm_cmd, a, cmd->submit_offset + cmd->size); 4213f012e29Smrg cmd->relocs = VOID2U64(&msm_cmd->relocs[a]); 422e88f27b3Smrg cmd->nr_relocs = (b > a) ? b - a : 0; 423e88f27b3Smrg } 424e88f27b3Smrg 4253f012e29Smrg DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos); 426e88f27b3Smrg 427e88f27b3Smrg ret = drmCommandWriteRead(ring->pipe->dev->fd, DRM_MSM_GEM_SUBMIT, 428e88f27b3Smrg &req, sizeof(req)); 429857b0bc6Smrg if (ret) { 430e88f27b3Smrg ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); 4313f012e29Smrg dump_submit(msm_ring); 4323f012e29Smrg } else if (!ret) { 433857b0bc6Smrg /* update timestamp on all rings associated with submit: */ 4343f012e29Smrg for (i = 0; i < msm_ring->submit.nr_cmds; i++) { 4353f012e29Smrg struct msm_cmd *msm_cmd = msm_ring->cmds[i]; 4363f012e29Smrg msm_cmd->ring->last_timestamp = req.fence; 437857b0bc6Smrg } 438857b0bc6Smrg } 439e88f27b3Smrg 440857b0bc6Smrg flush_reset(ring); 441e88f27b3Smrg 442e88f27b3Smrg return ret; 443e88f27b3Smrg} 444e88f27b3Smrg 4453f012e29Smrgstatic void msm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size) 4463f012e29Smrg{ 4473f012e29Smrg assert(to_msm_ringbuffer(ring)->is_growable); 4483f012e29Smrg finalize_current_cmd(ring, ring->last_start); 4493f012e29Smrg ring_cmd_new(ring, size); 4503f012e29Smrg} 4513f012e29Smrg 452857b0bc6Smrgstatic void msm_ringbuffer_reset(struct fd_ringbuffer *ring) 453857b0bc6Smrg{ 454857b0bc6Smrg flush_reset(ring); 455857b0bc6Smrg} 456857b0bc6Smrg 457e88f27b3Smrgstatic void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, 458e88f27b3Smrg const struct fd_reloc *r) 459e88f27b3Smrg{ 460e88f27b3Smrg struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring; 461e88f27b3Smrg struct msm_bo *msm_bo = to_msm_bo(r->bo); 462e88f27b3Smrg struct drm_msm_gem_submit_reloc *reloc; 4633f012e29Smrg struct msm_cmd *cmd = current_cmd(ring); 4643f012e29Smrg uint32_t idx = APPEND(cmd, relocs); 465e88f27b3Smrg uint32_t addr; 466e88f27b3Smrg 4673f012e29Smrg reloc = &cmd->relocs[idx]; 468e88f27b3Smrg 469e88f27b3Smrg reloc->reloc_idx = bo2idx(parent, r->bo, r->flags); 470e88f27b3Smrg reloc->reloc_offset = r->offset; 471e88f27b3Smrg reloc->or = r->or; 472e88f27b3Smrg reloc->shift = r->shift; 473e88f27b3Smrg reloc->submit_offset = offset_bytes(ring->cur, ring->start); 474e88f27b3Smrg 475e88f27b3Smrg addr = msm_bo->presumed; 476e88f27b3Smrg if (r->shift < 0) 477e88f27b3Smrg addr >>= -r->shift; 478e88f27b3Smrg else 479e88f27b3Smrg addr <<= r->shift; 480e88f27b3Smrg (*ring->cur++) = addr | r->or; 481e88f27b3Smrg} 482e88f27b3Smrg 4833f012e29Smrgstatic uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 4843f012e29Smrg struct fd_ringbuffer *target, uint32_t cmd_idx, 4853f012e29Smrg uint32_t submit_offset, uint32_t size) 486e88f27b3Smrg{ 4873f012e29Smrg struct msm_cmd *cmd = NULL; 4883f012e29Smrg uint32_t idx = 0; 4893f012e29Smrg 4903f012e29Smrg LIST_FOR_EACH_ENTRY(cmd, &to_msm_ringbuffer(target)->cmd_list, list) { 4913f012e29Smrg if (idx == cmd_idx) 4923f012e29Smrg break; 4933f012e29Smrg idx++; 4943f012e29Smrg } 495e88f27b3Smrg 4963f012e29Smrg assert(cmd && (idx == cmd_idx)); 497e88f27b3Smrg 4983f012e29Smrg if (idx < (to_msm_ringbuffer(target)->cmd_count - 1)) { 4993f012e29Smrg /* All but the last cmd buffer is fully "baked" (ie. already has 5003f012e29Smrg * done get_cmd() to add it to the cmds table). But in this case, 5013f012e29Smrg * the size we get is invalid (since it is calculated from the 5023f012e29Smrg * last cmd buffer): 5033f012e29Smrg */ 5043f012e29Smrg size = cmd->size; 5053f012e29Smrg } else { 5063f012e29Smrg get_cmd(ring, cmd, submit_offset, size, MSM_SUBMIT_CMD_IB_TARGET_BUF); 5073f012e29Smrg } 508e88f27b3Smrg 509e88f27b3Smrg msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){ 5103f012e29Smrg .bo = cmd->ring_bo, 511e88f27b3Smrg .flags = FD_RELOC_READ, 512e88f27b3Smrg .offset = submit_offset, 513e88f27b3Smrg }); 5143f012e29Smrg 5153f012e29Smrg return size; 5163f012e29Smrg} 5173f012e29Smrg 5183f012e29Smrgstatic uint32_t msm_ringbuffer_cmd_count(struct fd_ringbuffer *ring) 5193f012e29Smrg{ 5203f012e29Smrg return to_msm_ringbuffer(ring)->cmd_count; 521e88f27b3Smrg} 522e88f27b3Smrg 523e88f27b3Smrgstatic void msm_ringbuffer_destroy(struct fd_ringbuffer *ring) 524e88f27b3Smrg{ 525e88f27b3Smrg struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 5263f012e29Smrg 5273f012e29Smrg flush_reset(ring); 5283f012e29Smrg delete_cmds(msm_ring); 5293f012e29Smrg 5303f012e29Smrg free(msm_ring->submit.cmds); 5313f012e29Smrg free(msm_ring->submit.bos); 5323f012e29Smrg free(msm_ring->bos); 5333f012e29Smrg free(msm_ring->cmds); 534e88f27b3Smrg free(msm_ring); 535e88f27b3Smrg} 536e88f27b3Smrg 5373f012e29Smrgstatic const struct fd_ringbuffer_funcs funcs = { 538e88f27b3Smrg .hostptr = msm_ringbuffer_hostptr, 539e88f27b3Smrg .flush = msm_ringbuffer_flush, 5403f012e29Smrg .grow = msm_ringbuffer_grow, 541857b0bc6Smrg .reset = msm_ringbuffer_reset, 542e88f27b3Smrg .emit_reloc = msm_ringbuffer_emit_reloc, 543e88f27b3Smrg .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, 5443f012e29Smrg .cmd_count = msm_ringbuffer_cmd_count, 545e88f27b3Smrg .destroy = msm_ringbuffer_destroy, 546e88f27b3Smrg}; 547e88f27b3Smrg 548e6188e58Smrgdrm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe, 549e88f27b3Smrg uint32_t size) 550e88f27b3Smrg{ 551e88f27b3Smrg struct msm_ringbuffer *msm_ring; 552e88f27b3Smrg struct fd_ringbuffer *ring = NULL; 553e88f27b3Smrg 554e88f27b3Smrg msm_ring = calloc(1, sizeof(*msm_ring)); 555e88f27b3Smrg if (!msm_ring) { 556e88f27b3Smrg ERROR_MSG("allocation failed"); 557e88f27b3Smrg goto fail; 558e88f27b3Smrg } 559e88f27b3Smrg 5603f012e29Smrg if (size == 0) { 5613f012e29Smrg assert(pipe->dev->version >= FD_VERSION_UNLIMITED_CMDS); 5623f012e29Smrg size = INIT_SIZE; 5633f012e29Smrg msm_ring->is_growable = TRUE; 5643f012e29Smrg } 5653f012e29Smrg 5663f012e29Smrg list_inithead(&msm_ring->cmd_list); 5673f012e29Smrg msm_ring->seqno = ++to_msm_device(pipe->dev)->ring_cnt; 5683f012e29Smrg 569e88f27b3Smrg ring = &msm_ring->base; 570e88f27b3Smrg ring->funcs = &funcs; 5713f012e29Smrg ring->size = size; 5723f012e29Smrg ring->pipe = pipe; /* needed in ring_cmd_new() */ 573e88f27b3Smrg 5743f012e29Smrg ring_cmd_new(ring, size); 575e88f27b3Smrg 576e88f27b3Smrg return ring; 577e88f27b3Smrgfail: 578e88f27b3Smrg if (ring) 579e88f27b3Smrg fd_ringbuffer_del(ring); 580e88f27b3Smrg return NULL; 581e88f27b3Smrg} 582