1 /* 2 * Copyright 2012, 2013 Thierry Reding 3 * Copyright 2013 Erik Faye-Lund 4 * Copyright 2014 NVIDIA Corporation 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 shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #ifdef HAVE_CONFIG_H 26 # include "config.h" 27 #endif 28 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #include <sys/mman.h> 35 36 #include <xf86drm.h> 37 38 #include <tegra_drm.h> 39 40 #include "private.h" 41 42 static void drm_tegra_bo_free(struct drm_tegra_bo *bo) 43 { 44 struct drm_tegra *drm = bo->drm; 45 struct drm_gem_close args; 46 47 if (bo->map) 48 munmap(bo->map, bo->size); 49 50 memset(&args, 0, sizeof(args)); 51 args.handle = bo->handle; 52 53 drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args); 54 55 free(bo); 56 } 57 58 static int drm_tegra_wrap(struct drm_tegra **drmp, int fd, bool close) 59 { 60 struct drm_tegra *drm; 61 62 if (fd < 0 || !drmp) 63 return -EINVAL; 64 65 drm = calloc(1, sizeof(*drm)); 66 if (!drm) 67 return -ENOMEM; 68 69 drm->close = close; 70 drm->fd = fd; 71 72 *drmp = drm; 73 74 return 0; 75 } 76 77 drm_public 78 int drm_tegra_new(struct drm_tegra **drmp, int fd) 79 { 80 bool supported = false; 81 drmVersionPtr version; 82 83 version = drmGetVersion(fd); 84 if (!version) 85 return -ENOMEM; 86 87 if (!strncmp(version->name, "tegra", version->name_len)) 88 supported = true; 89 90 drmFreeVersion(version); 91 92 if (!supported) 93 return -ENOTSUP; 94 95 return drm_tegra_wrap(drmp, fd, false); 96 } 97 98 drm_public 99 void drm_tegra_close(struct drm_tegra *drm) 100 { 101 if (!drm) 102 return; 103 104 if (drm->close) 105 close(drm->fd); 106 107 free(drm); 108 } 109 110 drm_public 111 int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm, 112 uint32_t flags, uint32_t size) 113 { 114 struct drm_tegra_gem_create args; 115 struct drm_tegra_bo *bo; 116 int err; 117 118 if (!drm || size == 0 || !bop) 119 return -EINVAL; 120 121 bo = calloc(1, sizeof(*bo)); 122 if (!bo) 123 return -ENOMEM; 124 125 atomic_set(&bo->ref, 1); 126 bo->flags = flags; 127 bo->size = size; 128 bo->drm = drm; 129 130 memset(&args, 0, sizeof(args)); 131 args.flags = flags; 132 args.size = size; 133 134 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args, 135 sizeof(args)); 136 if (err < 0) { 137 err = -errno; 138 free(bo); 139 return err; 140 } 141 142 bo->handle = args.handle; 143 144 *bop = bo; 145 146 return 0; 147 } 148 149 drm_public 150 int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm, 151 uint32_t handle, uint32_t flags, uint32_t size) 152 { 153 struct drm_tegra_bo *bo; 154 155 if (!drm || !bop) 156 return -EINVAL; 157 158 bo = calloc(1, sizeof(*bo)); 159 if (!bo) 160 return -ENOMEM; 161 162 atomic_set(&bo->ref, 1); 163 bo->handle = handle; 164 bo->flags = flags; 165 bo->size = size; 166 bo->drm = drm; 167 168 *bop = bo; 169 170 return 0; 171 } 172 173 drm_public 174 int drm_tegra_bo_name_ref(struct drm_tegra *drm, uint32_t name, uint32_t size, 175 struct drm_tegra_bo **bop) 176 { 177 struct drm_tegra_bo *bo; 178 struct drm_gem_open open_args; 179 struct drm_gem_close close_args; 180 int ret; 181 182 memset(&open_args, 0, sizeof(open_args)); 183 184 open_args.name = name; 185 186 ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &open_args); 187 if (ret) 188 return ret; 189 190 ret = drm_tegra_bo_wrap(bop, drm, open_args.handle, 0, size); 191 if (ret) 192 goto err; 193 194 (*bop)->name = name; 195 196 return 0; 197 198 err: 199 memset(&close_args, 0, sizeof(close_args)); 200 close_args.handle = open_args.handle; 201 drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &close_args); 202 203 return ret; 204 } 205 206 drm_public 207 int drm_tegra_bo_name_get(struct drm_tegra_bo *bo, uint32_t *name) 208 { 209 struct drm_gem_flink args; 210 int ret; 211 212 args.handle = bo->handle; 213 214 *name = bo->name; 215 if (*name && *name != ~0U) 216 return 0; 217 218 ret = drmIoctl(bo->drm->fd, DRM_IOCTL_GEM_FLINK, &args); 219 if (ret) { 220 *name = 0; 221 return ret; 222 } 223 224 bo->name = args.name; 225 *name = bo->name; 226 227 return 0; 228 } 229 230 drm_public 231 struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo) 232 { 233 if (bo) 234 atomic_inc(&bo->ref); 235 236 return bo; 237 } 238 239 drm_public 240 void drm_tegra_bo_unref(struct drm_tegra_bo *bo) 241 { 242 if (bo && atomic_dec_and_test(&bo->ref)) 243 drm_tegra_bo_free(bo); 244 } 245 246 drm_public 247 int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle) 248 { 249 if (!bo || !handle) 250 return -EINVAL; 251 252 *handle = bo->handle; 253 254 return 0; 255 } 256 257 drm_public 258 int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr) 259 { 260 struct drm_tegra *drm = bo->drm; 261 262 if (!bo->map) { 263 struct drm_tegra_gem_mmap args; 264 int err; 265 266 memset(&args, 0, sizeof(args)); 267 args.handle = bo->handle; 268 269 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args, 270 sizeof(args)); 271 if (err < 0) 272 return -errno; 273 274 bo->offset = args.offset; 275 276 bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 277 drm->fd, bo->offset); 278 if (bo->map == MAP_FAILED) { 279 bo->map = NULL; 280 return -errno; 281 } 282 } 283 284 if (ptr) 285 *ptr = bo->map; 286 287 return 0; 288 } 289 290 drm_public 291 int drm_tegra_bo_unmap(struct drm_tegra_bo *bo) 292 { 293 if (!bo) 294 return -EINVAL; 295 296 if (!bo->map) 297 return 0; 298 299 if (munmap(bo->map, bo->size)) 300 return -errno; 301 302 bo->map = NULL; 303 304 return 0; 305 } 306 307 drm_public 308 int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags) 309 { 310 struct drm_tegra_gem_get_flags args; 311 struct drm_tegra *drm = bo->drm; 312 int err; 313 314 if (!bo) 315 return -EINVAL; 316 317 memset(&args, 0, sizeof(args)); 318 args.handle = bo->handle; 319 320 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args, 321 sizeof(args)); 322 if (err < 0) 323 return -errno; 324 325 if (flags) 326 *flags = args.flags; 327 328 return 0; 329 } 330 331 drm_public 332 int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags) 333 { 334 struct drm_tegra_gem_get_flags args; 335 struct drm_tegra *drm = bo->drm; 336 int err; 337 338 if (!bo) 339 return -EINVAL; 340 341 memset(&args, 0, sizeof(args)); 342 args.handle = bo->handle; 343 args.flags = flags; 344 345 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args, 346 sizeof(args)); 347 if (err < 0) 348 return -errno; 349 350 return 0; 351 } 352 353 drm_public 354 int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo, 355 struct drm_tegra_bo_tiling *tiling) 356 { 357 struct drm_tegra_gem_get_tiling args; 358 struct drm_tegra *drm = bo->drm; 359 int err; 360 361 if (!bo) 362 return -EINVAL; 363 364 memset(&args, 0, sizeof(args)); 365 args.handle = bo->handle; 366 367 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args, 368 sizeof(args)); 369 if (err < 0) 370 return -errno; 371 372 if (tiling) { 373 tiling->mode = args.mode; 374 tiling->value = args.value; 375 } 376 377 return 0; 378 } 379 380 drm_public 381 int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo, 382 const struct drm_tegra_bo_tiling *tiling) 383 { 384 struct drm_tegra_gem_set_tiling args; 385 struct drm_tegra *drm = bo->drm; 386 int err; 387 388 if (!bo) 389 return -EINVAL; 390 391 memset(&args, 0, sizeof(args)); 392 args.handle = bo->handle; 393 args.mode = tiling->mode; 394 args.value = tiling->value; 395 396 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args, 397 sizeof(args)); 398 if (err < 0) 399 return -errno; 400 401 return 0; 402 } 403