1 /* 2 * Copyright 2008 Dave Airlie 3 * Copyright 2008 Jrme Glisse 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 16 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS 18 * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * The above copyright notice and this permission notice (including the 24 * next paragraph) shall be included in all copies or substantial portions 25 * of the Software. 26 */ 27 /* 28 * Authors: 29 * Dave Airlie 30 * Jrme Glisse <glisse (at) freedesktop.org> 31 */ 32 #include <stdio.h> 33 #include <stdint.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <errno.h> 37 #include "libdrm_macros.h" 38 #include "xf86drm.h" 39 #include "xf86atomic.h" 40 #include "drm.h" 41 #include "radeon_drm.h" 42 #include "radeon_bo.h" 43 #include "radeon_bo_int.h" 44 #include "radeon_bo_gem.h" 45 #include <fcntl.h> 46 struct radeon_bo_gem { 47 struct radeon_bo_int base; 48 uint32_t name; 49 int map_count; 50 atomic_t reloc_in_cs; 51 void *priv_ptr; 52 }; 53 54 struct bo_manager_gem { 55 struct radeon_bo_manager base; 56 }; 57 58 static int bo_wait(struct radeon_bo_int *boi); 59 60 static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, 61 uint32_t handle, 62 uint32_t size, 63 uint32_t alignment, 64 uint32_t domains, 65 uint32_t flags) 66 { 67 struct radeon_bo_gem *bo; 68 int r; 69 70 bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem)); 71 if (bo == NULL) { 72 return NULL; 73 } 74 75 bo->base.bom = bom; 76 bo->base.handle = 0; 77 bo->base.size = size; 78 bo->base.alignment = alignment; 79 bo->base.domains = domains; 80 bo->base.flags = flags; 81 bo->base.ptr = NULL; 82 atomic_set(&bo->reloc_in_cs, 0); 83 bo->map_count = 0; 84 if (handle) { 85 struct drm_gem_open open_arg; 86 87 memset(&open_arg, 0, sizeof(open_arg)); 88 open_arg.name = handle; 89 r = drmIoctl(bom->fd, DRM_IOCTL_GEM_OPEN, &open_arg); 90 if (r != 0) { 91 free(bo); 92 return NULL; 93 } 94 bo->base.handle = open_arg.handle; 95 bo->base.size = open_arg.size; 96 bo->name = handle; 97 } else { 98 struct drm_radeon_gem_create args; 99 100 args.size = size; 101 args.alignment = alignment; 102 args.initial_domain = bo->base.domains; 103 args.flags = flags; 104 args.handle = 0; 105 r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE, 106 &args, sizeof(args)); 107 bo->base.handle = args.handle; 108 if (r) { 109 fprintf(stderr, "Failed to allocate :\n"); 110 fprintf(stderr, " size : %d bytes\n", size); 111 fprintf(stderr, " alignment : %d bytes\n", alignment); 112 fprintf(stderr, " domains : %d\n", bo->base.domains); 113 free(bo); 114 return NULL; 115 } 116 } 117 radeon_bo_ref((struct radeon_bo*)bo); 118 return (struct radeon_bo*)bo; 119 } 120 121 static void bo_ref(struct radeon_bo_int *boi) 122 { 123 } 124 125 static struct radeon_bo *bo_unref(struct radeon_bo_int *boi) 126 { 127 struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi; 128 struct drm_gem_close args; 129 130 if (boi->cref) { 131 return (struct radeon_bo *)boi; 132 } 133 if (bo_gem->priv_ptr) { 134 drm_munmap(bo_gem->priv_ptr, boi->size); 135 } 136 137 /* Zero out args to make valgrind happy */ 138 memset(&args, 0, sizeof(args)); 139 140 /* close object */ 141 args.handle = boi->handle; 142 drmIoctl(boi->bom->fd, DRM_IOCTL_GEM_CLOSE, &args); 143 memset(bo_gem, 0, sizeof(struct radeon_bo_gem)); 144 free(bo_gem); 145 return NULL; 146 } 147 148 static int bo_map(struct radeon_bo_int *boi, int write) 149 { 150 struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi; 151 struct drm_radeon_gem_mmap args; 152 int r; 153 void *ptr; 154 155 if (bo_gem->map_count++ != 0) { 156 return 0; 157 } 158 if (bo_gem->priv_ptr) { 159 goto wait; 160 } 161 162 boi->ptr = NULL; 163 164 /* Zero out args to make valgrind happy */ 165 memset(&args, 0, sizeof(args)); 166 args.handle = boi->handle; 167 args.offset = 0; 168 args.size = (uint64_t)boi->size; 169 r = drmCommandWriteRead(boi->bom->fd, 170 DRM_RADEON_GEM_MMAP, 171 &args, 172 sizeof(args)); 173 if (r) { 174 fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n", 175 boi, boi->handle, r); 176 return r; 177 } 178 ptr = drm_mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, boi->bom->fd, args.addr_ptr); 179 if (ptr == MAP_FAILED) 180 return -errno; 181 bo_gem->priv_ptr = ptr; 182 wait: 183 boi->ptr = bo_gem->priv_ptr; 184 r = bo_wait(boi); 185 if (r) 186 return r; 187 return 0; 188 } 189 190 static int bo_unmap(struct radeon_bo_int *boi) 191 { 192 struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi; 193 194 if (--bo_gem->map_count > 0) { 195 return 0; 196 } 197 //drm_munmap(bo->ptr, bo->size); 198 boi->ptr = NULL; 199 return 0; 200 } 201 202 static int bo_wait(struct radeon_bo_int *boi) 203 { 204 struct drm_radeon_gem_wait_idle args; 205 int ret; 206 207 /* Zero out args to make valgrind happy */ 208 memset(&args, 0, sizeof(args)); 209 args.handle = boi->handle; 210 do { 211 ret = drmCommandWrite(boi->bom->fd, DRM_RADEON_GEM_WAIT_IDLE, 212 &args, sizeof(args)); 213 } while (ret == -EBUSY); 214 return ret; 215 } 216 217 static int bo_is_busy(struct radeon_bo_int *boi, uint32_t *domain) 218 { 219 struct drm_radeon_gem_busy args; 220 int ret; 221 222 args.handle = boi->handle; 223 args.domain = 0; 224 225 ret = drmCommandWriteRead(boi->bom->fd, DRM_RADEON_GEM_BUSY, 226 &args, sizeof(args)); 227 228 *domain = args.domain; 229 return ret; 230 } 231 232 static int bo_set_tiling(struct radeon_bo_int *boi, uint32_t tiling_flags, 233 uint32_t pitch) 234 { 235 struct drm_radeon_gem_set_tiling args; 236 int r; 237 238 args.handle = boi->handle; 239 args.tiling_flags = tiling_flags; 240 args.pitch = pitch; 241 242 r = drmCommandWriteRead(boi->bom->fd, 243 DRM_RADEON_GEM_SET_TILING, 244 &args, 245 sizeof(args)); 246 return r; 247 } 248 249 static int bo_get_tiling(struct radeon_bo_int *boi, uint32_t *tiling_flags, 250 uint32_t *pitch) 251 { 252 struct drm_radeon_gem_set_tiling args = {}; 253 int r; 254 255 args.handle = boi->handle; 256 257 r = drmCommandWriteRead(boi->bom->fd, 258 DRM_RADEON_GEM_GET_TILING, 259 &args, 260 sizeof(args)); 261 262 if (r) 263 return r; 264 265 *tiling_flags = args.tiling_flags; 266 *pitch = args.pitch; 267 return r; 268 } 269 270 static const struct radeon_bo_funcs bo_gem_funcs = { 271 .bo_open = bo_open, 272 .bo_ref = bo_ref, 273 .bo_unref = bo_unref, 274 .bo_map = bo_map, 275 .bo_unmap = bo_unmap, 276 .bo_wait = bo_wait, 277 .bo_is_static = NULL, 278 .bo_set_tiling = bo_set_tiling, 279 .bo_get_tiling = bo_get_tiling, 280 .bo_is_busy = bo_is_busy, 281 .bo_is_referenced_by_cs = NULL, 282 }; 283 284 struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd) 285 { 286 struct bo_manager_gem *bomg; 287 288 bomg = (struct bo_manager_gem*)calloc(1, sizeof(struct bo_manager_gem)); 289 if (bomg == NULL) { 290 return NULL; 291 } 292 bomg->base.funcs = &bo_gem_funcs; 293 bomg->base.fd = fd; 294 return (struct radeon_bo_manager*)bomg; 295 } 296 297 void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom) 298 { 299 struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom; 300 301 if (bom == NULL) { 302 return; 303 } 304 free(bomg); 305 } 306 307 uint32_t 308 radeon_gem_name_bo(struct radeon_bo *bo) 309 { 310 struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; 311 return bo_gem->name; 312 } 313 314 void * 315 radeon_gem_get_reloc_in_cs(struct radeon_bo *bo) 316 { 317 struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; 318 return &bo_gem->reloc_in_cs; 319 } 320 321 int 322 radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name) 323 { 324 struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; 325 struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; 326 struct drm_gem_flink flink; 327 int r; 328 329 if (bo_gem->name) { 330 *name = bo_gem->name; 331 return 0; 332 } 333 flink.handle = bo->handle; 334 r = drmIoctl(boi->bom->fd, DRM_IOCTL_GEM_FLINK, &flink); 335 if (r) { 336 return r; 337 } 338 bo_gem->name = flink.name; 339 *name = flink.name; 340 return 0; 341 } 342 343 int 344 radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain) 345 { 346 struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; 347 struct drm_radeon_gem_set_domain args; 348 int r; 349 350 args.handle = bo->handle; 351 args.read_domains = read_domains; 352 args.write_domain = write_domain; 353 354 r = drmCommandWriteRead(boi->bom->fd, 355 DRM_RADEON_GEM_SET_DOMAIN, 356 &args, 357 sizeof(args)); 358 return r; 359 } 360 361 int radeon_gem_prime_share_bo(struct radeon_bo *bo, int *handle) 362 { 363 struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; 364 int ret; 365 366 ret = drmPrimeHandleToFD(bo_gem->base.bom->fd, bo->handle, DRM_CLOEXEC, handle); 367 return ret; 368 } 369 370 struct radeon_bo * 371 radeon_gem_bo_open_prime(struct radeon_bo_manager *bom, int fd_handle, uint32_t size) 372 { 373 struct radeon_bo_gem *bo; 374 int r; 375 uint32_t handle; 376 377 bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem)); 378 if (bo == NULL) { 379 return NULL; 380 } 381 382 bo->base.bom = bom; 383 bo->base.handle = 0; 384 bo->base.size = size; 385 bo->base.alignment = 0; 386 bo->base.domains = RADEON_GEM_DOMAIN_GTT; 387 bo->base.flags = 0; 388 bo->base.ptr = NULL; 389 atomic_set(&bo->reloc_in_cs, 0); 390 bo->map_count = 0; 391 392 r = drmPrimeFDToHandle(bom->fd, fd_handle, &handle); 393 if (r != 0) { 394 free(bo); 395 return NULL; 396 } 397 398 bo->base.handle = handle; 399 bo->name = handle; 400 401 radeon_bo_ref((struct radeon_bo *)bo); 402 return (struct radeon_bo *)bo; 403 404 } 405