blob: 0a5326e991bad0dbb0346b782681d5b5bae7689a [file] [log] [blame]
Chris Wilsona464fb72015-01-02 16:33:29 +05301/*
2 * Copyright © 2011 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 * Authors:
24 * Chris Wilson <chris@chris-wilson.co.uk>
25 *
26 */
27
28#define _GNU_SOURCE
29#include <unistd.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <fcntl.h>
34#include <inttypes.h>
35#include <pthread.h>
36#include <errno.h>
37#include <sys/stat.h>
38#include <sys/ioctl.h>
39#include "drm.h"
40#include "ioctl_wrappers.h"
41#include "drmtest.h"
42#include "igt_debugfs.h"
43
Akash Goelf3e1a3d2015-01-02 16:33:34 +053044struct local_i915_gem_mmap_v2 {
45 uint32_t handle;
46 uint32_t pad;
47 uint64_t offset;
48 uint64_t size;
49 uint64_t addr_ptr;
50 uint64_t flags;
51#define I915_MMAP_WC 0x1
52};
53#define LOCAL_IOCTL_I915_GEM_MMAP_v2 DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct local_i915_gem_mmap_v2)
54
Chris Wilsona464fb72015-01-02 16:33:29 +053055static int OBJECT_SIZE = 16*1024*1024;
56
57static void set_domain(int fd, uint32_t handle)
58{
59 gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
60}
61
62static void *
63mmap_bo(int fd, uint32_t handle)
64{
65 void *ptr;
66
67 ptr = gem_mmap__wc(fd, handle, 0, OBJECT_SIZE, PROT_READ | PROT_WRITE);
68 igt_assert(ptr && ptr != MAP_FAILED);
69
70 return ptr;
71}
72
73static void *
74create_pointer(int fd)
75{
76 uint32_t handle;
77 void *ptr;
78
79 handle = gem_create(fd, OBJECT_SIZE);
80
81 ptr = mmap_bo(fd, handle);
82 set_domain(fd, handle);
83
84 gem_close(fd, handle);
85
86 return ptr;
87}
88
89static void
Akash Goelf3e1a3d2015-01-02 16:33:34 +053090test_invalid_flags(int fd)
91{
92 struct drm_i915_getparam gp;
93 struct local_i915_gem_mmap_v2 arg;
94 uint64_t flag = I915_MMAP_WC;
95 int val = -1;
96
97 memset(&arg, 0, sizeof(arg));
98 arg.handle = gem_create(fd, 4096);
99 arg.offset = 0;
100 arg.size = 4096;
101
102 memset(&gp, 0, sizeof(gp));
103 gp.param = 30; /* MMAP_VERSION */
104 gp.value = &val;
105
106 /* Do we have the new mmap_ioctl? */
Paulo Zanonicd33b472015-08-04 16:25:17 -0300107 drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
Akash Goelf3e1a3d2015-01-02 16:33:34 +0530108
109 if (val >= 1) {
110 /*
111 * Only MMAP_WC flag is supported in version 1, so any other
112 * flag should be rejected.
113 */
114 flag <<= 1;
115 while (flag) {
116 arg.flags = flag;
117 igt_assert(drmIoctl(fd,
118 LOCAL_IOCTL_I915_GEM_MMAP_v2,
119 &arg) == -1);
120 igt_assert_eq(errno, EINVAL);
121 flag <<= 1;
122 }
123 }
124
125 gem_close(fd, arg.handle);
126}
127
128static void
Chris Wilsona464fb72015-01-02 16:33:29 +0530129test_copy(int fd)
130{
131 void *src, *dst;
132
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100133 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530134
135 /* copy from a fresh src to fresh dst to force pagefault on both */
136 src = create_pointer(fd);
137 dst = create_pointer(fd);
138
139 memcpy(dst, src, OBJECT_SIZE);
140 memcpy(src, dst, OBJECT_SIZE);
141
142 munmap(dst, OBJECT_SIZE);
143 munmap(src, OBJECT_SIZE);
144}
145
146enum test_read_write {
147 READ_BEFORE_WRITE,
148 READ_AFTER_WRITE,
149};
150
151static void
152test_read_write(int fd, enum test_read_write order)
153{
154 uint32_t handle;
155 void *ptr;
156 volatile uint32_t val = 0;
157
158 handle = gem_create(fd, OBJECT_SIZE);
159 set_domain(fd, handle);
160
161 ptr = mmap_bo(fd, handle);
162 igt_assert(ptr != MAP_FAILED);
163
164 if (order == READ_BEFORE_WRITE) {
165 val = *(uint32_t *)ptr;
166 *(uint32_t *)ptr = val;
167 } else {
168 *(uint32_t *)ptr = val;
169 val = *(uint32_t *)ptr;
170 }
171
172 gem_close(fd, handle);
173 munmap(ptr, OBJECT_SIZE);
174}
175
176static void
177test_read_write2(int fd, enum test_read_write order)
178{
179 uint32_t handle;
180 void *r, *w;
181 volatile uint32_t val = 0;
182
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100183 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530184
185 handle = gem_create(fd, OBJECT_SIZE);
186 set_domain(fd, handle);
187
188 r = gem_mmap__wc(fd, handle, 0, OBJECT_SIZE, PROT_READ);
189 igt_assert(r != MAP_FAILED);
190
191 w = gem_mmap__wc(fd, handle, 0, OBJECT_SIZE, PROT_READ | PROT_WRITE);
192 igt_assert(w != MAP_FAILED);
193
194 if (order == READ_BEFORE_WRITE) {
195 val = *(uint32_t *)r;
196 *(uint32_t *)w = val;
197 } else {
198 *(uint32_t *)w = val;
199 val = *(uint32_t *)r;
200 }
201
202 gem_close(fd, handle);
203 munmap(r, OBJECT_SIZE);
204 munmap(w, OBJECT_SIZE);
205}
206
207static void
208test_write(int fd)
209{
210 void *src;
211 uint32_t dst;
212
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100213 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530214
215 /* copy from a fresh src to fresh dst to force pagefault on both */
216 src = create_pointer(fd);
217 dst = gem_create(fd, OBJECT_SIZE);
218
219 gem_write(fd, dst, 0, src, OBJECT_SIZE);
220
221 gem_close(fd, dst);
222 munmap(src, OBJECT_SIZE);
223}
224
225static void
226test_write_gtt(int fd)
227{
228 uint32_t dst;
229 char *dst_gtt;
230 void *src;
231
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100232 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530233
234 dst = gem_create(fd, OBJECT_SIZE);
235 set_domain(fd, dst);
236
237 /* prefault object into gtt */
238 dst_gtt = mmap_bo(fd, dst);
239 memset(dst_gtt, 0, OBJECT_SIZE);
240 munmap(dst_gtt, OBJECT_SIZE);
241
242 src = create_pointer(fd);
243
244 gem_write(fd, dst, 0, src, OBJECT_SIZE);
245
246 gem_close(fd, dst);
247 munmap(src, OBJECT_SIZE);
248}
249
250static void
251test_read(int fd)
252{
253 void *dst;
254 uint32_t src;
255
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100256 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530257
258 /* copy from a fresh src to fresh dst to force pagefault on both */
259 dst = create_pointer(fd);
260 src = gem_create(fd, OBJECT_SIZE);
261
262 gem_read(fd, src, 0, dst, OBJECT_SIZE);
263
264 gem_close(fd, src);
265 munmap(dst, OBJECT_SIZE);
266}
267
268static void
Chris Wilson007ff022015-04-10 09:48:46 +0100269test_close(int fd)
270{
271 uint32_t handle = gem_create(fd, OBJECT_SIZE);
272 uint8_t *ptr = mmap_bo(fd, handle);
273 int i;
274
275 memset(ptr, 0xcc, OBJECT_SIZE);
276 gem_close(fd, handle);
277 for (i = 0; i < 4096; i++)
278 igt_assert(ptr[i*4096+i] == 0xcc);
279
280 munmap(ptr, OBJECT_SIZE);
281}
282
283static void
284test_write_cpu_read_wc(int fd, int force_domain)
Chris Wilsona464fb72015-01-02 16:33:29 +0530285{
286 uint32_t handle;
287 uint32_t *src, *dst;
288
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100289 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530290
291 handle = gem_create(fd, OBJECT_SIZE);
292
293 dst = gem_mmap__wc(fd, handle, 0, OBJECT_SIZE, PROT_READ);
294 igt_assert(dst != (uint32_t *)MAP_FAILED);
295
296 src = gem_mmap__cpu(fd, handle, 0, OBJECT_SIZE, PROT_WRITE);
297 igt_assert(src != (uint32_t *)MAP_FAILED);
298
Chris Wilsona464fb72015-01-02 16:33:29 +0530299 memset(src, 0xaa, OBJECT_SIZE);
Chris Wilson007ff022015-04-10 09:48:46 +0100300 if (force_domain)
301 set_domain(fd, handle);
Chris Wilsona464fb72015-01-02 16:33:29 +0530302 igt_assert(memcmp(dst, src, OBJECT_SIZE) == 0);
Chris Wilson3214a272015-01-13 09:17:29 +0000303 gem_close(fd, handle);
Chris Wilsona464fb72015-01-02 16:33:29 +0530304
305 munmap(src, OBJECT_SIZE);
306 munmap(dst, OBJECT_SIZE);
307}
308
309static void
310test_write_gtt_read_wc(int fd)
311{
312 uint32_t handle;
313 uint32_t *src, *dst;
314
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100315 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530316
317 handle = gem_create(fd, OBJECT_SIZE);
318 set_domain(fd, handle);
319
320 dst = gem_mmap__wc(fd, handle, 0, OBJECT_SIZE, PROT_READ);
321 igt_assert(dst != (uint32_t *)MAP_FAILED);
322
323 src = gem_mmap__gtt(fd, handle, OBJECT_SIZE, PROT_WRITE);
324 igt_assert(src != (uint32_t *)MAP_FAILED);
325
Chris Wilsona464fb72015-01-02 16:33:29 +0530326 memset(src, 0xaa, OBJECT_SIZE);
327 igt_assert(memcmp(dst, src, OBJECT_SIZE) == 0);
Chris Wilson3214a272015-01-13 09:17:29 +0000328 gem_close(fd, handle);
Chris Wilsona464fb72015-01-02 16:33:29 +0530329
330 munmap(src, OBJECT_SIZE);
331 munmap(dst, OBJECT_SIZE);
332}
333
Chris Wilsond3bf83a2015-01-15 08:49:59 +0000334static void
335test_set_cache_level(int fd)
336{
337 struct drm_mode_cursor arg;
338 struct drm_mode_card_res res;
339 uint32_t crtc[32];
340 int active_crtc = 0;
341 int n;
342
343 /* We want to trigger an old WARN in set-cache-level when
344 * it sees an unbound object in the GTT domain, following
345 * the introduction of mmap(wc).
346 */
347
348 memset(&arg, 0, sizeof(arg));
349 arg.flags = DRM_MODE_CURSOR_BO;
350 arg.width = arg.height = 64;
351 arg.handle = gem_create(fd, 64*64*4);
352 set_domain(fd, arg.handle);
353
354 /* Bind the object to the cursor to force set-cache-level(DISPLAY) */
355 memset(&res, 0, sizeof(res));
356 res.count_crtcs = 32;
357 res.crtc_id_ptr = (uintptr_t)crtc;
358 do_ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
359 for (n = 0; n < res.count_crtcs; n++) {
360 struct drm_mode_crtc mode;
361
362 memset(&mode, 0, sizeof(mode));
363 mode.crtc_id = crtc[n];
364 do_ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &mode);
365
366 if (!mode.mode_valid)
367 continue;
368
369 active_crtc++;
370
371 arg.crtc_id = crtc[n];
372 do_ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
373 }
374
375 gem_close(fd, arg.handle);
376 igt_require(active_crtc);
377}
378
Chris Wilsona464fb72015-01-02 16:33:29 +0530379struct thread_fault_concurrent {
380 pthread_t thread;
381 int id;
382 uint32_t **ptr;
383};
384
385static void *
386thread_fault_concurrent(void *closure)
387{
388 struct thread_fault_concurrent *t = closure;
389 uint32_t val = 0;
390 int n;
391
392 for (n = 0; n < 32; n++) {
393 if (n & 1)
394 *t->ptr[(n + t->id) % 32] = val;
395 else
396 val = *t->ptr[(n + t->id) % 32];
397 }
398
399 return NULL;
400}
401
402static void
403test_fault_concurrent(int fd)
404{
405 uint32_t *ptr[32];
406 struct thread_fault_concurrent thread[64];
407 int n;
408
Daniel Vettera3e34ce2015-02-06 11:05:28 +0100409 gem_require_mmap_wc(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530410
411 for (n = 0; n < 32; n++) {
412 ptr[n] = create_pointer(fd);
413 }
414
415 for (n = 0; n < 64; n++) {
416 thread[n].ptr = ptr;
417 thread[n].id = n;
418 pthread_create(&thread[n].thread, NULL, thread_fault_concurrent, &thread[n]);
419 }
420
421 for (n = 0; n < 64; n++)
422 pthread_join(thread[n].thread, NULL);
423
424 for (n = 0; n < 32; n++) {
425 munmap(ptr[n], OBJECT_SIZE);
426 }
427}
428
429static void
430run_without_prefault(int fd,
431 void (*func)(int fd))
432{
433 igt_disable_prefault();
434 func(fd);
435 igt_enable_prefault();
436}
437
438int fd;
439
440igt_main
441{
442 if (igt_run_in_simulation())
443 OBJECT_SIZE = 1 * 1024 * 1024;
444
445 igt_fixture
446 fd = drm_open_any();
447
Daniel Vetterfbcc7ba2015-01-22 09:43:10 +0100448 igt_subtest("invalid-flags")
Akash Goelf3e1a3d2015-01-02 16:33:34 +0530449 test_invalid_flags(fd);
Chris Wilson007ff022015-04-10 09:48:46 +0100450 igt_subtest("close")
451 test_close(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530452 igt_subtest("copy")
453 test_copy(fd);
454 igt_subtest("read")
455 test_read(fd);
456 igt_subtest("write")
457 test_write(fd);
458 igt_subtest("write-gtt")
459 test_write_gtt(fd);
460 igt_subtest("read-write")
461 test_read_write(fd, READ_BEFORE_WRITE);
462 igt_subtest("write-read")
463 test_read_write(fd, READ_AFTER_WRITE);
464 igt_subtest("read-write-distinct")
465 test_read_write2(fd, READ_BEFORE_WRITE);
466 igt_subtest("write-read-distinct")
467 test_read_write2(fd, READ_AFTER_WRITE);
468 igt_subtest("fault-concurrent")
469 test_fault_concurrent(fd);
470 igt_subtest("read-no-prefault")
471 run_without_prefault(fd, test_read);
472 igt_subtest("write-no-prefault")
473 run_without_prefault(fd, test_write);
474 igt_subtest("write-gtt-no-prefault")
475 run_without_prefault(fd, test_write_gtt);
476 igt_subtest("write-cpu-read-wc")
Chris Wilson007ff022015-04-10 09:48:46 +0100477 test_write_cpu_read_wc(fd, 1);
478 igt_subtest("write-cpu-read-wc-unflushed")
479 test_write_cpu_read_wc(fd, 0);
Chris Wilsona464fb72015-01-02 16:33:29 +0530480 igt_subtest("write-gtt-read-wc")
481 test_write_gtt_read_wc(fd);
Chris Wilsond3bf83a2015-01-15 08:49:59 +0000482 igt_subtest("set-cache-level")
483 test_set_cache_level(fd);
Chris Wilsona464fb72015-01-02 16:33:29 +0530484
485 igt_fixture
486 close(fd);
487}