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