1d722e3fbSopenharmony_ci/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2d722e3fbSopenharmony_ci 3d722e3fbSopenharmony_ci/* 4d722e3fbSopenharmony_ci * Copyright (C) 2013 Rob Clark <robclark@freedesktop.org> 5d722e3fbSopenharmony_ci * 6d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 8d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation 9d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 11d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 12d722e3fbSopenharmony_ci * 13d722e3fbSopenharmony_ci * The above copyright notice and this permission notice (including the next 14d722e3fbSopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 15d722e3fbSopenharmony_ci * Software. 16d722e3fbSopenharmony_ci * 17d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20d722e3fbSopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21d722e3fbSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22d722e3fbSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23d722e3fbSopenharmony_ci * SOFTWARE. 24d722e3fbSopenharmony_ci * 25d722e3fbSopenharmony_ci * Authors: 26d722e3fbSopenharmony_ci * Rob Clark <robclark@freedesktop.org> 27d722e3fbSopenharmony_ci */ 28d722e3fbSopenharmony_ci 29d722e3fbSopenharmony_ci#include <assert.h> 30d722e3fbSopenharmony_ci 31d722e3fbSopenharmony_ci#include "xf86atomic.h" 32d722e3fbSopenharmony_ci#include "freedreno_ringbuffer.h" 33d722e3fbSopenharmony_ci#include "kgsl_priv.h" 34d722e3fbSopenharmony_ci 35d722e3fbSopenharmony_ci 36d722e3fbSopenharmony_ci/* because kgsl tries to validate the gpuaddr on kernel side in ISSUEIBCMDS, 37d722e3fbSopenharmony_ci * we can't use normal gem bo's for ringbuffer.. someday the kernel part 38d722e3fbSopenharmony_ci * needs to be reworked into a single sane drm driver :-/ 39d722e3fbSopenharmony_ci */ 40d722e3fbSopenharmony_cistruct kgsl_rb_bo { 41d722e3fbSopenharmony_ci struct kgsl_pipe *pipe; 42d722e3fbSopenharmony_ci void *hostptr; 43d722e3fbSopenharmony_ci uint32_t gpuaddr; 44d722e3fbSopenharmony_ci uint32_t size; 45d722e3fbSopenharmony_ci}; 46d722e3fbSopenharmony_ci 47d722e3fbSopenharmony_cistruct kgsl_ringbuffer { 48d722e3fbSopenharmony_ci struct fd_ringbuffer base; 49d722e3fbSopenharmony_ci struct kgsl_rb_bo *bo; 50d722e3fbSopenharmony_ci}; 51d722e3fbSopenharmony_ci 52d722e3fbSopenharmony_cistatic inline struct kgsl_ringbuffer * to_kgsl_ringbuffer(struct fd_ringbuffer *x) 53d722e3fbSopenharmony_ci{ 54d722e3fbSopenharmony_ci return (struct kgsl_ringbuffer *)x; 55d722e3fbSopenharmony_ci} 56d722e3fbSopenharmony_ci 57d722e3fbSopenharmony_cistatic void kgsl_rb_bo_del(struct kgsl_rb_bo *bo) 58d722e3fbSopenharmony_ci{ 59d722e3fbSopenharmony_ci struct kgsl_sharedmem_free req = { 60d722e3fbSopenharmony_ci .gpuaddr = bo->gpuaddr, 61d722e3fbSopenharmony_ci }; 62d722e3fbSopenharmony_ci int ret; 63d722e3fbSopenharmony_ci 64d722e3fbSopenharmony_ci drm_munmap(bo->hostptr, bo->size); 65d722e3fbSopenharmony_ci 66d722e3fbSopenharmony_ci ret = ioctl(bo->pipe->fd, IOCTL_KGSL_SHAREDMEM_FREE, &req); 67d722e3fbSopenharmony_ci if (ret) { 68d722e3fbSopenharmony_ci ERROR_MSG("sharedmem free failed: %s", strerror(errno)); 69d722e3fbSopenharmony_ci } 70d722e3fbSopenharmony_ci 71d722e3fbSopenharmony_ci free(bo); 72d722e3fbSopenharmony_ci} 73d722e3fbSopenharmony_ci 74d722e3fbSopenharmony_cistatic struct kgsl_rb_bo * kgsl_rb_bo_new(struct kgsl_pipe *pipe, uint32_t size) 75d722e3fbSopenharmony_ci{ 76d722e3fbSopenharmony_ci struct kgsl_rb_bo *bo; 77d722e3fbSopenharmony_ci struct kgsl_gpumem_alloc req = { 78d722e3fbSopenharmony_ci .size = ALIGN(size, 4096), 79d722e3fbSopenharmony_ci .flags = KGSL_MEMFLAGS_GPUREADONLY, 80d722e3fbSopenharmony_ci }; 81d722e3fbSopenharmony_ci int ret; 82d722e3fbSopenharmony_ci 83d722e3fbSopenharmony_ci bo = calloc(1, sizeof(*bo)); 84d722e3fbSopenharmony_ci if (!bo) { 85d722e3fbSopenharmony_ci ERROR_MSG("allocation failed"); 86d722e3fbSopenharmony_ci return NULL; 87d722e3fbSopenharmony_ci } 88d722e3fbSopenharmony_ci ret = ioctl(pipe->fd, IOCTL_KGSL_GPUMEM_ALLOC, &req); 89d722e3fbSopenharmony_ci if (ret) { 90d722e3fbSopenharmony_ci ERROR_MSG("gpumem allocation failed: %s", strerror(errno)); 91d722e3fbSopenharmony_ci goto fail; 92d722e3fbSopenharmony_ci } 93d722e3fbSopenharmony_ci 94d722e3fbSopenharmony_ci bo->pipe = pipe; 95d722e3fbSopenharmony_ci bo->gpuaddr = req.gpuaddr; 96d722e3fbSopenharmony_ci bo->size = size; 97d722e3fbSopenharmony_ci bo->hostptr = drm_mmap(NULL, size, PROT_WRITE|PROT_READ, 98d722e3fbSopenharmony_ci MAP_SHARED, pipe->fd, req.gpuaddr); 99d722e3fbSopenharmony_ci 100d722e3fbSopenharmony_ci return bo; 101d722e3fbSopenharmony_cifail: 102d722e3fbSopenharmony_ci if (bo) 103d722e3fbSopenharmony_ci kgsl_rb_bo_del(bo); 104d722e3fbSopenharmony_ci return NULL; 105d722e3fbSopenharmony_ci} 106d722e3fbSopenharmony_ci 107d722e3fbSopenharmony_cistatic void * kgsl_ringbuffer_hostptr(struct fd_ringbuffer *ring) 108d722e3fbSopenharmony_ci{ 109d722e3fbSopenharmony_ci struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring); 110d722e3fbSopenharmony_ci return kgsl_ring->bo->hostptr; 111d722e3fbSopenharmony_ci} 112d722e3fbSopenharmony_ci 113d722e3fbSopenharmony_cistatic int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start, 114d722e3fbSopenharmony_ci int in_fence_fd, int *out_fence_fd) 115d722e3fbSopenharmony_ci{ 116d722e3fbSopenharmony_ci struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring); 117d722e3fbSopenharmony_ci struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(ring->pipe); 118d722e3fbSopenharmony_ci uint32_t offset = (uint8_t *)last_start - (uint8_t *)ring->start; 119d722e3fbSopenharmony_ci struct kgsl_ibdesc ibdesc = { 120d722e3fbSopenharmony_ci .gpuaddr = kgsl_ring->bo->gpuaddr + offset, 121d722e3fbSopenharmony_ci .hostptr = last_start, 122d722e3fbSopenharmony_ci .sizedwords = ring->cur - last_start, 123d722e3fbSopenharmony_ci }; 124d722e3fbSopenharmony_ci struct kgsl_ringbuffer_issueibcmds req = { 125d722e3fbSopenharmony_ci .drawctxt_id = kgsl_pipe->drawctxt_id, 126d722e3fbSopenharmony_ci .ibdesc_addr = (unsigned long)&ibdesc, 127d722e3fbSopenharmony_ci .numibs = 1, 128d722e3fbSopenharmony_ci .flags = KGSL_CONTEXT_SUBMIT_IB_LIST, 129d722e3fbSopenharmony_ci }; 130d722e3fbSopenharmony_ci int ret; 131d722e3fbSopenharmony_ci 132d722e3fbSopenharmony_ci assert(in_fence_fd == -1); 133d722e3fbSopenharmony_ci assert(out_fence_fd == NULL); 134d722e3fbSopenharmony_ci 135d722e3fbSopenharmony_ci kgsl_pipe_pre_submit(kgsl_pipe); 136d722e3fbSopenharmony_ci 137d722e3fbSopenharmony_ci /* z180_cmdstream_issueibcmds() is made of fail: */ 138d722e3fbSopenharmony_ci if (ring->pipe->id == FD_PIPE_2D) { 139d722e3fbSopenharmony_ci /* fix up size field in last cmd packet */ 140d722e3fbSopenharmony_ci uint32_t last_size = (uint32_t)(ring->cur - last_start); 141d722e3fbSopenharmony_ci /* 5 is length of first packet, 2 for the two 7f000000's */ 142d722e3fbSopenharmony_ci last_start[2] = last_size - (5 + 2); 143d722e3fbSopenharmony_ci ibdesc.gpuaddr = kgsl_ring->bo->gpuaddr; 144d722e3fbSopenharmony_ci ibdesc.hostptr = kgsl_ring->bo->hostptr; 145d722e3fbSopenharmony_ci ibdesc.sizedwords = 0x145; 146d722e3fbSopenharmony_ci req.timestamp = (uintptr_t)kgsl_ring->bo->hostptr; 147d722e3fbSopenharmony_ci } 148d722e3fbSopenharmony_ci 149d722e3fbSopenharmony_ci do { 150d722e3fbSopenharmony_ci ret = ioctl(kgsl_pipe->fd, IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS, &req); 151d722e3fbSopenharmony_ci } while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN))); 152d722e3fbSopenharmony_ci if (ret) 153d722e3fbSopenharmony_ci ERROR_MSG("issueibcmds failed! %d (%s)", ret, strerror(errno)); 154d722e3fbSopenharmony_ci 155d722e3fbSopenharmony_ci ring->last_timestamp = req.timestamp; 156d722e3fbSopenharmony_ci ring->last_start = ring->cur; 157d722e3fbSopenharmony_ci 158d722e3fbSopenharmony_ci kgsl_pipe_post_submit(kgsl_pipe, req.timestamp); 159d722e3fbSopenharmony_ci 160d722e3fbSopenharmony_ci return ret; 161d722e3fbSopenharmony_ci} 162d722e3fbSopenharmony_ci 163d722e3fbSopenharmony_cistatic void kgsl_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, 164d722e3fbSopenharmony_ci const struct fd_reloc *r) 165d722e3fbSopenharmony_ci{ 166d722e3fbSopenharmony_ci struct kgsl_bo *kgsl_bo = to_kgsl_bo(r->bo); 167d722e3fbSopenharmony_ci uint32_t addr = kgsl_bo_gpuaddr(kgsl_bo, r->offset); 168d722e3fbSopenharmony_ci assert(addr); 169d722e3fbSopenharmony_ci if (r->shift < 0) 170d722e3fbSopenharmony_ci addr >>= -r->shift; 171d722e3fbSopenharmony_ci else 172d722e3fbSopenharmony_ci addr <<= r->shift; 173d722e3fbSopenharmony_ci (*ring->cur++) = addr | r->or; 174d722e3fbSopenharmony_ci kgsl_pipe_add_submit(to_kgsl_pipe(ring->pipe), kgsl_bo); 175d722e3fbSopenharmony_ci} 176d722e3fbSopenharmony_ci 177d722e3fbSopenharmony_cistatic uint32_t kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 178d722e3fbSopenharmony_ci struct fd_ringbuffer *target, uint32_t cmd_idx) 179d722e3fbSopenharmony_ci{ 180d722e3fbSopenharmony_ci struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target); 181d722e3fbSopenharmony_ci assert(cmd_idx == 0); 182d722e3fbSopenharmony_ci (*ring->cur++) = target_ring->bo->gpuaddr; 183d722e3fbSopenharmony_ci return offset_bytes(target->cur, target->start); 184d722e3fbSopenharmony_ci} 185d722e3fbSopenharmony_ci 186d722e3fbSopenharmony_cistatic void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring) 187d722e3fbSopenharmony_ci{ 188d722e3fbSopenharmony_ci struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring); 189d722e3fbSopenharmony_ci if (ring->last_timestamp) 190d722e3fbSopenharmony_ci fd_pipe_wait(ring->pipe, ring->last_timestamp); 191d722e3fbSopenharmony_ci if (kgsl_ring->bo) 192d722e3fbSopenharmony_ci kgsl_rb_bo_del(kgsl_ring->bo); 193d722e3fbSopenharmony_ci free(kgsl_ring); 194d722e3fbSopenharmony_ci} 195d722e3fbSopenharmony_ci 196d722e3fbSopenharmony_cistatic const struct fd_ringbuffer_funcs funcs = { 197d722e3fbSopenharmony_ci .hostptr = kgsl_ringbuffer_hostptr, 198d722e3fbSopenharmony_ci .flush = kgsl_ringbuffer_flush, 199d722e3fbSopenharmony_ci .emit_reloc = kgsl_ringbuffer_emit_reloc, 200d722e3fbSopenharmony_ci .emit_reloc_ring = kgsl_ringbuffer_emit_reloc_ring, 201d722e3fbSopenharmony_ci .destroy = kgsl_ringbuffer_destroy, 202d722e3fbSopenharmony_ci}; 203d722e3fbSopenharmony_ci 204d722e3fbSopenharmony_cidrm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe, 205d722e3fbSopenharmony_ci uint32_t size, enum fd_ringbuffer_flags flags) 206d722e3fbSopenharmony_ci{ 207d722e3fbSopenharmony_ci struct kgsl_ringbuffer *kgsl_ring; 208d722e3fbSopenharmony_ci struct fd_ringbuffer *ring = NULL; 209d722e3fbSopenharmony_ci 210d722e3fbSopenharmony_ci assert(!flags); 211d722e3fbSopenharmony_ci 212d722e3fbSopenharmony_ci kgsl_ring = calloc(1, sizeof(*kgsl_ring)); 213d722e3fbSopenharmony_ci if (!kgsl_ring) { 214d722e3fbSopenharmony_ci ERROR_MSG("allocation failed"); 215d722e3fbSopenharmony_ci goto fail; 216d722e3fbSopenharmony_ci } 217d722e3fbSopenharmony_ci 218d722e3fbSopenharmony_ci ring = &kgsl_ring->base; 219d722e3fbSopenharmony_ci atomic_set(&ring->refcnt, 1); 220d722e3fbSopenharmony_ci 221d722e3fbSopenharmony_ci ring->funcs = &funcs; 222d722e3fbSopenharmony_ci ring->size = size; 223d722e3fbSopenharmony_ci 224d722e3fbSopenharmony_ci kgsl_ring->bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), size); 225d722e3fbSopenharmony_ci if (!kgsl_ring->bo) { 226d722e3fbSopenharmony_ci ERROR_MSG("ringbuffer allocation failed"); 227d722e3fbSopenharmony_ci goto fail; 228d722e3fbSopenharmony_ci } 229d722e3fbSopenharmony_ci 230d722e3fbSopenharmony_ci return ring; 231d722e3fbSopenharmony_cifail: 232d722e3fbSopenharmony_ci if (ring) 233d722e3fbSopenharmony_ci fd_ringbuffer_del(ring); 234d722e3fbSopenharmony_ci return NULL; 235d722e3fbSopenharmony_ci} 236