lib/igt_kms: Unify pipe name helpers
[platform/upstream/intel-gpu-tools.git] / tests / gem_mmap_gtt.c
1 /*
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
44 static int OBJECT_SIZE = 16*1024*1024;
45
46 static void set_domain(int fd, uint32_t handle)
47 {
48         gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
49 }
50
51 static void *
52 mmap_bo(int fd, uint32_t handle)
53 {
54         void *ptr;
55
56         ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
57         igt_assert(ptr != MAP_FAILED);
58
59         return ptr;
60 }
61
62 static void *
63 create_pointer(int fd)
64 {
65         uint32_t handle;
66         void *ptr;
67
68         handle = gem_create(fd, OBJECT_SIZE);
69
70         ptr = mmap_bo(fd, handle);
71
72         gem_close(fd, handle);
73
74         return ptr;
75 }
76
77 static void
78 test_access(int fd)
79 {
80         uint32_t handle, flink, handle2;
81         struct drm_i915_gem_mmap_gtt mmap_arg;
82         int fd2;
83
84         handle = gem_create(fd, OBJECT_SIZE);
85         igt_assert(handle);
86
87         fd2 = drm_open_any();
88
89         /* Check that fd1 can mmap. */
90         mmap_arg.handle = handle;
91         igt_assert(drmIoctl(fd,
92                             DRM_IOCTL_I915_GEM_MMAP_GTT,
93                             &mmap_arg) == 0);
94
95         igt_assert(mmap64(0, OBJECT_SIZE, PROT_READ | PROT_WRITE,
96                           MAP_SHARED, fd, mmap_arg.offset));
97
98         /* Check that the same offset on the other fd doesn't work. */
99         igt_assert(mmap64(0, OBJECT_SIZE, PROT_READ | PROT_WRITE,
100                           MAP_SHARED, fd2, mmap_arg.offset) == MAP_FAILED);
101         igt_assert(errno == EACCES);
102
103         flink = gem_flink(fd, handle);
104         igt_assert(flink);
105         handle2 = gem_open(fd2, flink);
106         igt_assert(handle2);
107
108         /* Recheck that it works after flink. */
109         /* Check that the same offset on the other fd doesn't work. */
110         igt_assert(mmap64(0, OBJECT_SIZE, PROT_READ | PROT_WRITE,
111                           MAP_SHARED, fd2, mmap_arg.offset));
112 }
113
114 static void
115 test_short(int fd)
116 {
117         struct drm_i915_gem_mmap_gtt mmap_arg;
118         int pages, p;
119
120         mmap_arg.handle = gem_create(fd, OBJECT_SIZE);
121         igt_assert(mmap_arg.handle);
122
123         igt_assert(drmIoctl(fd,
124                             DRM_IOCTL_I915_GEM_MMAP_GTT,
125                             &mmap_arg) == 0);
126         for (pages = 1; pages <= OBJECT_SIZE / 4096; pages <<= 1) {
127                 uint8_t *r, *w;
128
129                 w = mmap64(0, pages * 4096, PROT_READ | PROT_WRITE,
130                            MAP_SHARED, fd, mmap_arg.offset);
131                 igt_assert(w != MAP_FAILED);
132
133                 r = mmap64(0, pages * 4096, PROT_READ,
134                            MAP_SHARED, fd, mmap_arg.offset);
135                 igt_assert(r != MAP_FAILED);
136
137                 for (p = 0; p < pages; p++) {
138                         w[4096*p] = r[4096*p];
139                         w[4096*p+4095] = r[4096*p+4095];
140                 }
141
142                 munmap(r, pages * 4096);
143                 munmap(w, pages * 4096);
144         }
145         gem_close(fd, mmap_arg.handle);
146 }
147
148 static void
149 test_copy(int fd)
150 {
151         void *src, *dst;
152
153         /* copy from a fresh src to fresh dst to force pagefault on both */
154         src = create_pointer(fd);
155         dst = create_pointer(fd);
156
157         memcpy(dst, src, OBJECT_SIZE);
158         memcpy(src, dst, OBJECT_SIZE);
159
160         munmap(dst, OBJECT_SIZE);
161         munmap(src, OBJECT_SIZE);
162 }
163
164 enum test_read_write {
165         READ_BEFORE_WRITE,
166         READ_AFTER_WRITE,
167 };
168
169 static void
170 test_read_write(int fd, enum test_read_write order)
171 {
172         uint32_t handle;
173         void *ptr;
174         volatile uint32_t val = 0;
175
176         handle = gem_create(fd, OBJECT_SIZE);
177
178         ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
179         igt_assert(ptr != MAP_FAILED);
180
181         if (order == READ_BEFORE_WRITE) {
182                 val = *(uint32_t *)ptr;
183                 *(uint32_t *)ptr = val;
184         } else {
185                 *(uint32_t *)ptr = val;
186                 val = *(uint32_t *)ptr;
187         }
188
189         gem_close(fd, handle);
190         munmap(ptr, OBJECT_SIZE);
191 }
192
193 static void
194 test_read_write2(int fd, enum test_read_write order)
195 {
196         uint32_t handle;
197         void *r, *w;
198         volatile uint32_t val = 0;
199
200         handle = gem_create(fd, OBJECT_SIZE);
201
202         r = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ);
203         igt_assert(r != MAP_FAILED);
204
205         w = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
206         igt_assert(w != MAP_FAILED);
207
208         if (order == READ_BEFORE_WRITE) {
209                 val = *(uint32_t *)r;
210                 *(uint32_t *)w = val;
211         } else {
212                 *(uint32_t *)w = val;
213                 val = *(uint32_t *)r;
214         }
215
216         gem_close(fd, handle);
217         munmap(r, OBJECT_SIZE);
218         munmap(w, OBJECT_SIZE);
219 }
220
221 static void
222 test_write(int fd)
223 {
224         void *src;
225         uint32_t dst;
226
227         /* copy from a fresh src to fresh dst to force pagefault on both */
228         src = create_pointer(fd);
229         dst = gem_create(fd, OBJECT_SIZE);
230
231         gem_write(fd, dst, 0, src, OBJECT_SIZE);
232
233         gem_close(fd, dst);
234         munmap(src, OBJECT_SIZE);
235 }
236
237 static void
238 test_write_gtt(int fd)
239 {
240         uint32_t dst;
241         char *dst_gtt;
242         void *src;
243
244         dst = gem_create(fd, OBJECT_SIZE);
245
246         /* prefault object into gtt */
247         dst_gtt = mmap_bo(fd, dst);
248         set_domain(fd, dst);
249         memset(dst_gtt, 0, OBJECT_SIZE);
250         munmap(dst_gtt, OBJECT_SIZE);
251
252         src = create_pointer(fd);
253
254         gem_write(fd, dst, 0, src, OBJECT_SIZE);
255
256         gem_close(fd, dst);
257         munmap(src, OBJECT_SIZE);
258 }
259
260 static void
261 test_read(int fd)
262 {
263         void *dst;
264         uint32_t src;
265
266         /* copy from a fresh src to fresh dst to force pagefault on both */
267         dst = create_pointer(fd);
268         src = gem_create(fd, OBJECT_SIZE);
269
270         gem_read(fd, src, 0, dst, OBJECT_SIZE);
271
272         gem_close(fd, src);
273         munmap(dst, OBJECT_SIZE);
274 }
275
276 struct thread_fault_concurrent {
277         pthread_t thread;
278         int id;
279         uint32_t **ptr;
280 };
281
282 static void *
283 thread_fault_concurrent(void *closure)
284 {
285         struct thread_fault_concurrent *t = closure;
286         uint32_t val = 0;
287         int n;
288
289         for (n = 0; n < 32; n++) {
290                 if (n & 1)
291                         *t->ptr[(n + t->id) % 32] = val;
292                 else
293                         val = *t->ptr[(n + t->id) % 32];
294         }
295
296         return NULL;
297 }
298
299 static void
300 test_fault_concurrent(int fd)
301 {
302         uint32_t *ptr[32];
303         struct thread_fault_concurrent thread[64];
304         int n;
305
306         for (n = 0; n < 32; n++) {
307                 ptr[n] = create_pointer(fd);
308         }
309
310         for (n = 0; n < 64; n++) {
311                 thread[n].ptr = ptr;
312                 thread[n].id = n;
313                 pthread_create(&thread[n].thread, NULL, thread_fault_concurrent, &thread[n]);
314         }
315
316         for (n = 0; n < 64; n++)
317                 pthread_join(thread[n].thread, NULL);
318
319         for (n = 0; n < 32; n++) {
320                 munmap(ptr[n], OBJECT_SIZE);
321         }
322 }
323
324 static void
325 run_without_prefault(int fd,
326                         void (*func)(int fd))
327 {
328         igt_disable_prefault();
329         func(fd);
330         igt_enable_prefault();
331 }
332
333 int fd;
334
335 igt_main
336 {
337         if (igt_run_in_simulation())
338                 OBJECT_SIZE = 1 * 1024 * 1024;
339
340         igt_fixture
341                 fd = drm_open_any();
342
343         igt_subtest("access")
344                 test_access(fd);
345         igt_subtest("short")
346                 test_short(fd);
347         igt_subtest("copy")
348                 test_copy(fd);
349         igt_subtest("read")
350                 test_read(fd);
351         igt_subtest("write")
352                 test_write(fd);
353         igt_subtest("write-gtt")
354                 test_write_gtt(fd);
355         igt_subtest("read-write")
356                 test_read_write(fd, READ_BEFORE_WRITE);
357         igt_subtest("write-read")
358                 test_read_write(fd, READ_AFTER_WRITE);
359         igt_subtest("read-write-distinct")
360                 test_read_write2(fd, READ_BEFORE_WRITE);
361         igt_subtest("write-read-distinct")
362                 test_read_write2(fd, READ_AFTER_WRITE);
363         igt_subtest("fault-concurrent")
364                 test_fault_concurrent(fd);
365         igt_subtest("read-no-prefault")
366                 run_without_prefault(fd, test_read);
367         igt_subtest("write-no-prefault")
368                 run_without_prefault(fd, test_write);
369         igt_subtest("write-gtt-no-prefault")
370                 run_without_prefault(fd, test_write_gtt);
371
372         igt_fixture
373                 close(fd);
374 }