• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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