• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2016 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "igt.h"
25 #include "igt_kmod.h"
26 #include "igt_vgem.h"
27 #include "igt_debugfs.h"
28 #include "igt_sysfs.h"
29 
30 #include <sys/mman.h>
31 #include <sys/poll.h>
32 #include <sys/stat.h>
33 #include <dirent.h>
34 
35 IGT_TEST_DESCRIPTION("Basic sanity check of Virtual GEM module (vGEM).");
36 
__gem_setversion(int fd,drm_set_version_t * sv)37 static int __gem_setversion(int fd, drm_set_version_t *sv)
38 {
39 	int err;
40 
41 	err = 0;
42 	if (igt_ioctl(fd, DRM_IOCTL_SET_VERSION, sv))
43 		err = -errno;
44 	errno = 0;
45 
46 	return err;
47 }
48 
test_setversion(int fd)49 static void test_setversion(int fd)
50 {
51 	drm_set_version_t sv;
52 
53 	memset(&sv, 0, sizeof(sv));
54 	sv.drm_di_major = 1; /* must be equal to DRM_IF_MAJOR */
55 	sv.drm_di_minor = 4; /* must be less than DRM_IF_MINOR */
56 	sv.drm_dd_major = -1; /* don't care */
57 	sv.drm_dd_minor = -1; /* don't care */
58 	igt_assert_eq(__gem_setversion(fd, &sv), 0);
59 
60 	igt_info("vgem DRM interface v%d.%d, device v%d.%d\n",
61 		 sv.drm_di_major, sv.drm_di_minor,
62 		 sv.drm_dd_major, sv.drm_dd_minor);
63 }
64 
test_client(int fd)65 static void test_client(int fd)
66 {
67 	close(drm_open_driver(DRIVER_VGEM));
68 	close(drm_open_driver_render(DRIVER_VGEM));
69 }
70 
test_create(int fd)71 static void test_create(int fd)
72 {
73 	struct vgem_bo bo;
74 
75 	bo.width = 0;
76 	bo.height = 0;
77 	bo.bpp = 0;
78 	igt_assert_eq(__vgem_create(fd, &bo), -EINVAL);
79 
80 	bo.width = 1;
81 	bo.height = 1;
82 	bo.bpp = 1;
83 	vgem_create(fd, &bo);
84 	igt_assert_eq(bo.size, 4096);
85 	gem_close(fd, bo.handle);
86 
87 	bo.width = 1024;
88 	bo.height = 1024;
89 	bo.bpp = 8;
90 	vgem_create(fd, &bo);
91 	igt_assert_eq(bo.size, 1<<20);
92 	gem_close(fd, bo.handle);
93 
94 	bo.width = 1<<15;
95 	bo.height = 1<<15;
96 	bo.bpp = 16;
97 	vgem_create(fd, &bo);
98 	igt_assert_eq(bo.size, 1<<31);
99 	gem_close(fd, bo.handle);
100 }
101 
test_mmap(int fd)102 static void test_mmap(int fd)
103 {
104 	struct vgem_bo bo;
105 	uint32_t *ptr;
106 
107 	bo.width = 1024;
108 	bo.height = 1024;
109 	bo.bpp = 32;
110 	vgem_create(fd, &bo);
111 
112 	ptr = vgem_mmap(fd, &bo, PROT_WRITE);
113 	gem_close(fd, bo.handle);
114 
115 	for (int page = 0; page < bo.size >> 12; page++)
116 		ptr[page] = 0;
117 
118 	munmap(ptr, bo.size);
119 }
120 
has_prime_import(int fd)121 static bool has_prime_import(int fd)
122 {
123 	uint64_t value;
124 
125 	if (drmGetCap(fd, DRM_CAP_PRIME, &value))
126 		return false;
127 
128 	return value & DRM_PRIME_CAP_IMPORT;
129 }
130 
test_dmabuf_export(int fd)131 static void test_dmabuf_export(int fd)
132 {
133 	struct vgem_bo bo;
134 	uint32_t handle;
135 	int other;
136 	int dmabuf;
137 
138 	other = drm_open_driver(DRIVER_ANY);
139 	igt_require(has_prime_import(other));
140 
141 	bo.width = 1024;
142 	bo.height = 1;
143 	bo.bpp = 32;
144 
145 	vgem_create(fd, &bo);
146 	dmabuf = prime_handle_to_fd(fd, bo.handle);
147 	gem_close(fd, bo.handle);
148 
149 	handle = prime_fd_to_handle(other, dmabuf);
150 	close(dmabuf);
151 	gem_close(other, handle);
152 	close(other);
153 }
154 
test_dmabuf_mmap(int fd)155 static void test_dmabuf_mmap(int fd)
156 {
157 	struct vgem_bo bo;
158 	uint32_t *ptr;
159 	int export;
160 
161 	bo.width = 1024;
162 	bo.height = 1024;
163 	bo.bpp = 32;
164 	vgem_create(fd, &bo);
165 
166 	export = prime_handle_to_fd_for_mmap(fd, bo.handle);
167 	ptr = mmap(NULL, bo.size, PROT_WRITE, MAP_SHARED, export, 0);
168 	close(export);
169 	igt_assert(ptr != MAP_FAILED);
170 
171 	for (int page = 0; page < bo.size >> 12; page++)
172 		ptr[page] = page;
173 	munmap(ptr, bo.size);
174 
175 	ptr = vgem_mmap(fd, &bo, PROT_READ);
176 	gem_close(fd, bo.handle);
177 
178 	for (int page = 0; page < bo.size >> 12; page++)
179 		igt_assert_eq(ptr[page], page);
180 	munmap(ptr, bo.size);
181 }
182 
prime_busy(int fd,bool excl)183 static bool prime_busy(int fd, bool excl)
184 {
185 	struct pollfd pfd = { .fd = fd, .events = excl ? POLLOUT : POLLIN };
186 	return poll(&pfd, 1, 0) == 0;
187 }
188 
test_dmabuf_fence(int fd)189 static void test_dmabuf_fence(int fd)
190 {
191 	struct vgem_bo bo;
192 	int dmabuf;
193 	uint32_t fence;
194 
195 	bo.width = 1024;
196 	bo.height = 1;
197 	bo.bpp = 32;
198 	vgem_create(fd, &bo);
199 
200 	/* export, then fence */
201 
202 	dmabuf = prime_handle_to_fd(fd, bo.handle);
203 
204 	fence = vgem_fence_attach(fd, &bo, 0);
205 	igt_assert(!prime_busy(dmabuf, false));
206 	igt_assert(prime_busy(dmabuf, true));
207 
208 	vgem_fence_signal(fd, fence);
209 	igt_assert(!prime_busy(dmabuf, false));
210 	igt_assert(!prime_busy(dmabuf, true));
211 
212 	fence = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE);
213 	igt_assert(prime_busy(dmabuf, false));
214 	igt_assert(prime_busy(dmabuf, true));
215 
216 	vgem_fence_signal(fd, fence);
217 	igt_assert(!prime_busy(dmabuf, false));
218 	igt_assert(!prime_busy(dmabuf, true));
219 
220 	close(dmabuf);
221 	gem_close(fd, bo.handle);
222 }
223 
test_dmabuf_fence_before(int fd)224 static void test_dmabuf_fence_before(int fd)
225 {
226 	struct vgem_bo bo;
227 	int dmabuf;
228 	uint32_t fence;
229 
230 	bo.width = 1024;
231 	bo.height = 1;
232 	bo.bpp = 32;
233 	vgem_create(fd, &bo);
234 
235 	fence = vgem_fence_attach(fd, &bo, 0);
236 	dmabuf = prime_handle_to_fd(fd, bo.handle);
237 
238 	igt_assert(!prime_busy(dmabuf, false));
239 	igt_assert(prime_busy(dmabuf, true));
240 
241 	vgem_fence_signal(fd, fence);
242 	igt_assert(!prime_busy(dmabuf, false));
243 	igt_assert(!prime_busy(dmabuf, true));
244 
245 	close(dmabuf);
246 	gem_close(fd, bo.handle);
247 
248 	vgem_create(fd, &bo);
249 
250 	fence = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE);
251 	dmabuf = prime_handle_to_fd(fd, bo.handle);
252 	igt_assert(prime_busy(dmabuf, false));
253 	igt_assert(prime_busy(dmabuf, true));
254 
255 	vgem_fence_signal(fd, fence);
256 	igt_assert(!prime_busy(dmabuf, false));
257 	igt_assert(!prime_busy(dmabuf, true));
258 
259 	close(dmabuf);
260 	gem_close(fd, bo.handle);
261 }
262 
test_sysfs_read(int fd)263 static void test_sysfs_read(int fd)
264 {
265 	int dir = igt_sysfs_open(fd);
266 	DIR *dirp = fdopendir(dir);
267 	struct dirent *de;
268 
269 	while ((de = readdir(dirp))) {
270 		struct stat st;
271 
272 		if (*de->d_name == '.')
273 			continue;
274 
275 		if (fstatat(dir, de->d_name, &st, 0))
276 			continue;
277 
278 		if (S_ISDIR(st.st_mode))
279 			continue;
280 
281 		igt_debug("Reading %s\n", de->d_name);
282 		igt_set_timeout(1, "vgem sysfs read stalled");
283 		free(igt_sysfs_get(dir, de->d_name));
284 		igt_reset_timeout();
285 	}
286 
287 	closedir(dirp);
288 	close(dir);
289 }
290 
test_debugfs_read(int fd)291 static void test_debugfs_read(int fd)
292 {
293 	int dir = igt_debugfs_dir(fd);
294 	DIR *dirp = fdopendir(dir);
295 	struct dirent *de;
296 
297 	igt_assert(dirp);
298 	while ((de = readdir(dirp))) {
299 		struct stat st;
300 
301 		if (*de->d_name == '.')
302 			continue;
303 
304 		if (fstatat(dir, de->d_name, &st, 0))
305 			continue;
306 
307 		if (S_ISDIR(st.st_mode))
308 			continue;
309 
310 		igt_debug("Reading %s\n", de->d_name);
311 		igt_set_timeout(1, "vgem debugfs read stalled");
312 		free(igt_sysfs_get(dir, de->d_name));
313 		igt_reset_timeout();
314 	}
315 
316 	closedir(dirp);
317 	close(dir);
318 }
319 
module_unload(void)320 static int module_unload(void)
321 {
322 	return igt_kmod_unload("vgem", 0);
323 }
324 
test_unload(void)325 static void test_unload(void)
326 {
327 	struct vgem_bo bo;
328 	int vgem, dmabuf;
329 	uint32_t *ptr;
330 
331 	/* Load and unload vgem just to make sure it exists */
332 	vgem = __drm_open_driver(DRIVER_VGEM);
333 	igt_require(vgem != -1);
334 	close(vgem);
335 	igt_require(module_unload() == 0);
336 
337 	vgem = __drm_open_driver(DRIVER_VGEM);
338 	igt_assert(vgem != -1);
339 
340 	/* The driver should stop the module from unloading */
341 	igt_assert_f(module_unload() != 0,
342 		     "open(//dev/vgem) should keep the module alive\n");
343 
344 	bo.width = 1024;
345 	bo.height = 1;
346 	bo.bpp = 32;
347 	vgem_create(vgem, &bo);
348 	close(vgem);
349 
350 	/* Closing the driver should clear all normal references */
351 	igt_assert_f(module_unload() == 0,
352 		     "No open(/dev/vgem), should be able to unload\n");
353 
354 	vgem = __drm_open_driver(DRIVER_VGEM);
355 	igt_assert(vgem != -1);
356 	bo.width = 1024;
357 	bo.height = 1;
358 	bo.bpp = 32;
359 	vgem_create(vgem, &bo);
360 	dmabuf = prime_handle_to_fd(vgem, bo.handle);
361 	close(vgem);
362 
363 	/* A dmabuf should prevent module unload. */
364 	igt_assert_f(module_unload() != 0,
365 		     "A dmabuf should keep the module alive\n");
366 
367 	close(dmabuf);
368 	igt_assert_f(module_unload() == 0,
369 		     "No open dmabuf, should be able to unload\n");
370 
371 	vgem = __drm_open_driver(DRIVER_VGEM);
372 	igt_assert(vgem != -1);
373 	bo.width = 1024;
374 	bo.height = 1;
375 	bo.bpp = 32;
376 	vgem_create(vgem, &bo);
377 	dmabuf = prime_handle_to_fd_for_mmap(vgem, bo.handle);
378 	close(vgem);
379 
380 	ptr = mmap(NULL, bo.size, PROT_WRITE, MAP_SHARED, dmabuf, 0);
381 	igt_assert(ptr != MAP_FAILED);
382 	close(dmabuf);
383 
384 	/* Although closed, the mmap should keep the dmabuf/module alive */
385 	igt_assert_f(module_unload() == 0,
386 		     "A mmap should not keep the module alive\n");
387 
388 	for (int page = 0; page < bo.size >> 12; page++)
389 		ptr[1024*page + page%1024] = page;
390 
391 	/* And finally we should have no more uses on the module. */
392 	munmap(ptr, bo.size);
393 }
394 
has_prime_export(int fd)395 static bool has_prime_export(int fd)
396 {
397 	uint64_t value;
398 
399 	if (drmGetCap(fd, DRM_CAP_PRIME, &value))
400 		return false;
401 
402 	return value & DRM_PRIME_CAP_EXPORT;
403 }
404 
405 igt_main
406 {
407 	int fd = -1;
408 
409 	igt_subtest("unload")
410 		test_unload();
411 
412 	igt_fixture {
413 		fd = drm_open_driver(DRIVER_VGEM);
414 	}
415 
416 	igt_subtest_f("setversion")
417 		test_setversion(fd);
418 
419 	igt_subtest_f("second-client")
420 		test_client(fd);
421 
422 	igt_subtest_f("create")
423 		test_create(fd);
424 
425 	igt_subtest_f("mmap")
426 		test_mmap(fd);
427 
428 	igt_subtest_group {
429 		igt_fixture {
430 			igt_require(has_prime_export(fd));
431 		}
432 
433 		igt_subtest("dmabuf-export")
434 			test_dmabuf_export(fd);
435 
436 		igt_subtest("dmabuf-mmap")
437 			test_dmabuf_mmap(fd);
438 
439 		igt_subtest_group {
440 			igt_fixture {
441 				igt_require(vgem_has_fences(fd));
442 			}
443 
444 			igt_subtest("dmabuf-fence")
445 				test_dmabuf_fence(fd);
446 			igt_subtest("dmabuf-fence-before")
447 				test_dmabuf_fence_before(fd);
448 		}
449 	}
450 
451 	igt_subtest("sysfs")
452 		test_sysfs_read(fd);
453 	igt_subtest("debugfs")
454 		test_debugfs_read(fd);
455 
456 	igt_fixture {
457 		close(fd);
458 	}
459 }
460