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 * Daniel Vetter <[email protected]>
25 *
26 */
27
28 /** @file gem_tiled_pread_pwrite.c
29 *
30 * This is a test of pread's behavior on tiled objects with respect to the
31 * reported swizzling value.
32 *
33 * The goal is to exercise the slow_bit17_copy path for reading on bit17
34 * machines, but will also be useful for catching swizzling value bugs on
35 * other systems.
36 */
37
38 /*
39 * Testcase: Exercise swizzle code for swapping
40 *
41 * The swizzle checks in the swapin path are at a different place than the ones
42 * for pread/pwrite, so we need to check them separately.
43 *
44 * This test obviously needs swap present (and exits if none is detected).
45 */
46
47 #include "igt.h"
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <fcntl.h>
52 #include <inttypes.h>
53 #include <errno.h>
54 #include <sys/stat.h>
55 #include <sys/time.h>
56 #include <sys/ioctl.h>
57 #include <pthread.h>
58
59 #include <drm.h>
60
61
62 IGT_TEST_DESCRIPTION("Exercise swizzle code for swapping.");
63
64 #define WIDTH 512
65 #define HEIGHT 512
66 #define LINEAR_DWORDS (4 * WIDTH * HEIGHT)
67 static uint32_t current_tiling_mode;
68
69 #define PAGE_SIZE 4096
70 #define AVAIL_RAM 512
71
72 static uint32_t
create_bo(int fd)73 create_bo(int fd)
74 {
75 uint32_t handle;
76 uint32_t *data;
77
78 handle = gem_create(fd, LINEAR_DWORDS);
79 gem_set_tiling(fd, handle, current_tiling_mode, WIDTH * sizeof(uint32_t));
80
81 data = __gem_mmap__gtt(fd, handle, LINEAR_DWORDS, PROT_READ | PROT_WRITE);
82 if (data == NULL) {
83 gem_close(fd, handle);
84 return 0;
85 }
86 munmap(data, LINEAR_DWORDS);
87
88 return handle;
89 }
90
91 static void
fill_bo(int fd,uint32_t handle)92 fill_bo(int fd, uint32_t handle)
93 {
94 uint32_t *data;
95 int i;
96
97 data = gem_mmap__gtt(fd, handle, LINEAR_DWORDS,
98 PROT_READ | PROT_WRITE);
99
100 gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
101 for (i = 0; i < WIDTH*HEIGHT; i++)
102 data[i] = i;
103 munmap(data, LINEAR_DWORDS);
104 }
105
106 static void
check_bo(int fd,uint32_t handle)107 check_bo(int fd, uint32_t handle)
108 {
109 uint32_t *data;
110 int j;
111
112 data = gem_mmap__gtt(fd, handle, LINEAR_DWORDS, PROT_READ);
113 gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
114 j = rand() % (WIDTH * HEIGHT);
115 igt_assert_f(data[j] == j, "mismatch at %i: %i\n", j, data[j]);
116 munmap(data, LINEAR_DWORDS);
117 }
118
119 uint32_t *bo_handles;
120
121 struct thread {
122 pthread_t thread;
123 int *idx_arr;
124 int fd, count;
125 };
126
thread_run(void * data)127 static void *thread_run(void *data)
128 {
129 struct thread *t = data;
130 int i;
131
132 for (i = 0; i < t->count; i++)
133 check_bo(t->fd, bo_handles[t->idx_arr[i]]);
134
135 return NULL;
136 }
137
thread_init(struct thread * t,int fd,int count)138 static void thread_init(struct thread *t, int fd, int count)
139 {
140 int i;
141
142 t->fd = fd;
143 t->count = count;
144 t->idx_arr = calloc(count, sizeof(int));
145 igt_assert(t->idx_arr);
146
147 for (i = 0; i < count; i++)
148 t->idx_arr[i] = i;
149
150 igt_permute_array(t->idx_arr, count, igt_exchange_int);
151 }
152
thread_fini(struct thread * t)153 static void thread_fini(struct thread *t)
154 {
155 free(t->idx_arr);
156 }
157
check_memory_layout(int fd)158 static void check_memory_layout(int fd)
159 {
160 igt_skip_on_f(igt_debugfs_search(fd, "i915_swizzle_info", "L-shaped"),
161 "L-shaped memory configuration detected\n");
162
163 igt_debug("normal memory configuration detected, continuing\n");
164 }
165
166 igt_main
167 {
168 struct thread *threads;
169 int fd, n, count, num_threads;
170
171 igt_fixture {
172 size_t lock_size;
173
174 current_tiling_mode = I915_TILING_X;
175
176 fd = drm_open_driver(DRIVER_INTEL);
177
178 intel_purge_vm_caches(fd);
179 check_memory_layout(fd);
180
181 /* lock RAM, leaving only 512MB available */
182 lock_size = max(0, intel_get_total_ram_mb() - AVAIL_RAM);
183 igt_lock_mem(lock_size);
184
185 /* need slightly more than available memory */
186 count = min(intel_get_total_ram_mb(), AVAIL_RAM) * 1.25;
187 bo_handles = calloc(count, sizeof(uint32_t));
188 igt_assert(bo_handles);
189
190 num_threads = gem_available_fences(fd);
191 threads = calloc(num_threads, sizeof(struct thread));
192 igt_assert(threads);
193
194 igt_info("Using %d 1MiB objects (available RAM: %ld/%ld, swap: %ld)\n",
195 count,
196 (long)intel_get_avail_ram_mb(),
197 (long)intel_get_total_ram_mb(),
198 (long)intel_get_total_swap_mb());
199 intel_require_memory(count, 1024*1024, CHECK_RAM | CHECK_SWAP);
200
201 for (n = 0; n < count; n++) {
202 bo_handles[n] = create_bo(fd);
203 /* Not enough mmap address space possible. */
204 igt_require(bo_handles[n]);
205 }
206 }
207
208 igt_subtest("non-threaded") {
209 for (n = 0; n < count; n++)
210 fill_bo(fd, bo_handles[n]);
211
212 thread_init(&threads[0], fd, count);
213 thread_run(&threads[0]);
214 thread_run(&threads[0]);
215 thread_run(&threads[0]);
216 thread_fini(&threads[0]);
217 }
218
219 /* Once more with threads */
220 igt_subtest("threaded") {
221 for (n = 0; n < count; n++)
222 fill_bo(fd, bo_handles[n]);
223
224 for (n = 0; n < num_threads; n++)
225 thread_init(&threads[n], fd, count);
226
227 thread_run(&threads[0]);
228 for (n = 0; n < num_threads; n++)
229 pthread_create(&threads[n].thread, NULL, thread_run, &threads[n]);
230 for (n = 0; n < num_threads; n++)
231 pthread_join(threads[n].thread, NULL);
232 thread_run(&threads[0]);
233
234 for (n = 0; n < num_threads; n++)
235 thread_fini(&threads[n]);
236 }
237
238 igt_fixture
239 close(fd);
240 }
241