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