blob: 5b54a4a325dd7499b14a29c71ca4eae3c8c89d06 [file] [log] [blame]
Chris Wilsonc3440442016-06-18 00:42:19 +01001/*
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_vgem.h"
Chris Wilson8deba382016-06-20 19:21:26 +010026#include "igt_debugfs.h"
27#include "igt_sysfs.h"
Chris Wilsonc3440442016-06-18 00:42:19 +010028
29#include <sys/mman.h>
Chris Wilson93256e32016-06-22 07:21:09 +010030#include <sys/poll.h>
Chris Wilson8deba382016-06-20 19:21:26 +010031#include <sys/stat.h>
32#include <dirent.h>
Chris Wilsonc3440442016-06-18 00:42:19 +010033
34IGT_TEST_DESCRIPTION("Basic sanity check of Virtual GEM module (vGEM).");
35
Chris Wilson68c5d532016-06-22 09:10:33 +010036static void test_client(int fd)
37{
38 close(drm_open_driver(DRIVER_VGEM));
39 close(drm_open_driver_render(DRIVER_VGEM));
40}
41
Chris Wilsonc3440442016-06-18 00:42:19 +010042static void test_create(int fd)
43{
44 struct vgem_bo bo;
45
46 bo.width = 0;
47 bo.height = 0;
48 bo.bpp = 0;
49 igt_assert_eq(__vgem_create(fd, &bo), -EINVAL);
50
51 bo.width = 1;
52 bo.height = 1;
53 bo.bpp = 1;
54 vgem_create(fd, &bo);
55 igt_assert_eq(bo.size, 4096);
56 gem_close(fd, bo.handle);
57
58 bo.width = 1024;
59 bo.height = 1024;
60 bo.bpp = 8;
61 vgem_create(fd, &bo);
62 igt_assert_eq(bo.size, 1<<20);
63 gem_close(fd, bo.handle);
64
65 bo.width = 1<<15;
66 bo.height = 1<<15;
67 bo.bpp = 16;
68 vgem_create(fd, &bo);
69 igt_assert_eq(bo.size, 1<<31);
70 gem_close(fd, bo.handle);
71}
72
73static void test_mmap(int fd)
74{
75 struct vgem_bo bo;
76 uint32_t *ptr;
77
78 bo.width = 1024;
79 bo.height = 1024;
80 bo.bpp = 32;
81 vgem_create(fd, &bo);
82
83 ptr = vgem_mmap(fd, &bo, PROT_WRITE);
84 gem_close(fd, bo.handle);
85
86 for (int page = 0; page < bo.size >> 12; page++)
87 ptr[page] = 0;
88
89 munmap(ptr, bo.size);
90}
91
92static bool has_prime_import(int fd)
93{
94 uint64_t value;
95
96 if (drmGetCap(fd, DRM_CAP_PRIME, &value))
97 return false;
98
99 return value & DRM_PRIME_CAP_IMPORT;
100}
101
102static void test_dmabuf_export(int fd)
103{
104 struct vgem_bo bo;
105 uint32_t handle;
106 int other;
107 int dmabuf;
108
109 other = drm_open_driver(DRIVER_ANY);
110 igt_require(has_prime_import(other));
111
112 bo.width = 1024;
113 bo.height = 1;
114 bo.bpp = 32;
115
116 vgem_create(fd, &bo);
117 dmabuf = prime_handle_to_fd(fd, bo.handle);
118 gem_close(fd, bo.handle);
119
120 handle = prime_fd_to_handle(other, dmabuf);
121 close(dmabuf);
122 gem_close(other, handle);
123 close(other);
124}
125
126static void test_dmabuf_mmap(int fd)
127{
128 struct vgem_bo bo;
129 uint32_t *ptr;
130 int export;
131
132 bo.width = 1024;
133 bo.height = 1024;
134 bo.bpp = 32;
135 vgem_create(fd, &bo);
136
137 export = prime_handle_to_fd_for_mmap(fd, bo.handle);
138 ptr = mmap(NULL, bo.size, PROT_WRITE, MAP_SHARED, export, 0);
139 close(export);
140 igt_assert(ptr != MAP_FAILED);
141
142 for (int page = 0; page < bo.size >> 12; page++)
143 ptr[page] = page;
144 munmap(ptr, bo.size);
145
146 ptr = vgem_mmap(fd, &bo, PROT_READ);
147 gem_close(fd, bo.handle);
148
149 for (int page = 0; page < bo.size >> 12; page++)
150 igt_assert_eq(ptr[page], page);
151 munmap(ptr, bo.size);
152}
153
Chris Wilson93256e32016-06-22 07:21:09 +0100154static bool prime_busy(int fd, bool excl)
155{
156 struct pollfd pfd = { .fd = fd, .events = excl ? POLLOUT : POLLIN };
157 return poll(&pfd, 1, 0) == 0;
158}
159
160static void test_dmabuf_fence(int fd)
161{
162 struct vgem_bo bo;
163 int dmabuf;
164 uint32_t fence;
165
166 bo.width = 1024;
167 bo.height = 1;
168 bo.bpp = 32;
169 vgem_create(fd, &bo);
170
171 /* export, then fence */
172
173 dmabuf = prime_handle_to_fd(fd, bo.handle);
174
Chris Wilsonc8ab5772016-07-15 09:01:59 +0100175 fence = vgem_fence_attach(fd, &bo, 0);
Chris Wilson93256e32016-06-22 07:21:09 +0100176 igt_assert(!prime_busy(dmabuf, false));
177 igt_assert(prime_busy(dmabuf, true));
178
179 vgem_fence_signal(fd, fence);
180 igt_assert(!prime_busy(dmabuf, false));
181 igt_assert(!prime_busy(dmabuf, true));
182
Chris Wilsonc8ab5772016-07-15 09:01:59 +0100183 fence = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE);
Chris Wilson93256e32016-06-22 07:21:09 +0100184 igt_assert(prime_busy(dmabuf, false));
185 igt_assert(prime_busy(dmabuf, true));
186
187 vgem_fence_signal(fd, fence);
188 igt_assert(!prime_busy(dmabuf, false));
189 igt_assert(!prime_busy(dmabuf, true));
190
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100191 close(dmabuf);
Chris Wilson93256e32016-06-22 07:21:09 +0100192 gem_close(fd, bo.handle);
193}
194
195static void test_dmabuf_fence_before(int fd)
196{
197 struct vgem_bo bo;
198 int dmabuf;
199 uint32_t fence;
200
201 bo.width = 1024;
202 bo.height = 1;
203 bo.bpp = 32;
204 vgem_create(fd, &bo);
205
Chris Wilsonc8ab5772016-07-15 09:01:59 +0100206 fence = vgem_fence_attach(fd, &bo, 0);
Chris Wilson93256e32016-06-22 07:21:09 +0100207 dmabuf = prime_handle_to_fd(fd, bo.handle);
208
209 igt_assert(!prime_busy(dmabuf, false));
210 igt_assert(prime_busy(dmabuf, true));
211
212 vgem_fence_signal(fd, fence);
213 igt_assert(!prime_busy(dmabuf, false));
214 igt_assert(!prime_busy(dmabuf, true));
215
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100216 close(dmabuf);
Chris Wilson93256e32016-06-22 07:21:09 +0100217 gem_close(fd, bo.handle);
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100218
Chris Wilson93256e32016-06-22 07:21:09 +0100219 vgem_create(fd, &bo);
220
Chris Wilsonc8ab5772016-07-15 09:01:59 +0100221 fence = vgem_fence_attach(fd, &bo, VGEM_FENCE_WRITE);
Chris Wilson93256e32016-06-22 07:21:09 +0100222 dmabuf = prime_handle_to_fd(fd, bo.handle);
223 igt_assert(prime_busy(dmabuf, false));
224 igt_assert(prime_busy(dmabuf, true));
225
226 vgem_fence_signal(fd, fence);
227 igt_assert(!prime_busy(dmabuf, false));
228 igt_assert(!prime_busy(dmabuf, true));
229
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100230 close(dmabuf);
Chris Wilson93256e32016-06-22 07:21:09 +0100231 gem_close(fd, bo.handle);
232}
233
Chris Wilson8deba382016-06-20 19:21:26 +0100234static void test_sysfs_read(int fd)
235{
236 int dir = igt_sysfs_open(fd, NULL);
237 DIR *dirp = fdopendir(dir);
238 struct dirent *de;
239
240 while ((de = readdir(dirp))) {
241 struct stat st;
242
243 if (*de->d_name == '.')
244 continue;
245
246 if (fstatat(dir, de->d_name, &st, 0))
247 continue;
248
249 if (S_ISDIR(st.st_mode))
250 continue;
251
252 igt_debug("Reading %s\n", de->d_name);
253 igt_set_timeout(1, "vgem sysfs read stalled");
254 free(igt_sysfs_get(dir, de->d_name));
255 igt_reset_timeout();
256 }
257
258 closedir(dirp);
259 close(dir);
260}
261
262static void test_debugfs_read(int fd)
263{
264 int dir = igt_debugfs_dir(fd);
265 DIR *dirp = fdopendir(dir);
266 struct dirent *de;
267
Chris Wilson2962c512016-07-09 09:04:05 +0100268 igt_assert(dirp);
Chris Wilson8deba382016-06-20 19:21:26 +0100269 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 debugfs 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
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100291static int module_unload(void)
292{
293 return system("/sbin/modprobe -s -r vgem");
294}
295
296static void test_unload(void)
297{
298 struct vgem_bo bo;
299 int vgem, dmabuf;
300 uint32_t *ptr;
301
302 igt_require(module_unload() == 0);
303
304 vgem = __drm_open_driver(DRIVER_VGEM);
305 igt_assert(vgem != -1);
306
307 /* The driver should stop the module from unloading */
308 igt_assert_f(module_unload() != 0,
309 "open(//dev/vgem) should keep the module alive\n");
310
311 bo.width = 1024;
312 bo.height = 1;
313 bo.bpp = 32;
314 vgem_create(vgem, &bo);
315 close(vgem);
316
317 /* Closing the driver should clear all normal references */
318 igt_assert_f(module_unload() == 0,
319 "No open(/dev/vgem), should be able to unload\n");
320
321 vgem = __drm_open_driver(DRIVER_VGEM);
322 igt_assert(vgem != -1);
323 bo.width = 1024;
324 bo.height = 1;
325 bo.bpp = 32;
326 vgem_create(vgem, &bo);
327 dmabuf = prime_handle_to_fd(vgem, bo.handle);
328 close(vgem);
329
330 /* A dmabuf should prevent module unload. */
331 igt_assert_f(module_unload() != 0,
332 "A dmabuf should keep the module alive\n");
333
334 close(dmabuf);
335 igt_assert_f(module_unload() == 0,
336 "No open dmabuf, should be able to unload\n");
337
338 vgem = __drm_open_driver(DRIVER_VGEM);
339 igt_assert(vgem != -1);
340 bo.width = 1024;
341 bo.height = 1;
342 bo.bpp = 32;
343 vgem_create(vgem, &bo);
344 dmabuf = prime_handle_to_fd_for_mmap(vgem, bo.handle);
345 close(vgem);
346
347 ptr = mmap(NULL, bo.size, PROT_WRITE, MAP_SHARED, dmabuf, 0);
348 igt_assert(ptr != MAP_FAILED);
349 close(dmabuf);
350
351 /* Although closed, the mmap should keep the dmabuf/module alive */
Chris Wilson8abe9192016-10-05 14:40:16 +0100352 igt_assert_f(module_unload() == 0,
353 "A mmap should not keep the module alive\n");
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100354
355 for (int page = 0; page < bo.size >> 12; page++)
356 ptr[1024*page + page%1024] = page;
357
358 /* And finally we should have no more uses on the module. */
359 munmap(ptr, bo.size);
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100360}
361
Chris Wilsonc3440442016-06-18 00:42:19 +0100362static bool has_prime_export(int fd)
363{
364 uint64_t value;
365
366 if (drmGetCap(fd, DRM_CAP_PRIME, &value))
367 return false;
368
369 return value & DRM_PRIME_CAP_EXPORT;
370}
371
372igt_main
373{
374 int fd = -1;
375
Chris Wilsoncfbd09d2016-09-30 13:41:30 +0100376 igt_subtest("unload")
377 test_unload();
378
Chris Wilsonc3440442016-06-18 00:42:19 +0100379 igt_fixture {
380 fd = drm_open_driver(DRIVER_VGEM);
381 }
382
Chris Wilson68c5d532016-06-22 09:10:33 +0100383 igt_subtest_f("second-client")
384 test_client(fd);
385
Chris Wilsonc3440442016-06-18 00:42:19 +0100386 igt_subtest_f("create")
387 test_create(fd);
388
389 igt_subtest_f("mmap")
390 test_mmap(fd);
391
392 igt_subtest_group {
393 igt_fixture {
394 igt_require(has_prime_export(fd));
395 }
396
Chris Wilson93256e32016-06-22 07:21:09 +0100397 igt_subtest("dmabuf-export")
Chris Wilsonc3440442016-06-18 00:42:19 +0100398 test_dmabuf_export(fd);
399
Chris Wilson93256e32016-06-22 07:21:09 +0100400 igt_subtest("dmabuf-mmap")
Chris Wilsonc3440442016-06-18 00:42:19 +0100401 test_dmabuf_mmap(fd);
Chris Wilson93256e32016-06-22 07:21:09 +0100402
403 igt_subtest_group {
404 igt_fixture {
405 igt_require(vgem_has_fences(fd));
406 }
407
408 igt_subtest("dmabuf-fence")
409 test_dmabuf_fence(fd);
410 igt_subtest("dmabuf-fence-before")
411 test_dmabuf_fence_before(fd);
412 }
Chris Wilsonc3440442016-06-18 00:42:19 +0100413 }
414
Chris Wilson8deba382016-06-20 19:21:26 +0100415 igt_subtest("sysfs")
416 test_sysfs_read(fd);
417 igt_subtest("debugfs")
418 test_debugfs_read(fd);
419
Chris Wilsonc3440442016-06-18 00:42:19 +0100420 igt_fixture {
421 close(fd);
422 }
423}