2 * Copyright © 2016 Intel Corporation
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:
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
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
25 #include <linux/prime_numbers.h>
27 #include "../i915_selftest.h"
29 #include "mock_gem_device.h"
30 #include "mock_context.h"
33 static bool assert_vma(struct i915_vma
*vma
,
34 struct drm_i915_gem_object
*obj
,
35 struct i915_gem_context
*ctx
)
39 if (vma
->vm
!= &ctx
->ppgtt
->vm
) {
40 pr_err("VMA created with wrong VM\n");
44 if (vma
->size
!= obj
->base
.size
) {
45 pr_err("VMA created with wrong size, found %llu, expected %zu\n",
46 vma
->size
, obj
->base
.size
);
50 if (vma
->ggtt_view
.type
!= I915_GGTT_VIEW_NORMAL
) {
51 pr_err("VMA created with wrong type [%d]\n",
59 static struct i915_vma
*
60 checked_vma_instance(struct drm_i915_gem_object
*obj
,
61 struct i915_address_space
*vm
,
62 struct i915_ggtt_view
*view
)
67 vma
= i915_vma_instance(obj
, vm
, view
);
71 /* Manual checks, will be reinforced by i915_vma_compare! */
73 pr_err("VMA's vm [%p] does not match request [%p]\n",
78 if (i915_is_ggtt(vm
) != i915_vma_is_ggtt(vma
)) {
79 pr_err("VMA ggtt status [%d] does not match parent [%d]\n",
80 i915_vma_is_ggtt(vma
), i915_is_ggtt(vm
));
84 if (i915_vma_compare(vma
, vm
, view
)) {
85 pr_err("i915_vma_compare failed with create parameters!\n");
86 return ERR_PTR(-EINVAL
);
89 if (i915_vma_compare(vma
, vma
->vm
,
90 i915_vma_is_ggtt(vma
) ? &vma
->ggtt_view
: NULL
)) {
91 pr_err("i915_vma_compare failed with itself\n");
92 return ERR_PTR(-EINVAL
);
96 pr_err("i915_vma_compare failed to detect the difference!\n");
97 return ERR_PTR(-EINVAL
);
103 static int create_vmas(struct drm_i915_private
*i915
,
104 struct list_head
*objects
,
105 struct list_head
*contexts
)
107 struct drm_i915_gem_object
*obj
;
108 struct i915_gem_context
*ctx
;
111 list_for_each_entry(obj
, objects
, st_link
) {
112 for (pinned
= 0; pinned
<= 1; pinned
++) {
113 list_for_each_entry(ctx
, contexts
, link
) {
114 struct i915_address_space
*vm
= &ctx
->ppgtt
->vm
;
115 struct i915_vma
*vma
;
118 vma
= checked_vma_instance(obj
, vm
, NULL
);
122 if (!assert_vma(vma
, obj
, ctx
)) {
123 pr_err("VMA lookup/create failed\n");
128 err
= i915_vma_pin(vma
, 0, 0, PIN_USER
);
130 pr_err("Failed to pin VMA\n");
143 static int igt_vma_create(void *arg
)
145 struct i915_ggtt
*ggtt
= arg
;
146 struct drm_i915_private
*i915
= ggtt
->vm
.i915
;
147 struct drm_i915_gem_object
*obj
, *on
;
148 struct i915_gem_context
*ctx
, *cn
;
149 unsigned long num_obj
, num_ctx
;
150 unsigned long no
, nc
;
151 IGT_TIMEOUT(end_time
);
156 /* Exercise creating many vma amonst many objections, checking the
157 * vma creation and lookup routines.
161 for_each_prime_number(num_obj
, ULONG_MAX
- 1) {
162 for (; no
< num_obj
; no
++) {
163 obj
= i915_gem_object_create_internal(i915
, PAGE_SIZE
);
167 list_add(&obj
->st_link
, &objects
);
171 for_each_prime_number(num_ctx
, MAX_CONTEXT_HW_ID
) {
172 for (; nc
< num_ctx
; nc
++) {
173 ctx
= mock_context(i915
, "mock");
177 list_move(&ctx
->link
, &contexts
);
180 err
= create_vmas(i915
, &objects
, &contexts
);
184 if (igt_timeout(end_time
,
185 "%s timed out: after %lu objects in %lu contexts\n",
190 list_for_each_entry_safe(ctx
, cn
, &contexts
, link
) {
191 list_del_init(&ctx
->link
);
192 mock_context_close(ctx
);
197 /* Final pass to lookup all created contexts */
198 err
= create_vmas(i915
, &objects
, &contexts
);
200 list_for_each_entry_safe(ctx
, cn
, &contexts
, link
) {
201 list_del_init(&ctx
->link
);
202 mock_context_close(ctx
);
205 list_for_each_entry_safe(obj
, on
, &objects
, st_link
)
206 i915_gem_object_put(obj
);
213 bool (*assert)(const struct i915_vma
*,
214 const struct pin_mode
*mode
,
219 static bool assert_pin_valid(const struct i915_vma
*vma
,
220 const struct pin_mode
*mode
,
226 if (i915_vma_misplaced(vma
, mode
->size
, 0, mode
->flags
))
233 static bool assert_pin_enospc(const struct i915_vma
*vma
,
234 const struct pin_mode
*mode
,
237 return result
== -ENOSPC
;
241 static bool assert_pin_einval(const struct i915_vma
*vma
,
242 const struct pin_mode
*mode
,
245 return result
== -EINVAL
;
248 static int igt_vma_pin1(void *arg
)
250 struct i915_ggtt
*ggtt
= arg
;
251 const struct pin_mode modes
[] = {
252 #define VALID(sz, fl) { .size = (sz), .flags = (fl), .assert = assert_pin_valid, .string = #sz ", " #fl ", (valid) " }
253 #define __INVALID(sz, fl, check, eval) { .size = (sz), .flags = (fl), .assert = (check), .string = #sz ", " #fl ", (invalid " #eval ")" }
254 #define INVALID(sz, fl) __INVALID(sz, fl, assert_pin_einval, EINVAL)
255 #define NOSPACE(sz, fl) __INVALID(sz, fl, assert_pin_enospc, ENOSPC)
256 VALID(0, PIN_GLOBAL
),
257 VALID(0, PIN_GLOBAL
| PIN_MAPPABLE
),
259 VALID(0, PIN_GLOBAL
| PIN_OFFSET_BIAS
| 4096),
260 VALID(0, PIN_GLOBAL
| PIN_OFFSET_BIAS
| 8192),
261 VALID(0, PIN_GLOBAL
| PIN_OFFSET_BIAS
| (ggtt
->mappable_end
- 4096)),
262 VALID(0, PIN_GLOBAL
| PIN_MAPPABLE
| PIN_OFFSET_BIAS
| (ggtt
->mappable_end
- 4096)),
263 VALID(0, PIN_GLOBAL
| PIN_OFFSET_BIAS
| (ggtt
->vm
.total
- 4096)),
265 VALID(0, PIN_GLOBAL
| PIN_MAPPABLE
| PIN_OFFSET_FIXED
| (ggtt
->mappable_end
- 4096)),
266 INVALID(0, PIN_GLOBAL
| PIN_MAPPABLE
| PIN_OFFSET_FIXED
| ggtt
->mappable_end
),
267 VALID(0, PIN_GLOBAL
| PIN_OFFSET_FIXED
| (ggtt
->vm
.total
- 4096)),
268 INVALID(0, PIN_GLOBAL
| PIN_OFFSET_FIXED
| ggtt
->vm
.total
),
269 INVALID(0, PIN_GLOBAL
| PIN_OFFSET_FIXED
| round_down(U64_MAX
, PAGE_SIZE
)),
271 VALID(4096, PIN_GLOBAL
),
272 VALID(8192, PIN_GLOBAL
),
273 VALID(ggtt
->mappable_end
- 4096, PIN_GLOBAL
| PIN_MAPPABLE
),
274 VALID(ggtt
->mappable_end
, PIN_GLOBAL
| PIN_MAPPABLE
),
275 NOSPACE(ggtt
->mappable_end
+ 4096, PIN_GLOBAL
| PIN_MAPPABLE
),
276 VALID(ggtt
->vm
.total
- 4096, PIN_GLOBAL
),
277 VALID(ggtt
->vm
.total
, PIN_GLOBAL
),
278 NOSPACE(ggtt
->vm
.total
+ 4096, PIN_GLOBAL
),
279 NOSPACE(round_down(U64_MAX
, PAGE_SIZE
), PIN_GLOBAL
),
280 INVALID(8192, PIN_GLOBAL
| PIN_MAPPABLE
| PIN_OFFSET_FIXED
| (ggtt
->mappable_end
- 4096)),
281 INVALID(8192, PIN_GLOBAL
| PIN_OFFSET_FIXED
| (ggtt
->vm
.total
- 4096)),
282 INVALID(8192, PIN_GLOBAL
| PIN_OFFSET_FIXED
| (round_down(U64_MAX
, PAGE_SIZE
) - 4096)),
284 VALID(8192, PIN_GLOBAL
| PIN_OFFSET_BIAS
| (ggtt
->mappable_end
- 4096)),
286 #if !IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
287 /* Misusing BIAS is a programming error (it is not controllable
288 * from userspace) so when debugging is enabled, it explodes.
289 * However, the tests are still quite interesting for checking
290 * variable start, end and size.
292 NOSPACE(0, PIN_GLOBAL
| PIN_MAPPABLE
| PIN_OFFSET_BIAS
| ggtt
->mappable_end
),
293 NOSPACE(0, PIN_GLOBAL
| PIN_OFFSET_BIAS
| ggtt
->vm
.total
),
294 NOSPACE(8192, PIN_GLOBAL
| PIN_MAPPABLE
| PIN_OFFSET_BIAS
| (ggtt
->mappable_end
- 4096)),
295 NOSPACE(8192, PIN_GLOBAL
| PIN_OFFSET_BIAS
| (ggtt
->vm
.total
- 4096)),
303 struct drm_i915_gem_object
*obj
;
304 struct i915_vma
*vma
;
307 /* Exercise all the weird and wonderful i915_vma_pin requests,
308 * focusing on error handling of boundary conditions.
311 GEM_BUG_ON(!drm_mm_clean(&ggtt
->vm
.mm
));
313 obj
= i915_gem_object_create_internal(ggtt
->vm
.i915
, PAGE_SIZE
);
317 vma
= checked_vma_instance(obj
, &ggtt
->vm
, NULL
);
321 for (m
= modes
; m
->assert; m
++) {
322 err
= i915_vma_pin(vma
, m
->size
, 0, m
->flags
);
323 if (!m
->assert(vma
, m
, err
)) {
324 pr_err("%s to pin single page into GGTT with mode[%d:%s]: size=%llx flags=%llx, err=%d\n",
325 m
->assert == assert_pin_valid
? "Failed" : "Unexpectedly succeeded",
326 (int)(m
- modes
), m
->string
, m
->size
, m
->flags
,
336 err
= i915_vma_unbind(vma
);
338 pr_err("Failed to unbind single page from GGTT, err=%d\n", err
);
346 i915_gem_object_put(obj
);
350 static unsigned long rotated_index(const struct intel_rotation_info
*r
,
355 return (r
->plane
[n
].stride
* (r
->plane
[n
].height
- y
- 1) +
356 r
->plane
[n
].offset
+ x
);
359 static struct scatterlist
*
360 assert_rotated(struct drm_i915_gem_object
*obj
,
361 const struct intel_rotation_info
*r
, unsigned int n
,
362 struct scatterlist
*sg
)
366 for (x
= 0; x
< r
->plane
[n
].width
; x
++) {
367 for (y
= 0; y
< r
->plane
[n
].height
; y
++) {
368 unsigned long src_idx
;
372 pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n",
374 return ERR_PTR(-EINVAL
);
377 src_idx
= rotated_index(r
, n
, x
, y
);
378 src
= i915_gem_object_get_dma_address(obj
, src_idx
);
380 if (sg_dma_len(sg
) != PAGE_SIZE
) {
381 pr_err("Invalid sg.length, found %d, expected %lu for rotated page (%d, %d) [src index %lu]\n",
382 sg_dma_len(sg
), PAGE_SIZE
,
384 return ERR_PTR(-EINVAL
);
387 if (sg_dma_address(sg
) != src
) {
388 pr_err("Invalid address for rotated page (%d, %d) [src index %lu]\n",
390 return ERR_PTR(-EINVAL
);
400 static unsigned int rotated_size(const struct intel_rotation_plane_info
*a
,
401 const struct intel_rotation_plane_info
*b
)
403 return a
->width
* a
->height
+ b
->width
* b
->height
;
406 static int igt_vma_rotate(void *arg
)
408 struct i915_ggtt
*ggtt
= arg
;
409 struct i915_address_space
*vm
= &ggtt
->vm
;
410 struct drm_i915_gem_object
*obj
;
411 const struct intel_rotation_plane_info planes
[] = {
412 { .width
= 1, .height
= 1, .stride
= 1 },
413 { .width
= 2, .height
= 2, .stride
= 2 },
414 { .width
= 4, .height
= 4, .stride
= 4 },
415 { .width
= 8, .height
= 8, .stride
= 8 },
417 { .width
= 3, .height
= 5, .stride
= 3 },
418 { .width
= 3, .height
= 5, .stride
= 4 },
419 { .width
= 3, .height
= 5, .stride
= 5 },
421 { .width
= 5, .height
= 3, .stride
= 5 },
422 { .width
= 5, .height
= 3, .stride
= 7 },
423 { .width
= 5, .height
= 3, .stride
= 9 },
425 { .width
= 4, .height
= 6, .stride
= 6 },
426 { .width
= 6, .height
= 4, .stride
= 6 },
429 const unsigned int max_pages
= 64;
432 /* Create VMA for many different combinations of planes and check
433 * that the page layout within the rotated VMA match our expectations.
436 obj
= i915_gem_object_create_internal(vm
->i915
, max_pages
* PAGE_SIZE
);
440 for (a
= planes
; a
->width
; a
++) {
441 for (b
= planes
+ ARRAY_SIZE(planes
); b
-- != planes
; ) {
442 struct i915_ggtt_view view
;
443 unsigned int n
, max_offset
;
445 max_offset
= max(a
->stride
* a
->height
,
446 b
->stride
* b
->height
);
447 GEM_BUG_ON(max_offset
> max_pages
);
448 max_offset
= max_pages
- max_offset
;
450 view
.type
= I915_GGTT_VIEW_ROTATED
;
451 view
.rotated
.plane
[0] = *a
;
452 view
.rotated
.plane
[1] = *b
;
454 for_each_prime_number_from(view
.rotated
.plane
[0].offset
, 0, max_offset
) {
455 for_each_prime_number_from(view
.rotated
.plane
[1].offset
, 0, max_offset
) {
456 struct scatterlist
*sg
;
457 struct i915_vma
*vma
;
459 vma
= checked_vma_instance(obj
, vm
, &view
);
465 err
= i915_vma_pin(vma
, 0, 0, PIN_GLOBAL
);
467 pr_err("Failed to pin VMA, err=%d\n", err
);
471 if (vma
->size
!= rotated_size(a
, b
) * PAGE_SIZE
) {
472 pr_err("VMA is wrong size, expected %lu, found %llu\n",
473 PAGE_SIZE
* rotated_size(a
, b
), vma
->size
);
478 if (vma
->pages
->nents
!= rotated_size(a
, b
)) {
479 pr_err("sg table is wrong sizeo, expected %u, found %u nents\n",
480 rotated_size(a
, b
), vma
->pages
->nents
);
485 if (vma
->node
.size
< vma
->size
) {
486 pr_err("VMA binding too small, expected %llu, found %llu\n",
487 vma
->size
, vma
->node
.size
);
492 if (vma
->pages
== obj
->mm
.pages
) {
493 pr_err("VMA using unrotated object pages!\n");
498 sg
= vma
->pages
->sgl
;
499 for (n
= 0; n
< ARRAY_SIZE(view
.rotated
.plane
); n
++) {
500 sg
= assert_rotated(obj
, &view
.rotated
, n
, sg
);
502 pr_err("Inconsistent VMA pages for plane %d: [(%d, %d, %d, %d), (%d, %d, %d, %d)]\n", n
,
503 view
.rotated
.plane
[0].width
,
504 view
.rotated
.plane
[0].height
,
505 view
.rotated
.plane
[0].stride
,
506 view
.rotated
.plane
[0].offset
,
507 view
.rotated
.plane
[1].width
,
508 view
.rotated
.plane
[1].height
,
509 view
.rotated
.plane
[1].stride
,
510 view
.rotated
.plane
[1].offset
);
523 i915_gem_object_put(obj
);
528 static bool assert_partial(struct drm_i915_gem_object
*obj
,
529 struct i915_vma
*vma
,
530 unsigned long offset
,
536 for_each_sgt_dma(dma
, sgt
, vma
->pages
) {
540 pr_err("Partial scattergather list too long\n");
544 src
= i915_gem_object_get_dma_address(obj
, offset
);
546 pr_err("DMA mismatch for partial page offset %lu\n",
558 static bool assert_pin(struct i915_vma
*vma
,
559 struct i915_ggtt_view
*view
,
565 if (vma
->size
!= size
) {
566 pr_err("(%s) VMA is wrong size, expected %llu, found %llu\n",
567 name
, size
, vma
->size
);
571 if (vma
->node
.size
< vma
->size
) {
572 pr_err("(%s) VMA binding too small, expected %llu, found %llu\n",
573 name
, vma
->size
, vma
->node
.size
);
577 if (view
&& view
->type
!= I915_GGTT_VIEW_NORMAL
) {
578 if (memcmp(&vma
->ggtt_view
, view
, sizeof(*view
))) {
579 pr_err("(%s) VMA mismatch upon creation!\n",
584 if (vma
->pages
== vma
->obj
->mm
.pages
) {
585 pr_err("(%s) VMA using original object pages!\n",
590 if (vma
->ggtt_view
.type
!= I915_GGTT_VIEW_NORMAL
) {
591 pr_err("Not the normal ggtt view! Found %d\n",
592 vma
->ggtt_view
.type
);
596 if (vma
->pages
!= vma
->obj
->mm
.pages
) {
597 pr_err("VMA not using object pages!\n");
605 static int igt_vma_partial(void *arg
)
607 struct i915_ggtt
*ggtt
= arg
;
608 struct i915_address_space
*vm
= &ggtt
->vm
;
609 const unsigned int npages
= 1021; /* prime! */
610 struct drm_i915_gem_object
*obj
;
618 unsigned int sz
, offset
;
619 struct i915_vma
*vma
;
622 /* Create lots of different VMA for the object and check that
623 * we are returned the same VMA when we later request the same range.
626 obj
= i915_gem_object_create_internal(vm
->i915
, npages
* PAGE_SIZE
);
630 for (p
= phases
; p
->name
; p
++) { /* exercise both create/lookup */
631 unsigned int count
, nvma
;
634 for_each_prime_number_from(sz
, 1, npages
) {
635 for_each_prime_number_from(offset
, 0, npages
- sz
) {
636 struct i915_ggtt_view view
;
638 view
.type
= I915_GGTT_VIEW_PARTIAL
;
639 view
.partial
.offset
= offset
;
640 view
.partial
.size
= sz
;
643 view
.type
= I915_GGTT_VIEW_NORMAL
;
645 vma
= checked_vma_instance(obj
, vm
, &view
);
651 err
= i915_vma_pin(vma
, 0, 0, PIN_GLOBAL
);
655 if (!assert_pin(vma
, &view
, sz
*PAGE_SIZE
, p
->name
)) {
656 pr_err("(%s) Inconsistent partial pinning for (offset=%d, size=%d)\n",
657 p
->name
, offset
, sz
);
662 if (!assert_partial(obj
, vma
, offset
, sz
)) {
663 pr_err("(%s) Inconsistent partial pages for (offset=%d, size=%d)\n",
664 p
->name
, offset
, sz
);
675 list_for_each_entry(vma
, &obj
->vma
.list
, obj_link
)
678 pr_err("(%s) All partial vma were not recorded on the obj->vma_list: found %u, expected %u\n",
679 p
->name
, count
, nvma
);
684 /* Check that we did create the whole object mapping */
685 vma
= checked_vma_instance(obj
, vm
, NULL
);
691 err
= i915_vma_pin(vma
, 0, 0, PIN_GLOBAL
);
695 if (!assert_pin(vma
, NULL
, obj
->base
.size
, p
->name
)) {
696 pr_err("(%s) inconsistent full pin\n", p
->name
);
704 list_for_each_entry(vma
, &obj
->vma
.list
, obj_link
)
707 pr_err("(%s) allocated an extra full vma!\n", p
->name
);
714 i915_gem_object_put(obj
);
719 int i915_vma_mock_selftests(void)
721 static const struct i915_subtest tests
[] = {
722 SUBTEST(igt_vma_create
),
723 SUBTEST(igt_vma_pin1
),
724 SUBTEST(igt_vma_rotate
),
725 SUBTEST(igt_vma_partial
),
727 struct drm_i915_private
*i915
;
728 struct i915_ggtt ggtt
;
731 i915
= mock_gem_device();
735 mock_init_ggtt(i915
, &ggtt
);
737 mutex_lock(&i915
->drm
.struct_mutex
);
738 err
= i915_subtests(tests
, &ggtt
);
739 mock_device_flush(i915
);
740 mutex_unlock(&i915
->drm
.struct_mutex
);
742 i915_gem_drain_freed_objects(i915
);
744 mock_fini_ggtt(&ggtt
);
745 drm_dev_put(&i915
->drm
);