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