1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2 3 /* 4 * Copyright (C) 2013 Rob Clark <robclark (at) freedesktop.org> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Rob Clark <robclark (at) freedesktop.org> 27 */ 28 29 #ifdef HAVE_CONFIG_H 30 # include <config.h> 31 #endif 32 33 #include "kgsl_priv.h" 34 35 #include <linux/fb.h> 36 37 static int set_memtype(struct fd_device *dev, uint32_t handle, uint32_t flags) 38 { 39 struct drm_kgsl_gem_memtype req = { 40 .handle = handle, 41 .type = flags & DRM_FREEDRENO_GEM_TYPE_MEM_MASK, 42 }; 43 44 return drmCommandWrite(dev->fd, DRM_KGSL_GEM_SETMEMTYPE, 45 &req, sizeof(req)); 46 } 47 48 static int bo_alloc(struct kgsl_bo *kgsl_bo) 49 { 50 struct fd_bo *bo = &kgsl_bo->base; 51 if (!kgsl_bo->offset) { 52 struct drm_kgsl_gem_alloc req = { 53 .handle = bo->handle, 54 }; 55 int ret; 56 57 /* if the buffer is already backed by pages then this 58 * doesn't actually do anything (other than giving us 59 * the offset) 60 */ 61 ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_ALLOC, 62 &req, sizeof(req)); 63 if (ret) { 64 ERROR_MSG("alloc failed: %s", strerror(errno)); 65 return ret; 66 } 67 68 kgsl_bo->offset = req.offset; 69 } 70 71 return 0; 72 } 73 74 static int kgsl_bo_offset(struct fd_bo *bo, uint64_t *offset) 75 { 76 struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); 77 int ret = bo_alloc(kgsl_bo); 78 if (ret) 79 return ret; 80 *offset = kgsl_bo->offset; 81 return 0; 82 } 83 84 static int kgsl_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) 85 { 86 uint32_t timestamp = kgsl_bo_get_timestamp(to_kgsl_bo(bo)); 87 88 if (op & DRM_FREEDRENO_PREP_NOSYNC) { 89 uint32_t current; 90 int ret; 91 92 /* special case for is_idle().. we can't really handle that 93 * properly in kgsl (perhaps we need a way to just disable 94 * the bo-cache for kgsl?) 95 */ 96 if (!pipe) 97 return -EBUSY; 98 99 ret = kgsl_pipe_timestamp(to_kgsl_pipe(pipe), ¤t); 100 if (ret) 101 return ret; 102 103 if (timestamp > current) 104 return -EBUSY; 105 106 return 0; 107 } 108 109 if (timestamp) 110 fd_pipe_wait(pipe, timestamp); 111 112 return 0; 113 } 114 115 static void kgsl_bo_cpu_fini(struct fd_bo *bo) 116 { 117 } 118 119 static int kgsl_bo_madvise(struct fd_bo *bo, int willneed) 120 { 121 return willneed; /* not supported by kgsl */ 122 } 123 124 static void kgsl_bo_destroy(struct fd_bo *bo) 125 { 126 struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); 127 free(kgsl_bo); 128 129 } 130 131 static const struct fd_bo_funcs funcs = { 132 .offset = kgsl_bo_offset, 133 .cpu_prep = kgsl_bo_cpu_prep, 134 .cpu_fini = kgsl_bo_cpu_fini, 135 .madvise = kgsl_bo_madvise, 136 .destroy = kgsl_bo_destroy, 137 }; 138 139 /* allocate a buffer handle: */ 140 drm_private int kgsl_bo_new_handle(struct fd_device *dev, 141 uint32_t size, uint32_t flags, uint32_t *handle) 142 { 143 struct drm_kgsl_gem_create req = { 144 .size = size, 145 }; 146 int ret; 147 148 ret = drmCommandWriteRead(dev->fd, DRM_KGSL_GEM_CREATE, 149 &req, sizeof(req)); 150 if (ret) 151 return ret; 152 153 // TODO make flags match msm driver, since kgsl is legacy.. 154 // translate flags in kgsl.. 155 156 set_memtype(dev, req.handle, flags); 157 158 *handle = req.handle; 159 160 return 0; 161 } 162 163 /* allocate a new buffer object */ 164 drm_private struct fd_bo * kgsl_bo_from_handle(struct fd_device *dev, 165 uint32_t size, uint32_t handle) 166 { 167 struct kgsl_bo *kgsl_bo; 168 struct fd_bo *bo; 169 unsigned i; 170 171 kgsl_bo = calloc(1, sizeof(*kgsl_bo)); 172 if (!kgsl_bo) 173 return NULL; 174 175 bo = &kgsl_bo->base; 176 bo->funcs = &funcs; 177 178 for (i = 0; i < ARRAY_SIZE(kgsl_bo->list); i++) 179 list_inithead(&kgsl_bo->list[i]); 180 181 return bo; 182 } 183 184 struct fd_bo * 185 fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size) 186 { 187 struct fd_bo *bo; 188 189 if (!is_kgsl_pipe(pipe)) 190 return NULL; 191 192 bo = fd_bo_new(pipe->dev, 1, 0); 193 194 /* this is fugly, but works around a bug in the kernel.. 195 * priv->memdesc.size never gets set, so getbufinfo ioctl 196 * thinks the buffer hasn't be allocate and fails 197 */ 198 if (bo) { 199 void *fbmem = drm_mmap(NULL, size, PROT_READ | PROT_WRITE, 200 MAP_SHARED, fbfd, 0); 201 struct kgsl_map_user_mem req = { 202 .memtype = KGSL_USER_MEM_TYPE_ADDR, 203 .len = size, 204 .offset = 0, 205 .hostptr = (unsigned long)fbmem, 206 }; 207 struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); 208 int ret; 209 210 ret = ioctl(to_kgsl_pipe(pipe)->fd, IOCTL_KGSL_MAP_USER_MEM, &req); 211 if (ret) { 212 ERROR_MSG("mapping user mem failed: %s", 213 strerror(errno)); 214 goto fail; 215 } 216 kgsl_bo->gpuaddr = req.gpuaddr; 217 bo->map = fbmem; 218 } 219 220 return bo; 221 fail: 222 if (bo) 223 fd_bo_del(bo); 224 return NULL; 225 } 226 227 drm_private uint32_t kgsl_bo_gpuaddr(struct kgsl_bo *kgsl_bo, uint32_t offset) 228 { 229 struct fd_bo *bo = &kgsl_bo->base; 230 if (!kgsl_bo->gpuaddr) { 231 struct drm_kgsl_gem_bufinfo req = { 232 .handle = bo->handle, 233 }; 234 int ret; 235 236 ret = bo_alloc(kgsl_bo); 237 if (ret) { 238 return ret; 239 } 240 241 ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, 242 &req, sizeof(req)); 243 if (ret) { 244 ERROR_MSG("get bufinfo failed: %s", strerror(errno)); 245 return 0; 246 } 247 248 kgsl_bo->gpuaddr = req.gpuaddr[0]; 249 } 250 return kgsl_bo->gpuaddr + offset; 251 } 252 253 /* 254 * Super-cheezy way to synchronization between mesa and ddx.. the 255 * SET_ACTIVE ioctl gives us a way to stash a 32b # w/ a GEM bo, and 256 * GET_BUFINFO gives us a way to retrieve it. We use this to stash 257 * the timestamp of the last ISSUEIBCMDS on the buffer. 258 * 259 * To avoid an obscene amount of syscalls, we: 260 * 1) Only set the timestamp for buffers w/ an flink name, ie. 261 * only buffers shared across processes. This is enough to 262 * catch the DRI2 buffers. 263 * 2) Only set the timestamp for buffers submitted to the 3d ring 264 * and only check the timestamps on buffers submitted to the 265 * 2d ring. This should be enough to handle synchronizing of 266 * presentation blit. We could do synchronization in the other 267 * direction too, but that would be problematic if we are using 268 * the 3d ring from DDX, since client side wouldn't know this. 269 * 270 * The waiting on timestamp happens before flush, and setting of 271 * timestamp happens after flush. It is transparent to the user 272 * of libdrm_freedreno as all the tracking of buffers happens via 273 * _emit_reloc().. 274 */ 275 276 drm_private void kgsl_bo_set_timestamp(struct kgsl_bo *kgsl_bo, 277 uint32_t timestamp) 278 { 279 struct fd_bo *bo = &kgsl_bo->base; 280 if (bo->name) { 281 struct drm_kgsl_gem_active req = { 282 .handle = bo->handle, 283 .active = timestamp, 284 }; 285 int ret; 286 287 ret = drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_SET_ACTIVE, 288 &req, sizeof(req)); 289 if (ret) { 290 ERROR_MSG("set active failed: %s", strerror(errno)); 291 } 292 } 293 } 294 295 drm_private uint32_t kgsl_bo_get_timestamp(struct kgsl_bo *kgsl_bo) 296 { 297 struct fd_bo *bo = &kgsl_bo->base; 298 uint32_t timestamp = 0; 299 if (bo->name) { 300 struct drm_kgsl_gem_bufinfo req = { 301 .handle = bo->handle, 302 }; 303 int ret; 304 305 ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, 306 &req, sizeof(req)); 307 if (ret) { 308 ERROR_MSG("get bufinfo failed: %s", strerror(errno)); 309 return 0; 310 } 311 312 timestamp = req.active; 313 } 314 return timestamp; 315 } 316