1 /*
2 * Copyright © 2015 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 * Ankitprasad Sharma <ankitprasad.r.sharma at intel.com>
25 *
26 */
27
28 /** @file gem_create_stolen.c
29 *
30 * This is a test for the extended gem_create ioctl, that includes allocation
31 * of object from stolen memory.
32 *
33 * The goal is to simply ensure the basics work, and invalid input combinations
34 * are rejected.
35 */
36
37 #include <stdlib.h>
38 #include <sys/ioctl.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <inttypes.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45 #include <sys/time.h>
46 #include <getopt.h>
47
48 #include <drm.h>
49
50 #include "ioctl_wrappers.h"
51 #include "intel_bufmgr.h"
52 #include "intel_batchbuffer.h"
53 #include "intel_io.h"
54 #include "intel_chipset.h"
55 #include "igt_aux.h"
56 #include "drmtest.h"
57 #include "drm.h"
58 #include "i915_drm.h"
59 #include "i915/gem_mman.h"
60
61 IGT_TEST_DESCRIPTION("This test verifies the exetended gem_create ioctl,"
62 " that includes allocation of obj from stolen region");
63 #define CLEAR(s) memset(&s, 0, sizeof(s))
64 #define SIZE 1024*1024
65 #define DWORD_SIZE 4
66 #define DATA 0xdead
67 #define LARGE_SIZE 0xffffffff
68 #define MAX_OBJECTS 100
69
70 static drm_intel_bufmgr *bufmgr;
71 static struct intel_batchbuffer *batch;
72
verify_copy_op(drm_intel_bo * src,drm_intel_bo * dest)73 static void verify_copy_op(drm_intel_bo *src, drm_intel_bo *dest)
74 {
75 uint32_t *virt, i, ret;
76 /* Fill the src BO with dwords */
77 ret = drm_intel_gem_bo_map_gtt(src);
78 igt_assert(!ret);
79
80 virt = src->virtual;
81 for (i = 0; i < SIZE/DWORD_SIZE; i++)
82 virt[i] = i;
83
84 intel_copy_bo(batch, dest, src, SIZE);
85
86 ret = drm_intel_gem_bo_map_gtt(dest);
87 igt_assert(!ret);
88
89 virt = dest->virtual;
90 /* verify */
91 for (i = 0; i < SIZE/DWORD_SIZE; i++)
92 igt_assert_eq(virt[i], i);
93
94 drm_intel_bo_unmap(src);
95 drm_intel_bo_unmap(dest);
96 }
97
stolen_pwrite(int fd)98 static void stolen_pwrite(int fd)
99 {
100 drm_intel_bo *bo;
101 uint32_t buf[SIZE/DWORD_SIZE];
102 uint32_t handle = 0;
103 uint32_t *virt;
104 int i, ret = 0;
105
106 for (i = 0; i < SIZE/DWORD_SIZE; i++)
107 buf[i] = DATA;
108
109 gem_require_stolen_support(fd);
110
111 handle = gem_create_stolen(fd, SIZE);
112
113 gem_write(fd, handle, 0, buf, SIZE);
114 bo = gem_handle_to_libdrm_bo(bufmgr, fd, "bo", handle);
115
116 ret = drm_intel_gem_bo_map_gtt(bo);
117 igt_assert(!ret);
118
119 virt = bo->virtual;
120
121 for (i = 0; i < SIZE/DWORD_SIZE; i++)
122 igt_assert_eq(virt[i], DATA);
123
124 drm_intel_bo_unmap(bo);
125 drm_intel_bo_unreference(bo);
126 gem_close(fd, handle);
127 }
128
stolen_pread(int fd)129 static void stolen_pread(int fd)
130 {
131 drm_intel_bo *bo;
132 uint32_t buf[SIZE/DWORD_SIZE];
133 uint32_t handle = 0;
134 uint32_t *virt;
135 int i, ret = 0;
136
137 CLEAR(buf);
138
139 gem_require_stolen_support(fd);
140
141 handle = gem_create_stolen(fd, SIZE);
142
143 bo = gem_handle_to_libdrm_bo(bufmgr, fd, "bo", handle);
144
145 ret = drm_intel_gem_bo_map_gtt(bo);
146 igt_assert(!ret);
147
148 virt = bo->virtual;
149
150 for (i = 0; i < SIZE/DWORD_SIZE; i++)
151 virt[i] = DATA;
152
153 drm_intel_bo_unmap(bo);
154 drm_intel_bo_unreference(bo);
155
156 gem_read(fd, handle, 0, buf, SIZE);
157
158 for (i = 0; i < SIZE/DWORD_SIZE; i++)
159 igt_assert_eq(buf[i], DATA);
160
161 gem_close(fd, handle);
162 }
163
copy_test(int fd)164 static void copy_test(int fd)
165 {
166 drm_intel_bo *src, *dest;
167 uint32_t src_handle = 0, dest_handle = 0;
168
169 gem_require_stolen_support(fd);
170
171 src_handle = gem_create_stolen(fd, SIZE);
172 dest_handle = gem_create_stolen(fd, SIZE);
173
174 src = gem_handle_to_libdrm_bo(bufmgr, fd, "src_bo", src_handle);
175 dest = gem_handle_to_libdrm_bo(bufmgr, fd, "dst_bo", dest_handle);
176
177 igt_assert(src != NULL);
178 igt_assert(dest != NULL);
179
180 verify_copy_op(src, dest);
181
182 drm_intel_bo_unreference(src);
183 drm_intel_bo_unreference(dest);
184 gem_close(fd, src_handle);
185 gem_close(fd, dest_handle);
186 }
187
verify_object_clear(int fd)188 static void verify_object_clear(int fd)
189 {
190 drm_intel_bo *bo;
191 uint32_t handle = 0;
192 uint32_t *virt;
193 int i, ret;
194
195 gem_require_stolen_support(fd);
196
197 handle = gem_create_stolen(fd, SIZE);
198
199 bo = gem_handle_to_libdrm_bo(bufmgr, fd, "verify_bo", handle);
200 igt_assert(bo != NULL);
201
202 ret = drm_intel_gem_bo_map_gtt(bo);
203 igt_assert(!ret);
204
205 /* Verify if the BO is zeroed */
206 virt = bo->virtual;
207 for (i = 0; i < SIZE / DWORD_SIZE; i++)
208 igt_assert(!virt[i]);
209
210 drm_intel_bo_unmap(bo);
211 drm_intel_bo_unreference(bo);
212 gem_close(fd, handle);
213 }
214
stolen_large_obj_alloc(int fd)215 static void stolen_large_obj_alloc(int fd)
216 {
217 uint32_t handle = 0;
218
219 gem_require_stolen_support(fd);
220 handle = __gem_create_stolen(fd, (unsigned long long) LARGE_SIZE + 4096);
221 igt_assert(!handle);
222 }
223
stolen_fill_purge_test(int fd)224 static void stolen_fill_purge_test(int fd)
225 {
226 drm_intel_bo *bo;
227 int obj_count = 0, i = 0;
228 int _ret = 0, j = 0;
229 uint32_t handle[MAX_OBJECTS];
230 uint32_t new_handle;
231 uint32_t *virt;
232 int retained;
233
234 gem_require_stolen_support(fd);
235
236 /* Exhaust Stolen space */
237 do {
238 handle[i] = __gem_create_stolen(fd, SIZE);
239 if (handle[i] != 0) {
240 bo = gem_handle_to_libdrm_bo(bufmgr, fd,
241 "verify_bo", handle[i]);
242 igt_assert(bo != NULL);
243
244 _ret = drm_intel_gem_bo_map_gtt(bo);
245 igt_assert(!_ret);
246
247 virt = bo->virtual;
248 for (j = 0; j < SIZE/DWORD_SIZE; j++)
249 virt[j] = DATA;
250
251 drm_intel_bo_unmap(bo);
252 drm_intel_bo_unreference(bo);
253
254 obj_count++;
255 }
256
257 i++;
258 } while (handle[i-1] && i < MAX_OBJECTS);
259
260 igt_assert(obj_count > 0);
261
262 /* Mark all stolen objects purgeable */
263 for (i = 0; i < obj_count; i++)
264 retained = gem_madvise(fd, handle[i], I915_MADV_DONTNEED);
265
266 /* Try to allocate one more object */
267 new_handle = gem_create_stolen(fd, SIZE);
268
269 /* Check if the retained object's memory contents are intact */
270 for (i = 0; i < obj_count; i++) {
271 retained = gem_madvise(fd, handle[i], I915_MADV_WILLNEED);
272 if (retained) {
273 bo = gem_handle_to_libdrm_bo(bufmgr, fd,
274 "verify_bo", handle[i]);
275 igt_assert(bo != NULL);
276
277 _ret = drm_intel_gem_bo_map_gtt(bo);
278 igt_assert(!_ret);
279
280 virt = bo->virtual;
281 for (j = 0; j < SIZE/DWORD_SIZE; j++)
282 igt_assert_eq(virt[j], DATA);
283
284 drm_intel_bo_unmap(bo);
285 drm_intel_bo_unreference(bo);
286 }
287 }
288
289 gem_close(fd, new_handle);
290 for (i = 0; i < obj_count; i++)
291 gem_close(fd, handle[i]);
292 }
293
stolen_hibernate(int fd)294 static void stolen_hibernate(int fd)
295 {
296 drm_intel_bo *bo;
297 drm_intel_bo *src, *dest;
298 int obj_count = 0, i = 0;
299 int ret, j;
300 uint32_t handle[MAX_OBJECTS], src_handle;
301 uint32_t *virt;
302
303 gem_require_stolen_support(fd);
304
305 src_handle = gem_create(fd, SIZE);
306 src = gem_handle_to_libdrm_bo(bufmgr, fd,
307 "bo", src_handle);
308 igt_assert(src != NULL);
309
310 ret = drm_intel_gem_bo_map_gtt(src);
311 igt_assert_eq(ret, 0);
312
313 virt = src->virtual;
314 for (j = 0; j < SIZE/DWORD_SIZE; j++) {
315 igt_assert_eq(virt[j], 0);
316 virt[j] = j;
317 }
318
319 drm_intel_bo_unmap(src);
320 /* Exhaust Stolen space */
321 for (i = 0; i < MAX_OBJECTS; i++) {
322 handle[i] = __gem_create_stolen(fd, SIZE);
323 if (!handle[i])
324 break;
325
326 bo = gem_handle_to_libdrm_bo(bufmgr, fd,
327 "verify_bo", handle[i]);
328 igt_assert(bo != NULL);
329 ret = drm_intel_gem_bo_map_gtt(bo);
330 igt_assert_eq(ret, 0);
331
332 virt = bo->virtual;
333 for (j = 0; j < SIZE/DWORD_SIZE; j++)
334 igt_assert_eq(virt[j], 0);
335
336 drm_intel_bo_unmap(bo);
337 drm_intel_bo_unreference(bo);
338
339 obj_count++;
340 }
341
342 /* Assert if atleast one object is allocated from stolen, that
343 * is good enough to verify the content preservation across
344 * hibernation.
345 */
346 igt_assert(obj_count > 0);
347
348 /* Copy data to all stolen backed objects */
349 for (i = 0; i < obj_count; i++) {
350 dest = gem_handle_to_libdrm_bo(bufmgr, fd,
351 "dst_bo", handle[i]);
352 igt_assert(dest != NULL);
353 /* Copy contents to stolen backed objects via blt and
354 * verify post-hibernation, this also helps in identifying
355 * that the operation was completed before going to
356 * hibernation.
357 */
358 intel_copy_bo(batch, dest, src, SIZE);
359 }
360
361 drm_intel_bo_unreference(src);
362
363 igt_system_suspend_autoresume(SUSPEND_STATE_DISK, SUSPEND_TEST_NONE);
364 /* Check if the object's memory contents are intact
365 * across hibernation.
366 */
367 for (i = 0; i < obj_count; i++) {
368 bo = gem_handle_to_libdrm_bo(bufmgr, fd,
369 "verify_bo", handle[i]);
370 igt_assert(bo != NULL);
371 ret = drm_intel_gem_bo_map_gtt(bo);
372 igt_assert_eq(ret, 0);
373 virt = bo->virtual;
374 for (j = 0; j < SIZE/DWORD_SIZE; j++)
375 igt_assert_eq(virt[j], j);
376
377 drm_intel_bo_unmap(bo);
378 drm_intel_bo_unreference(bo);
379 }
380
381 gem_close(fd, src_handle);
382 for (i = 0; i < obj_count; i++)
383 gem_close(fd, handle[i]);
384 }
385
386 static void
stolen_no_mmap(int fd)387 stolen_no_mmap(int fd)
388 {
389 void *addr;
390 uint32_t handle = 0;
391
392 gem_require_stolen_support(fd);
393
394 handle = gem_create_stolen(fd, SIZE);
395
396 addr = __gem_mmap__cpu(fd, handle, 0, SIZE, PROT_READ | PROT_WRITE);
397 igt_assert(addr == NULL);
398
399 gem_close(fd, handle);
400 }
401
402 igt_main
403 {
404 int fd;
405 uint32_t devid;
406
407 igt_skip_on_simulation();
408
409 igt_fixture {
410 fd = drm_open_driver(DRIVER_INTEL);
411 devid = intel_get_drm_devid(fd);
412
413 bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
414 batch = intel_batchbuffer_alloc(bufmgr, devid);
415 }
416
417 igt_subtest("stolen-clear")
418 verify_object_clear(fd);
419
420 /*
421 * stolen mem special cases - checking for non cpu mappable
422 */
423 igt_subtest("stolen-no-mmap")
424 stolen_no_mmap(fd);
425
426 /* checking for pread/pwrite interfaces */
427 igt_subtest("stolen-pwrite")
428 stolen_pwrite(fd);
429
430 igt_subtest("stolen-pread")
431 stolen_pread(fd);
432
433 /* Functional Test - blt copy */
434 igt_subtest("stolen-copy")
435 copy_test(fd);
436
437 igt_subtest("large-object-alloc")
438 stolen_large_obj_alloc(fd);
439
440 /* Filling stolen completely and marking all the objects
441 * purgeable. Then trying to add one more object, to verify
442 * the purging logic.
443 * Again marking all objects WILLNEED and verifying the
444 * contents of the retained objects.
445 */
446 igt_subtest("stolen-fill-purge")
447 stolen_fill_purge_test(fd);
448
449 igt_subtest("stolen-hibernate")
450 stolen_hibernate(fd);
451
452 igt_fixture {
453 intel_batchbuffer_free(batch);
454 drm_intel_bufmgr_destroy(bufmgr);
455 }
456 }
457