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 "kgsl_priv.h" 30d722e3fbSopenharmony_ci 31d722e3fbSopenharmony_ci#include <linux/fb.h> 32d722e3fbSopenharmony_ci 33d722e3fbSopenharmony_cistatic int set_memtype(struct fd_device *dev, uint32_t handle, uint32_t flags) 34d722e3fbSopenharmony_ci{ 35d722e3fbSopenharmony_ci struct drm_kgsl_gem_memtype req = { 36d722e3fbSopenharmony_ci .handle = handle, 37d722e3fbSopenharmony_ci .type = flags & DRM_FREEDRENO_GEM_TYPE_MEM_MASK, 38d722e3fbSopenharmony_ci }; 39d722e3fbSopenharmony_ci 40d722e3fbSopenharmony_ci return drmCommandWrite(dev->fd, DRM_KGSL_GEM_SETMEMTYPE, 41d722e3fbSopenharmony_ci &req, sizeof(req)); 42d722e3fbSopenharmony_ci} 43d722e3fbSopenharmony_ci 44d722e3fbSopenharmony_cistatic int bo_alloc(struct kgsl_bo *kgsl_bo) 45d722e3fbSopenharmony_ci{ 46d722e3fbSopenharmony_ci struct fd_bo *bo = &kgsl_bo->base; 47d722e3fbSopenharmony_ci if (!kgsl_bo->offset) { 48d722e3fbSopenharmony_ci struct drm_kgsl_gem_alloc req = { 49d722e3fbSopenharmony_ci .handle = bo->handle, 50d722e3fbSopenharmony_ci }; 51d722e3fbSopenharmony_ci int ret; 52d722e3fbSopenharmony_ci 53d722e3fbSopenharmony_ci /* if the buffer is already backed by pages then this 54d722e3fbSopenharmony_ci * doesn't actually do anything (other than giving us 55d722e3fbSopenharmony_ci * the offset) 56d722e3fbSopenharmony_ci */ 57d722e3fbSopenharmony_ci ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_ALLOC, 58d722e3fbSopenharmony_ci &req, sizeof(req)); 59d722e3fbSopenharmony_ci if (ret) { 60d722e3fbSopenharmony_ci ERROR_MSG("alloc failed: %s", strerror(errno)); 61d722e3fbSopenharmony_ci return ret; 62d722e3fbSopenharmony_ci } 63d722e3fbSopenharmony_ci 64d722e3fbSopenharmony_ci kgsl_bo->offset = req.offset; 65d722e3fbSopenharmony_ci } 66d722e3fbSopenharmony_ci 67d722e3fbSopenharmony_ci return 0; 68d722e3fbSopenharmony_ci} 69d722e3fbSopenharmony_ci 70d722e3fbSopenharmony_cistatic int kgsl_bo_offset(struct fd_bo *bo, uint64_t *offset) 71d722e3fbSopenharmony_ci{ 72d722e3fbSopenharmony_ci struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); 73d722e3fbSopenharmony_ci int ret = bo_alloc(kgsl_bo); 74d722e3fbSopenharmony_ci if (ret) 75d722e3fbSopenharmony_ci return ret; 76d722e3fbSopenharmony_ci *offset = kgsl_bo->offset; 77d722e3fbSopenharmony_ci return 0; 78d722e3fbSopenharmony_ci} 79d722e3fbSopenharmony_ci 80d722e3fbSopenharmony_cistatic int kgsl_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) 81d722e3fbSopenharmony_ci{ 82d722e3fbSopenharmony_ci uint32_t timestamp = kgsl_bo_get_timestamp(to_kgsl_bo(bo)); 83d722e3fbSopenharmony_ci 84d722e3fbSopenharmony_ci if (op & DRM_FREEDRENO_PREP_NOSYNC) { 85d722e3fbSopenharmony_ci uint32_t current; 86d722e3fbSopenharmony_ci int ret; 87d722e3fbSopenharmony_ci 88d722e3fbSopenharmony_ci /* special case for is_idle().. we can't really handle that 89d722e3fbSopenharmony_ci * properly in kgsl (perhaps we need a way to just disable 90d722e3fbSopenharmony_ci * the bo-cache for kgsl?) 91d722e3fbSopenharmony_ci */ 92d722e3fbSopenharmony_ci if (!pipe) 93d722e3fbSopenharmony_ci return -EBUSY; 94d722e3fbSopenharmony_ci 95d722e3fbSopenharmony_ci ret = kgsl_pipe_timestamp(to_kgsl_pipe(pipe), ¤t); 96d722e3fbSopenharmony_ci if (ret) 97d722e3fbSopenharmony_ci return ret; 98d722e3fbSopenharmony_ci 99d722e3fbSopenharmony_ci if (timestamp > current) 100d722e3fbSopenharmony_ci return -EBUSY; 101d722e3fbSopenharmony_ci 102d722e3fbSopenharmony_ci return 0; 103d722e3fbSopenharmony_ci } 104d722e3fbSopenharmony_ci 105d722e3fbSopenharmony_ci if (timestamp) 106d722e3fbSopenharmony_ci fd_pipe_wait(pipe, timestamp); 107d722e3fbSopenharmony_ci 108d722e3fbSopenharmony_ci return 0; 109d722e3fbSopenharmony_ci} 110d722e3fbSopenharmony_ci 111d722e3fbSopenharmony_cistatic void kgsl_bo_cpu_fini(struct fd_bo *bo) 112d722e3fbSopenharmony_ci{ 113d722e3fbSopenharmony_ci} 114d722e3fbSopenharmony_ci 115d722e3fbSopenharmony_cistatic int kgsl_bo_madvise(struct fd_bo *bo, int willneed) 116d722e3fbSopenharmony_ci{ 117d722e3fbSopenharmony_ci return willneed; /* not supported by kgsl */ 118d722e3fbSopenharmony_ci} 119d722e3fbSopenharmony_ci 120d722e3fbSopenharmony_cistatic void kgsl_bo_destroy(struct fd_bo *bo) 121d722e3fbSopenharmony_ci{ 122d722e3fbSopenharmony_ci struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); 123d722e3fbSopenharmony_ci free(kgsl_bo); 124d722e3fbSopenharmony_ci 125d722e3fbSopenharmony_ci} 126d722e3fbSopenharmony_ci 127d722e3fbSopenharmony_cistatic const struct fd_bo_funcs funcs = { 128d722e3fbSopenharmony_ci .offset = kgsl_bo_offset, 129d722e3fbSopenharmony_ci .cpu_prep = kgsl_bo_cpu_prep, 130d722e3fbSopenharmony_ci .cpu_fini = kgsl_bo_cpu_fini, 131d722e3fbSopenharmony_ci .madvise = kgsl_bo_madvise, 132d722e3fbSopenharmony_ci .destroy = kgsl_bo_destroy, 133d722e3fbSopenharmony_ci}; 134d722e3fbSopenharmony_ci 135d722e3fbSopenharmony_ci/* allocate a buffer handle: */ 136d722e3fbSopenharmony_cidrm_private int kgsl_bo_new_handle(struct fd_device *dev, 137d722e3fbSopenharmony_ci uint32_t size, uint32_t flags, uint32_t *handle) 138d722e3fbSopenharmony_ci{ 139d722e3fbSopenharmony_ci struct drm_kgsl_gem_create req = { 140d722e3fbSopenharmony_ci .size = size, 141d722e3fbSopenharmony_ci }; 142d722e3fbSopenharmony_ci int ret; 143d722e3fbSopenharmony_ci 144d722e3fbSopenharmony_ci ret = drmCommandWriteRead(dev->fd, DRM_KGSL_GEM_CREATE, 145d722e3fbSopenharmony_ci &req, sizeof(req)); 146d722e3fbSopenharmony_ci if (ret) 147d722e3fbSopenharmony_ci return ret; 148d722e3fbSopenharmony_ci 149d722e3fbSopenharmony_ci // TODO make flags match msm driver, since kgsl is legacy.. 150d722e3fbSopenharmony_ci // translate flags in kgsl.. 151d722e3fbSopenharmony_ci 152d722e3fbSopenharmony_ci set_memtype(dev, req.handle, flags); 153d722e3fbSopenharmony_ci 154d722e3fbSopenharmony_ci *handle = req.handle; 155d722e3fbSopenharmony_ci 156d722e3fbSopenharmony_ci return 0; 157d722e3fbSopenharmony_ci} 158d722e3fbSopenharmony_ci 159d722e3fbSopenharmony_ci/* allocate a new buffer object */ 160d722e3fbSopenharmony_cidrm_private struct fd_bo * kgsl_bo_from_handle(struct fd_device *dev, 161d722e3fbSopenharmony_ci uint32_t size, uint32_t handle) 162d722e3fbSopenharmony_ci{ 163d722e3fbSopenharmony_ci struct kgsl_bo *kgsl_bo; 164d722e3fbSopenharmony_ci struct fd_bo *bo; 165d722e3fbSopenharmony_ci unsigned i; 166d722e3fbSopenharmony_ci 167d722e3fbSopenharmony_ci kgsl_bo = calloc(1, sizeof(*kgsl_bo)); 168d722e3fbSopenharmony_ci if (!kgsl_bo) 169d722e3fbSopenharmony_ci return NULL; 170d722e3fbSopenharmony_ci 171d722e3fbSopenharmony_ci bo = &kgsl_bo->base; 172d722e3fbSopenharmony_ci bo->funcs = &funcs; 173d722e3fbSopenharmony_ci 174d722e3fbSopenharmony_ci for (i = 0; i < ARRAY_SIZE(kgsl_bo->list); i++) 175d722e3fbSopenharmony_ci list_inithead(&kgsl_bo->list[i]); 176d722e3fbSopenharmony_ci 177d722e3fbSopenharmony_ci return bo; 178d722e3fbSopenharmony_ci} 179d722e3fbSopenharmony_ci 180d722e3fbSopenharmony_cidrm_public struct fd_bo * 181d722e3fbSopenharmony_cifd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size) 182d722e3fbSopenharmony_ci{ 183d722e3fbSopenharmony_ci struct fd_bo *bo; 184d722e3fbSopenharmony_ci 185d722e3fbSopenharmony_ci if (!is_kgsl_pipe(pipe)) 186d722e3fbSopenharmony_ci return NULL; 187d722e3fbSopenharmony_ci 188d722e3fbSopenharmony_ci bo = fd_bo_new(pipe->dev, 1, 0); 189d722e3fbSopenharmony_ci 190d722e3fbSopenharmony_ci /* this is fugly, but works around a bug in the kernel.. 191d722e3fbSopenharmony_ci * priv->memdesc.size never gets set, so getbufinfo ioctl 192d722e3fbSopenharmony_ci * thinks the buffer hasn't be allocate and fails 193d722e3fbSopenharmony_ci */ 194d722e3fbSopenharmony_ci if (bo) { 195d722e3fbSopenharmony_ci void *fbmem = drm_mmap(NULL, size, PROT_READ | PROT_WRITE, 196d722e3fbSopenharmony_ci MAP_SHARED, fbfd, 0); 197d722e3fbSopenharmony_ci struct kgsl_map_user_mem req = { 198d722e3fbSopenharmony_ci .memtype = KGSL_USER_MEM_TYPE_ADDR, 199d722e3fbSopenharmony_ci .len = size, 200d722e3fbSopenharmony_ci .offset = 0, 201d722e3fbSopenharmony_ci .hostptr = (unsigned long)fbmem, 202d722e3fbSopenharmony_ci }; 203d722e3fbSopenharmony_ci struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); 204d722e3fbSopenharmony_ci int ret; 205d722e3fbSopenharmony_ci 206d722e3fbSopenharmony_ci ret = ioctl(to_kgsl_pipe(pipe)->fd, IOCTL_KGSL_MAP_USER_MEM, &req); 207d722e3fbSopenharmony_ci if (ret) { 208d722e3fbSopenharmony_ci ERROR_MSG("mapping user mem failed: %s", 209d722e3fbSopenharmony_ci strerror(errno)); 210d722e3fbSopenharmony_ci goto fail; 211d722e3fbSopenharmony_ci } 212d722e3fbSopenharmony_ci kgsl_bo->gpuaddr = req.gpuaddr; 213d722e3fbSopenharmony_ci bo->map = fbmem; 214d722e3fbSopenharmony_ci } 215d722e3fbSopenharmony_ci 216d722e3fbSopenharmony_ci return bo; 217d722e3fbSopenharmony_cifail: 218d722e3fbSopenharmony_ci if (bo) 219d722e3fbSopenharmony_ci fd_bo_del(bo); 220d722e3fbSopenharmony_ci return NULL; 221d722e3fbSopenharmony_ci} 222d722e3fbSopenharmony_ci 223d722e3fbSopenharmony_cidrm_private uint32_t kgsl_bo_gpuaddr(struct kgsl_bo *kgsl_bo, uint32_t offset) 224d722e3fbSopenharmony_ci{ 225d722e3fbSopenharmony_ci struct fd_bo *bo = &kgsl_bo->base; 226d722e3fbSopenharmony_ci if (!kgsl_bo->gpuaddr) { 227d722e3fbSopenharmony_ci struct drm_kgsl_gem_bufinfo req = { 228d722e3fbSopenharmony_ci .handle = bo->handle, 229d722e3fbSopenharmony_ci }; 230d722e3fbSopenharmony_ci int ret; 231d722e3fbSopenharmony_ci 232d722e3fbSopenharmony_ci ret = bo_alloc(kgsl_bo); 233d722e3fbSopenharmony_ci if (ret) { 234d722e3fbSopenharmony_ci return ret; 235d722e3fbSopenharmony_ci } 236d722e3fbSopenharmony_ci 237d722e3fbSopenharmony_ci ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, 238d722e3fbSopenharmony_ci &req, sizeof(req)); 239d722e3fbSopenharmony_ci if (ret) { 240d722e3fbSopenharmony_ci ERROR_MSG("get bufinfo failed: %s", strerror(errno)); 241d722e3fbSopenharmony_ci return 0; 242d722e3fbSopenharmony_ci } 243d722e3fbSopenharmony_ci 244d722e3fbSopenharmony_ci kgsl_bo->gpuaddr = req.gpuaddr[0]; 245d722e3fbSopenharmony_ci } 246d722e3fbSopenharmony_ci return kgsl_bo->gpuaddr + offset; 247d722e3fbSopenharmony_ci} 248d722e3fbSopenharmony_ci 249d722e3fbSopenharmony_ci/* 250d722e3fbSopenharmony_ci * Super-cheezy way to synchronization between mesa and ddx.. the 251d722e3fbSopenharmony_ci * SET_ACTIVE ioctl gives us a way to stash a 32b # w/ a GEM bo, and 252d722e3fbSopenharmony_ci * GET_BUFINFO gives us a way to retrieve it. We use this to stash 253d722e3fbSopenharmony_ci * the timestamp of the last ISSUEIBCMDS on the buffer. 254d722e3fbSopenharmony_ci * 255d722e3fbSopenharmony_ci * To avoid an obscene amount of syscalls, we: 256d722e3fbSopenharmony_ci * 1) Only set the timestamp for buffers w/ an flink name, ie. 257d722e3fbSopenharmony_ci * only buffers shared across processes. This is enough to 258d722e3fbSopenharmony_ci * catch the DRI2 buffers. 259d722e3fbSopenharmony_ci * 2) Only set the timestamp for buffers submitted to the 3d ring 260d722e3fbSopenharmony_ci * and only check the timestamps on buffers submitted to the 261d722e3fbSopenharmony_ci * 2d ring. This should be enough to handle synchronizing of 262d722e3fbSopenharmony_ci * presentation blit. We could do synchronization in the other 263d722e3fbSopenharmony_ci * direction too, but that would be problematic if we are using 264d722e3fbSopenharmony_ci * the 3d ring from DDX, since client side wouldn't know this. 265d722e3fbSopenharmony_ci * 266d722e3fbSopenharmony_ci * The waiting on timestamp happens before flush, and setting of 267d722e3fbSopenharmony_ci * timestamp happens after flush. It is transparent to the user 268d722e3fbSopenharmony_ci * of libdrm_freedreno as all the tracking of buffers happens via 269d722e3fbSopenharmony_ci * _emit_reloc().. 270d722e3fbSopenharmony_ci */ 271d722e3fbSopenharmony_ci 272d722e3fbSopenharmony_cidrm_private void kgsl_bo_set_timestamp(struct kgsl_bo *kgsl_bo, 273d722e3fbSopenharmony_ci uint32_t timestamp) 274d722e3fbSopenharmony_ci{ 275d722e3fbSopenharmony_ci struct fd_bo *bo = &kgsl_bo->base; 276d722e3fbSopenharmony_ci if (bo->name) { 277d722e3fbSopenharmony_ci struct drm_kgsl_gem_active req = { 278d722e3fbSopenharmony_ci .handle = bo->handle, 279d722e3fbSopenharmony_ci .active = timestamp, 280d722e3fbSopenharmony_ci }; 281d722e3fbSopenharmony_ci int ret; 282d722e3fbSopenharmony_ci 283d722e3fbSopenharmony_ci ret = drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_SET_ACTIVE, 284d722e3fbSopenharmony_ci &req, sizeof(req)); 285d722e3fbSopenharmony_ci if (ret) { 286d722e3fbSopenharmony_ci ERROR_MSG("set active failed: %s", strerror(errno)); 287d722e3fbSopenharmony_ci } 288d722e3fbSopenharmony_ci } 289d722e3fbSopenharmony_ci} 290d722e3fbSopenharmony_ci 291d722e3fbSopenharmony_cidrm_private uint32_t kgsl_bo_get_timestamp(struct kgsl_bo *kgsl_bo) 292d722e3fbSopenharmony_ci{ 293d722e3fbSopenharmony_ci struct fd_bo *bo = &kgsl_bo->base; 294d722e3fbSopenharmony_ci uint32_t timestamp = 0; 295d722e3fbSopenharmony_ci if (bo->name) { 296d722e3fbSopenharmony_ci struct drm_kgsl_gem_bufinfo req = { 297d722e3fbSopenharmony_ci .handle = bo->handle, 298d722e3fbSopenharmony_ci }; 299d722e3fbSopenharmony_ci int ret; 300d722e3fbSopenharmony_ci 301d722e3fbSopenharmony_ci ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, 302d722e3fbSopenharmony_ci &req, sizeof(req)); 303d722e3fbSopenharmony_ci if (ret) { 304d722e3fbSopenharmony_ci ERROR_MSG("get bufinfo failed: %s", strerror(errno)); 305d722e3fbSopenharmony_ci return 0; 306d722e3fbSopenharmony_ci } 307d722e3fbSopenharmony_ci 308d722e3fbSopenharmony_ci timestamp = req.active; 309d722e3fbSopenharmony_ci } 310d722e3fbSopenharmony_ci return timestamp; 311d722e3fbSopenharmony_ci} 312