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
drm_tegra_bo_free(struct drm_tegra_bo * bo)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
drm_tegra_wrap(struct drm_tegra ** drmp,int fd,bool close)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
drm_tegra_new(struct drm_tegra ** drmp,int fd)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
drm_tegra_close(struct drm_tegra * drm)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
drm_tegra_bo_new(struct drm_tegra_bo ** bop,struct drm_tegra * drm,uint32_t flags,uint32_t size)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
drm_tegra_bo_wrap(struct drm_tegra_bo ** bop,struct drm_tegra * drm,uint32_t handle,uint32_t flags,uint32_t size)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
drm_tegra_bo_name_ref(struct drm_tegra * drm,uint32_t name,uint32_t size,struct drm_tegra_bo ** bop)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
drm_tegra_bo_name_get(struct drm_tegra_bo * bo,uint32_t * name)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
drm_tegra_bo_ref(struct drm_tegra_bo * bo)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
drm_tegra_bo_unref(struct drm_tegra_bo * bo)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
drm_tegra_bo_get_handle(struct drm_tegra_bo * bo,uint32_t * handle)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
drm_tegra_bo_map(struct drm_tegra_bo * bo,void ** ptr)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
drm_tegra_bo_unmap(struct drm_tegra_bo * bo)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
drm_tegra_bo_get_flags(struct drm_tegra_bo * bo,uint32_t * flags)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
drm_tegra_bo_set_flags(struct drm_tegra_bo * bo,uint32_t flags)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
drm_tegra_bo_get_tiling(struct drm_tegra_bo * bo,struct drm_tegra_bo_tiling * tiling)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
drm_tegra_bo_set_tiling(struct drm_tegra_bo * bo,const struct drm_tegra_bo_tiling * tiling)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