1d722e3fbSopenharmony_ci/* 2d722e3fbSopenharmony_ci * Copyright (C) 2014-2015 Etnaviv Project 3d722e3fbSopenharmony_ci * 4d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation 7d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10d722e3fbSopenharmony_ci * 11d722e3fbSopenharmony_ci * The above copyright notice and this permission notice (including the next 12d722e3fbSopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13d722e3fbSopenharmony_ci * Software. 14d722e3fbSopenharmony_ci * 15d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18d722e3fbSopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19d722e3fbSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20d722e3fbSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21d722e3fbSopenharmony_ci * SOFTWARE. 22d722e3fbSopenharmony_ci * 23d722e3fbSopenharmony_ci * Authors: 24d722e3fbSopenharmony_ci * Christian Gmeiner <christian.gmeiner@gmail.com> 25d722e3fbSopenharmony_ci */ 26d722e3fbSopenharmony_ci 27d722e3fbSopenharmony_ci#include <assert.h> 28d722e3fbSopenharmony_ci 29d722e3fbSopenharmony_ci#include "etnaviv_drmif.h" 30d722e3fbSopenharmony_ci#include "etnaviv_priv.h" 31d722e3fbSopenharmony_ci 32d722e3fbSopenharmony_cistatic pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; 33d722e3fbSopenharmony_ci 34d722e3fbSopenharmony_cistatic void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz) 35d722e3fbSopenharmony_ci{ 36d722e3fbSopenharmony_ci if ((nr + 1) > *max) { 37d722e3fbSopenharmony_ci if ((*max * 2) < (nr + 1)) 38d722e3fbSopenharmony_ci *max = nr + 5; 39d722e3fbSopenharmony_ci else 40d722e3fbSopenharmony_ci *max = *max * 2; 41d722e3fbSopenharmony_ci ptr = realloc(ptr, *max * sz); 42d722e3fbSopenharmony_ci } 43d722e3fbSopenharmony_ci 44d722e3fbSopenharmony_ci return ptr; 45d722e3fbSopenharmony_ci} 46d722e3fbSopenharmony_ci 47d722e3fbSopenharmony_ci#define APPEND(x, name) ({ \ 48d722e3fbSopenharmony_ci (x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \ 49d722e3fbSopenharmony_ci (x)->nr_ ## name ++; \ 50d722e3fbSopenharmony_ci}) 51d722e3fbSopenharmony_ci 52d722e3fbSopenharmony_cistatic inline struct etna_cmd_stream_priv * 53d722e3fbSopenharmony_cietna_cmd_stream_priv(struct etna_cmd_stream *stream) 54d722e3fbSopenharmony_ci{ 55d722e3fbSopenharmony_ci return (struct etna_cmd_stream_priv *)stream; 56d722e3fbSopenharmony_ci} 57d722e3fbSopenharmony_ci 58d722e3fbSopenharmony_cidrm_public struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, 59d722e3fbSopenharmony_ci uint32_t size, 60d722e3fbSopenharmony_ci void (*reset_notify)(struct etna_cmd_stream *stream, void *priv), 61d722e3fbSopenharmony_ci void *priv) 62d722e3fbSopenharmony_ci{ 63d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *stream = NULL; 64d722e3fbSopenharmony_ci 65d722e3fbSopenharmony_ci if (size == 0) { 66d722e3fbSopenharmony_ci ERROR_MSG("invalid size of 0"); 67d722e3fbSopenharmony_ci goto fail; 68d722e3fbSopenharmony_ci } 69d722e3fbSopenharmony_ci 70d722e3fbSopenharmony_ci stream = calloc(1, sizeof(*stream)); 71d722e3fbSopenharmony_ci if (!stream) { 72d722e3fbSopenharmony_ci ERROR_MSG("allocation failed"); 73d722e3fbSopenharmony_ci goto fail; 74d722e3fbSopenharmony_ci } 75d722e3fbSopenharmony_ci 76d722e3fbSopenharmony_ci /* allocate even number of 32-bit words */ 77d722e3fbSopenharmony_ci size = ALIGN(size, 2); 78d722e3fbSopenharmony_ci 79d722e3fbSopenharmony_ci stream->base.buffer = malloc(size * sizeof(uint32_t)); 80d722e3fbSopenharmony_ci if (!stream->base.buffer) { 81d722e3fbSopenharmony_ci ERROR_MSG("allocation failed"); 82d722e3fbSopenharmony_ci goto fail; 83d722e3fbSopenharmony_ci } 84d722e3fbSopenharmony_ci 85d722e3fbSopenharmony_ci stream->base.size = size; 86d722e3fbSopenharmony_ci stream->pipe = pipe; 87d722e3fbSopenharmony_ci stream->reset_notify = reset_notify; 88d722e3fbSopenharmony_ci stream->reset_notify_priv = priv; 89d722e3fbSopenharmony_ci 90d722e3fbSopenharmony_ci return &stream->base; 91d722e3fbSopenharmony_ci 92d722e3fbSopenharmony_cifail: 93d722e3fbSopenharmony_ci if (stream) 94d722e3fbSopenharmony_ci etna_cmd_stream_del(&stream->base); 95d722e3fbSopenharmony_ci 96d722e3fbSopenharmony_ci return NULL; 97d722e3fbSopenharmony_ci} 98d722e3fbSopenharmony_ci 99d722e3fbSopenharmony_cidrm_public void etna_cmd_stream_del(struct etna_cmd_stream *stream) 100d722e3fbSopenharmony_ci{ 101d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 102d722e3fbSopenharmony_ci 103d722e3fbSopenharmony_ci free(stream->buffer); 104d722e3fbSopenharmony_ci free(priv->submit.relocs); 105d722e3fbSopenharmony_ci free(priv->submit.pmrs); 106d722e3fbSopenharmony_ci free(priv); 107d722e3fbSopenharmony_ci} 108d722e3fbSopenharmony_ci 109d722e3fbSopenharmony_cistatic void reset_buffer(struct etna_cmd_stream *stream) 110d722e3fbSopenharmony_ci{ 111d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 112d722e3fbSopenharmony_ci 113d722e3fbSopenharmony_ci stream->offset = 0; 114d722e3fbSopenharmony_ci priv->submit.nr_bos = 0; 115d722e3fbSopenharmony_ci priv->submit.nr_relocs = 0; 116d722e3fbSopenharmony_ci priv->submit.nr_pmrs = 0; 117d722e3fbSopenharmony_ci priv->nr_bos = 0; 118d722e3fbSopenharmony_ci 119d722e3fbSopenharmony_ci if (priv->reset_notify) 120d722e3fbSopenharmony_ci priv->reset_notify(stream, priv->reset_notify_priv); 121d722e3fbSopenharmony_ci} 122d722e3fbSopenharmony_ci 123d722e3fbSopenharmony_cidrm_public uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream) 124d722e3fbSopenharmony_ci{ 125d722e3fbSopenharmony_ci return etna_cmd_stream_priv(stream)->last_timestamp; 126d722e3fbSopenharmony_ci} 127d722e3fbSopenharmony_ci 128d722e3fbSopenharmony_cistatic uint32_t append_bo(struct etna_cmd_stream *stream, struct etna_bo *bo) 129d722e3fbSopenharmony_ci{ 130d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 131d722e3fbSopenharmony_ci uint32_t idx; 132d722e3fbSopenharmony_ci 133d722e3fbSopenharmony_ci idx = APPEND(&priv->submit, bos); 134d722e3fbSopenharmony_ci idx = APPEND(priv, bos); 135d722e3fbSopenharmony_ci 136d722e3fbSopenharmony_ci priv->submit.bos[idx].flags = 0; 137d722e3fbSopenharmony_ci priv->submit.bos[idx].handle = bo->handle; 138d722e3fbSopenharmony_ci 139d722e3fbSopenharmony_ci priv->bos[idx] = etna_bo_ref(bo); 140d722e3fbSopenharmony_ci 141d722e3fbSopenharmony_ci return idx; 142d722e3fbSopenharmony_ci} 143d722e3fbSopenharmony_ci 144d722e3fbSopenharmony_ci/* add (if needed) bo, return idx: */ 145d722e3fbSopenharmony_cistatic uint32_t bo2idx(struct etna_cmd_stream *stream, struct etna_bo *bo, 146d722e3fbSopenharmony_ci uint32_t flags) 147d722e3fbSopenharmony_ci{ 148d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 149d722e3fbSopenharmony_ci uint32_t idx; 150d722e3fbSopenharmony_ci 151d722e3fbSopenharmony_ci pthread_mutex_lock(&idx_lock); 152d722e3fbSopenharmony_ci 153d722e3fbSopenharmony_ci if (bo->current_stream == stream) { 154d722e3fbSopenharmony_ci idx = bo->idx; 155d722e3fbSopenharmony_ci } else { 156d722e3fbSopenharmony_ci /* slow-path: */ 157d722e3fbSopenharmony_ci for (idx = 0; idx < priv->nr_bos; idx++) 158d722e3fbSopenharmony_ci if (priv->bos[idx] == bo) 159d722e3fbSopenharmony_ci break; 160d722e3fbSopenharmony_ci if (idx == priv->nr_bos) { 161d722e3fbSopenharmony_ci /* not found */ 162d722e3fbSopenharmony_ci idx = append_bo(stream, bo); 163d722e3fbSopenharmony_ci } 164d722e3fbSopenharmony_ci bo->current_stream = stream; 165d722e3fbSopenharmony_ci bo->idx = idx; 166d722e3fbSopenharmony_ci } 167d722e3fbSopenharmony_ci pthread_mutex_unlock(&idx_lock); 168d722e3fbSopenharmony_ci 169d722e3fbSopenharmony_ci if (flags & ETNA_RELOC_READ) 170d722e3fbSopenharmony_ci priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_READ; 171d722e3fbSopenharmony_ci if (flags & ETNA_RELOC_WRITE) 172d722e3fbSopenharmony_ci priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_WRITE; 173d722e3fbSopenharmony_ci 174d722e3fbSopenharmony_ci return idx; 175d722e3fbSopenharmony_ci} 176d722e3fbSopenharmony_ci 177d722e3fbSopenharmony_cistatic void flush(struct etna_cmd_stream *stream, int in_fence_fd, 178d722e3fbSopenharmony_ci int *out_fence_fd) 179d722e3fbSopenharmony_ci{ 180d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 181d722e3fbSopenharmony_ci int ret, id = priv->pipe->id; 182d722e3fbSopenharmony_ci struct etna_gpu *gpu = priv->pipe->gpu; 183d722e3fbSopenharmony_ci 184d722e3fbSopenharmony_ci struct drm_etnaviv_gem_submit req = { 185d722e3fbSopenharmony_ci .pipe = gpu->core, 186d722e3fbSopenharmony_ci .exec_state = id, 187d722e3fbSopenharmony_ci .bos = VOID2U64(priv->submit.bos), 188d722e3fbSopenharmony_ci .nr_bos = priv->submit.nr_bos, 189d722e3fbSopenharmony_ci .relocs = VOID2U64(priv->submit.relocs), 190d722e3fbSopenharmony_ci .nr_relocs = priv->submit.nr_relocs, 191d722e3fbSopenharmony_ci .pmrs = VOID2U64(priv->submit.pmrs), 192d722e3fbSopenharmony_ci .nr_pmrs = priv->submit.nr_pmrs, 193d722e3fbSopenharmony_ci .stream = VOID2U64(stream->buffer), 194d722e3fbSopenharmony_ci .stream_size = stream->offset * 4, /* in bytes */ 195d722e3fbSopenharmony_ci }; 196d722e3fbSopenharmony_ci 197d722e3fbSopenharmony_ci if (in_fence_fd != -1) { 198d722e3fbSopenharmony_ci req.flags |= ETNA_SUBMIT_FENCE_FD_IN | ETNA_SUBMIT_NO_IMPLICIT; 199d722e3fbSopenharmony_ci req.fence_fd = in_fence_fd; 200d722e3fbSopenharmony_ci } 201d722e3fbSopenharmony_ci 202d722e3fbSopenharmony_ci if (out_fence_fd) 203d722e3fbSopenharmony_ci req.flags |= ETNA_SUBMIT_FENCE_FD_OUT; 204d722e3fbSopenharmony_ci 205d722e3fbSopenharmony_ci ret = drmCommandWriteRead(gpu->dev->fd, DRM_ETNAVIV_GEM_SUBMIT, 206d722e3fbSopenharmony_ci &req, sizeof(req)); 207d722e3fbSopenharmony_ci 208d722e3fbSopenharmony_ci if (ret) 209d722e3fbSopenharmony_ci ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); 210d722e3fbSopenharmony_ci else 211d722e3fbSopenharmony_ci priv->last_timestamp = req.fence; 212d722e3fbSopenharmony_ci 213d722e3fbSopenharmony_ci for (uint32_t i = 0; i < priv->nr_bos; i++) { 214d722e3fbSopenharmony_ci struct etna_bo *bo = priv->bos[i]; 215d722e3fbSopenharmony_ci 216d722e3fbSopenharmony_ci bo->current_stream = NULL; 217d722e3fbSopenharmony_ci etna_bo_del(bo); 218d722e3fbSopenharmony_ci } 219d722e3fbSopenharmony_ci 220d722e3fbSopenharmony_ci if (out_fence_fd) 221d722e3fbSopenharmony_ci *out_fence_fd = req.fence_fd; 222d722e3fbSopenharmony_ci} 223d722e3fbSopenharmony_ci 224d722e3fbSopenharmony_cidrm_public void etna_cmd_stream_flush(struct etna_cmd_stream *stream) 225d722e3fbSopenharmony_ci{ 226d722e3fbSopenharmony_ci flush(stream, -1, NULL); 227d722e3fbSopenharmony_ci reset_buffer(stream); 228d722e3fbSopenharmony_ci} 229d722e3fbSopenharmony_ci 230d722e3fbSopenharmony_cidrm_public void etna_cmd_stream_flush2(struct etna_cmd_stream *stream, 231d722e3fbSopenharmony_ci int in_fence_fd, 232d722e3fbSopenharmony_ci int *out_fence_fd) 233d722e3fbSopenharmony_ci{ 234d722e3fbSopenharmony_ci flush(stream, in_fence_fd, out_fence_fd); 235d722e3fbSopenharmony_ci reset_buffer(stream); 236d722e3fbSopenharmony_ci} 237d722e3fbSopenharmony_ci 238d722e3fbSopenharmony_cidrm_public void etna_cmd_stream_finish(struct etna_cmd_stream *stream) 239d722e3fbSopenharmony_ci{ 240d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 241d722e3fbSopenharmony_ci 242d722e3fbSopenharmony_ci flush(stream, -1, NULL); 243d722e3fbSopenharmony_ci etna_pipe_wait(priv->pipe, priv->last_timestamp, 5000); 244d722e3fbSopenharmony_ci reset_buffer(stream); 245d722e3fbSopenharmony_ci} 246d722e3fbSopenharmony_ci 247d722e3fbSopenharmony_cidrm_public void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, 248d722e3fbSopenharmony_ci const struct etna_reloc *r) 249d722e3fbSopenharmony_ci{ 250d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 251d722e3fbSopenharmony_ci struct drm_etnaviv_gem_submit_reloc *reloc; 252d722e3fbSopenharmony_ci uint32_t idx = APPEND(&priv->submit, relocs); 253d722e3fbSopenharmony_ci uint32_t addr = 0; 254d722e3fbSopenharmony_ci 255d722e3fbSopenharmony_ci reloc = &priv->submit.relocs[idx]; 256d722e3fbSopenharmony_ci 257d722e3fbSopenharmony_ci reloc->reloc_idx = bo2idx(stream, r->bo, r->flags); 258d722e3fbSopenharmony_ci reloc->reloc_offset = r->offset; 259d722e3fbSopenharmony_ci reloc->submit_offset = stream->offset * 4; /* in bytes */ 260d722e3fbSopenharmony_ci reloc->flags = 0; 261d722e3fbSopenharmony_ci 262d722e3fbSopenharmony_ci etna_cmd_stream_emit(stream, addr); 263d722e3fbSopenharmony_ci} 264d722e3fbSopenharmony_ci 265d722e3fbSopenharmony_cidrm_public void etna_cmd_stream_perf(struct etna_cmd_stream *stream, const struct etna_perf *p) 266d722e3fbSopenharmony_ci{ 267d722e3fbSopenharmony_ci struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); 268d722e3fbSopenharmony_ci struct drm_etnaviv_gem_submit_pmr *pmr; 269d722e3fbSopenharmony_ci uint32_t idx = APPEND(&priv->submit, pmrs); 270d722e3fbSopenharmony_ci 271d722e3fbSopenharmony_ci pmr = &priv->submit.pmrs[idx]; 272d722e3fbSopenharmony_ci 273d722e3fbSopenharmony_ci pmr->flags = p->flags; 274d722e3fbSopenharmony_ci pmr->sequence = p->sequence; 275d722e3fbSopenharmony_ci pmr->read_offset = p->offset; 276d722e3fbSopenharmony_ci pmr->read_idx = bo2idx(stream, p->bo, ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE); 277d722e3fbSopenharmony_ci pmr->domain = p->signal->domain->id; 278d722e3fbSopenharmony_ci pmr->signal = p->signal->signal; 279d722e3fbSopenharmony_ci} 280