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 int drm_tegra_new(struct drm_tegra **drmp, int fd) 78 { 79 bool supported = false; 80 drmVersionPtr version; 81 82 version = drmGetVersion(fd); 83 if (!version) 84 return -ENOMEM; 85 86 if (!strncmp(version->name, "tegra", version->name_len)) 87 supported = true; 88 89 drmFreeVersion(version); 90 91 if (!supported) 92 return -ENOTSUP; 93 94 return drm_tegra_wrap(drmp, fd, false); 95 } 96 97 void drm_tegra_close(struct drm_tegra *drm) 98 { 99 if (!drm) 100 return; 101 102 if (drm->close) 103 close(drm->fd); 104 105 free(drm); 106 } 107 108 int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm, 109 uint32_t flags, uint32_t size) 110 { 111 struct drm_tegra_gem_create args; 112 struct drm_tegra_bo *bo; 113 int err; 114 115 if (!drm || size == 0 || !bop) 116 return -EINVAL; 117 118 bo = calloc(1, sizeof(*bo)); 119 if (!bo) 120 return -ENOMEM; 121 122 atomic_set(&bo->ref, 1); 123 bo->flags = flags; 124 bo->size = size; 125 bo->drm = drm; 126 127 memset(&args, 0, sizeof(args)); 128 args.flags = flags; 129 args.size = size; 130 131 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args, 132 sizeof(args)); 133 if (err < 0) { 134 err = -errno; 135 free(bo); 136 return err; 137 } 138 139 bo->handle = args.handle; 140 141 *bop = bo; 142 143 return 0; 144 } 145 146 int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm, 147 uint32_t handle, uint32_t flags, uint32_t size) 148 { 149 struct drm_tegra_bo *bo; 150 151 if (!drm || !bop) 152 return -EINVAL; 153 154 bo = calloc(1, sizeof(*bo)); 155 if (!bo) 156 return -ENOMEM; 157 158 atomic_set(&bo->ref, 1); 159 bo->handle = handle; 160 bo->flags = flags; 161 bo->size = size; 162 bo->drm = drm; 163 164 *bop = bo; 165 166 return 0; 167 } 168 169 int drm_tegra_bo_name_ref(struct drm_tegra *drm, uint32_t name, uint32_t size, 170 struct drm_tegra_bo **bop) 171 { 172 struct drm_tegra_bo *bo; 173 struct drm_gem_open open_args; 174 struct drm_gem_close close_args; 175 int ret; 176 177 memset(&open_args, 0, sizeof(open_args)); 178 179 open_args.name = name; 180 181 ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &open_args); 182 if (ret) 183 return ret; 184 185 ret = drm_tegra_bo_wrap(bop, drm, open_args.handle, 0, size); 186 if (ret) 187 goto err; 188 189 (*bop)->name = name; 190 191 return 0; 192 193 err: 194 memset(&close_args, 0, sizeof(close_args)); 195 close_args.handle = open_args.handle; 196 drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &close_args); 197 198 return ret; 199 } 200 201 int drm_tegra_bo_name_get(struct drm_tegra_bo *bo, uint32_t *name) 202 { 203 struct drm_gem_flink args; 204 int ret; 205 206 args.handle = bo->handle; 207 208 *name = bo->name; 209 if (*name && *name != ~0U) 210 return 0; 211 212 ret = drmIoctl(bo->drm->fd, DRM_IOCTL_GEM_FLINK, &args); 213 if (ret) { 214 *name = 0; 215 return ret; 216 } 217 218 bo->name = args.name; 219 *name = bo->name; 220 221 return 0; 222 } 223 224 struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo) 225 { 226 if (bo) 227 atomic_inc(&bo->ref); 228 229 return bo; 230 } 231 232 void drm_tegra_bo_unref(struct drm_tegra_bo *bo) 233 { 234 if (bo && atomic_dec_and_test(&bo->ref)) 235 drm_tegra_bo_free(bo); 236 } 237 238 int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle) 239 { 240 if (!bo || !handle) 241 return -EINVAL; 242 243 *handle = bo->handle; 244 245 return 0; 246 } 247 248 int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr) 249 { 250 struct drm_tegra *drm = bo->drm; 251 252 if (!bo->map) { 253 struct drm_tegra_gem_mmap args; 254 int err; 255 256 memset(&args, 0, sizeof(args)); 257 args.handle = bo->handle; 258 259 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args, 260 sizeof(args)); 261 if (err < 0) 262 return -errno; 263 264 bo->offset = args.offset; 265 266 bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 267 drm->fd, bo->offset); 268 if (bo->map == MAP_FAILED) { 269 bo->map = NULL; 270 return -errno; 271 } 272 } 273 274 if (ptr) 275 *ptr = bo->map; 276 277 return 0; 278 } 279 280 int drm_tegra_bo_unmap(struct drm_tegra_bo *bo) 281 { 282 if (!bo) 283 return -EINVAL; 284 285 if (!bo->map) 286 return 0; 287 288 if (munmap(bo->map, bo->size)) 289 return -errno; 290 291 bo->map = NULL; 292 293 return 0; 294 } 295 296 int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags) 297 { 298 struct drm_tegra_gem_get_flags args; 299 struct drm_tegra *drm = bo->drm; 300 int err; 301 302 if (!bo) 303 return -EINVAL; 304 305 memset(&args, 0, sizeof(args)); 306 args.handle = bo->handle; 307 308 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args, 309 sizeof(args)); 310 if (err < 0) 311 return -errno; 312 313 if (flags) 314 *flags = args.flags; 315 316 return 0; 317 } 318 319 int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags) 320 { 321 struct drm_tegra_gem_get_flags args; 322 struct drm_tegra *drm = bo->drm; 323 int err; 324 325 if (!bo) 326 return -EINVAL; 327 328 memset(&args, 0, sizeof(args)); 329 args.handle = bo->handle; 330 args.flags = flags; 331 332 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args, 333 sizeof(args)); 334 if (err < 0) 335 return -errno; 336 337 return 0; 338 } 339 340 int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo, 341 struct drm_tegra_bo_tiling *tiling) 342 { 343 struct drm_tegra_gem_get_tiling args; 344 struct drm_tegra *drm = bo->drm; 345 int err; 346 347 if (!bo) 348 return -EINVAL; 349 350 memset(&args, 0, sizeof(args)); 351 args.handle = bo->handle; 352 353 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args, 354 sizeof(args)); 355 if (err < 0) 356 return -errno; 357 358 if (tiling) { 359 tiling->mode = args.mode; 360 tiling->value = args.value; 361 } 362 363 return 0; 364 } 365 366 int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo, 367 const struct drm_tegra_bo_tiling *tiling) 368 { 369 struct drm_tegra_gem_set_tiling args; 370 struct drm_tegra *drm = bo->drm; 371 int err; 372 373 if (!bo) 374 return -EINVAL; 375 376 memset(&args, 0, sizeof(args)); 377 args.handle = bo->handle; 378 args.mode = tiling->mode; 379 args.value = tiling->value; 380 381 err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args, 382 sizeof(args)); 383 if (err < 0) 384 return -errno; 385 386 return 0; 387 } 388