162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright © 2016 Intel Corporation
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next
1262306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
1362306a36Sopenharmony_ci * Software.
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1662306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1762306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1862306a36Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1962306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2062306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2162306a36Sopenharmony_ci * IN THE SOFTWARE.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/prime_numbers.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "gem/i915_gem_context.h"
2862306a36Sopenharmony_ci#include "gem/i915_gem_internal.h"
2962306a36Sopenharmony_ci#include "gem/selftests/mock_context.h"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "i915_scatterlist.h"
3262306a36Sopenharmony_ci#include "i915_selftest.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include "mock_gem_device.h"
3562306a36Sopenharmony_ci#include "mock_gtt.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic bool assert_vma(struct i915_vma *vma,
3862306a36Sopenharmony_ci		       struct drm_i915_gem_object *obj,
3962306a36Sopenharmony_ci		       struct i915_gem_context *ctx)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	bool ok = true;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (vma->vm != ctx->vm) {
4462306a36Sopenharmony_ci		pr_err("VMA created with wrong VM\n");
4562306a36Sopenharmony_ci		ok = false;
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (vma->size != obj->base.size) {
4962306a36Sopenharmony_ci		pr_err("VMA created with wrong size, found %llu, expected %zu\n",
5062306a36Sopenharmony_ci		       vma->size, obj->base.size);
5162306a36Sopenharmony_ci		ok = false;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (vma->gtt_view.type != I915_GTT_VIEW_NORMAL) {
5562306a36Sopenharmony_ci		pr_err("VMA created with wrong type [%d]\n",
5662306a36Sopenharmony_ci		       vma->gtt_view.type);
5762306a36Sopenharmony_ci		ok = false;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return ok;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic struct i915_vma *
6462306a36Sopenharmony_cichecked_vma_instance(struct drm_i915_gem_object *obj,
6562306a36Sopenharmony_ci		     struct i915_address_space *vm,
6662306a36Sopenharmony_ci		     const struct i915_gtt_view *view)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct i915_vma *vma;
6962306a36Sopenharmony_ci	bool ok = true;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	vma = i915_vma_instance(obj, vm, view);
7262306a36Sopenharmony_ci	if (IS_ERR(vma))
7362306a36Sopenharmony_ci		return vma;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* Manual checks, will be reinforced by i915_vma_compare! */
7662306a36Sopenharmony_ci	if (vma->vm != vm) {
7762306a36Sopenharmony_ci		pr_err("VMA's vm [%p] does not match request [%p]\n",
7862306a36Sopenharmony_ci		       vma->vm, vm);
7962306a36Sopenharmony_ci		ok = false;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (i915_is_ggtt(vm) != i915_vma_is_ggtt(vma)) {
8362306a36Sopenharmony_ci		pr_err("VMA ggtt status [%d] does not match parent [%d]\n",
8462306a36Sopenharmony_ci		       i915_vma_is_ggtt(vma), i915_is_ggtt(vm));
8562306a36Sopenharmony_ci		ok = false;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (i915_vma_compare(vma, vm, view)) {
8962306a36Sopenharmony_ci		pr_err("i915_vma_compare failed with create parameters!\n");
9062306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (i915_vma_compare(vma, vma->vm,
9462306a36Sopenharmony_ci			     i915_vma_is_ggtt(vma) ? &vma->gtt_view : NULL)) {
9562306a36Sopenharmony_ci		pr_err("i915_vma_compare failed with itself\n");
9662306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (!ok) {
10062306a36Sopenharmony_ci		pr_err("i915_vma_compare failed to detect the difference!\n");
10162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return vma;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int create_vmas(struct drm_i915_private *i915,
10862306a36Sopenharmony_ci		       struct list_head *objects,
10962306a36Sopenharmony_ci		       struct list_head *contexts)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct drm_i915_gem_object *obj;
11262306a36Sopenharmony_ci	struct i915_gem_context *ctx;
11362306a36Sopenharmony_ci	int pinned;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	list_for_each_entry(obj, objects, st_link) {
11662306a36Sopenharmony_ci		for (pinned = 0; pinned <= 1; pinned++) {
11762306a36Sopenharmony_ci			list_for_each_entry(ctx, contexts, link) {
11862306a36Sopenharmony_ci				struct i915_address_space *vm;
11962306a36Sopenharmony_ci				struct i915_vma *vma;
12062306a36Sopenharmony_ci				int err;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci				vm = i915_gem_context_get_eb_vm(ctx);
12362306a36Sopenharmony_ci				vma = checked_vma_instance(obj, vm, NULL);
12462306a36Sopenharmony_ci				i915_vm_put(vm);
12562306a36Sopenharmony_ci				if (IS_ERR(vma))
12662306a36Sopenharmony_ci					return PTR_ERR(vma);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci				if (!assert_vma(vma, obj, ctx)) {
12962306a36Sopenharmony_ci					pr_err("VMA lookup/create failed\n");
13062306a36Sopenharmony_ci					return -EINVAL;
13162306a36Sopenharmony_ci				}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci				if (!pinned) {
13462306a36Sopenharmony_ci					err = i915_vma_pin(vma, 0, 0, PIN_USER);
13562306a36Sopenharmony_ci					if (err) {
13662306a36Sopenharmony_ci						pr_err("Failed to pin VMA\n");
13762306a36Sopenharmony_ci						return err;
13862306a36Sopenharmony_ci					}
13962306a36Sopenharmony_ci				} else {
14062306a36Sopenharmony_ci					i915_vma_unpin(vma);
14162306a36Sopenharmony_ci				}
14262306a36Sopenharmony_ci			}
14362306a36Sopenharmony_ci		}
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return 0;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int igt_vma_create(void *arg)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
15262306a36Sopenharmony_ci	struct drm_i915_private *i915 = ggtt->vm.i915;
15362306a36Sopenharmony_ci	struct drm_i915_gem_object *obj, *on;
15462306a36Sopenharmony_ci	struct i915_gem_context *ctx, *cn;
15562306a36Sopenharmony_ci	unsigned long num_obj, num_ctx;
15662306a36Sopenharmony_ci	unsigned long no, nc;
15762306a36Sopenharmony_ci	IGT_TIMEOUT(end_time);
15862306a36Sopenharmony_ci	LIST_HEAD(contexts);
15962306a36Sopenharmony_ci	LIST_HEAD(objects);
16062306a36Sopenharmony_ci	int err = -ENOMEM;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* Exercise creating many vma amonst many objections, checking the
16362306a36Sopenharmony_ci	 * vma creation and lookup routines.
16462306a36Sopenharmony_ci	 */
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	no = 0;
16762306a36Sopenharmony_ci	for_each_prime_number(num_obj, ULONG_MAX - 1) {
16862306a36Sopenharmony_ci		for (; no < num_obj; no++) {
16962306a36Sopenharmony_ci			obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
17062306a36Sopenharmony_ci			if (IS_ERR(obj))
17162306a36Sopenharmony_ci				goto out;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci			list_add(&obj->st_link, &objects);
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		nc = 0;
17762306a36Sopenharmony_ci		for_each_prime_number(num_ctx, 2 * BITS_PER_LONG) {
17862306a36Sopenharmony_ci			for (; nc < num_ctx; nc++) {
17962306a36Sopenharmony_ci				ctx = mock_context(i915, "mock");
18062306a36Sopenharmony_ci				if (!ctx)
18162306a36Sopenharmony_ci					goto out;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci				list_move(&ctx->link, &contexts);
18462306a36Sopenharmony_ci			}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci			err = create_vmas(i915, &objects, &contexts);
18762306a36Sopenharmony_ci			if (err)
18862306a36Sopenharmony_ci				goto out;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci			if (igt_timeout(end_time,
19162306a36Sopenharmony_ci					"%s timed out: after %lu objects in %lu contexts\n",
19262306a36Sopenharmony_ci					__func__, no, nc))
19362306a36Sopenharmony_ci				goto end;
19462306a36Sopenharmony_ci		}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		list_for_each_entry_safe(ctx, cn, &contexts, link) {
19762306a36Sopenharmony_ci			list_del_init(&ctx->link);
19862306a36Sopenharmony_ci			mock_context_close(ctx);
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		cond_resched();
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ciend:
20562306a36Sopenharmony_ci	/* Final pass to lookup all created contexts */
20662306a36Sopenharmony_ci	err = create_vmas(i915, &objects, &contexts);
20762306a36Sopenharmony_ciout:
20862306a36Sopenharmony_ci	list_for_each_entry_safe(ctx, cn, &contexts, link) {
20962306a36Sopenharmony_ci		list_del_init(&ctx->link);
21062306a36Sopenharmony_ci		mock_context_close(ctx);
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	list_for_each_entry_safe(obj, on, &objects, st_link)
21462306a36Sopenharmony_ci		i915_gem_object_put(obj);
21562306a36Sopenharmony_ci	return err;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistruct pin_mode {
21962306a36Sopenharmony_ci	u64 size;
22062306a36Sopenharmony_ci	u64 flags;
22162306a36Sopenharmony_ci	bool (*assert)(const struct i915_vma *,
22262306a36Sopenharmony_ci		       const struct pin_mode *mode,
22362306a36Sopenharmony_ci		       int result);
22462306a36Sopenharmony_ci	const char *string;
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic bool assert_pin_valid(const struct i915_vma *vma,
22862306a36Sopenharmony_ci			     const struct pin_mode *mode,
22962306a36Sopenharmony_ci			     int result)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	if (result)
23262306a36Sopenharmony_ci		return false;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (i915_vma_misplaced(vma, mode->size, 0, mode->flags))
23562306a36Sopenharmony_ci		return false;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return true;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci__maybe_unused
24162306a36Sopenharmony_cistatic bool assert_pin_enospc(const struct i915_vma *vma,
24262306a36Sopenharmony_ci			      const struct pin_mode *mode,
24362306a36Sopenharmony_ci			      int result)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	return result == -ENOSPC;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci__maybe_unused
24962306a36Sopenharmony_cistatic bool assert_pin_einval(const struct i915_vma *vma,
25062306a36Sopenharmony_ci			      const struct pin_mode *mode,
25162306a36Sopenharmony_ci			      int result)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	return result == -EINVAL;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic int igt_vma_pin1(void *arg)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
25962306a36Sopenharmony_ci	const struct pin_mode modes[] = {
26062306a36Sopenharmony_ci#define VALID(sz, fl) { .size = (sz), .flags = (fl), .assert = assert_pin_valid, .string = #sz ", " #fl ", (valid) " }
26162306a36Sopenharmony_ci#define __INVALID(sz, fl, check, eval) { .size = (sz), .flags = (fl), .assert = (check), .string = #sz ", " #fl ", (invalid " #eval ")" }
26262306a36Sopenharmony_ci#define INVALID(sz, fl) __INVALID(sz, fl, assert_pin_einval, EINVAL)
26362306a36Sopenharmony_ci#define NOSPACE(sz, fl) __INVALID(sz, fl, assert_pin_enospc, ENOSPC)
26462306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL),
26562306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_MAPPABLE),
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | 4096),
26862306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | 8192),
26962306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
27062306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
27162306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->vm.total - 4096)),
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (ggtt->mappable_end - 4096)),
27462306a36Sopenharmony_ci		INVALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | ggtt->mappable_end),
27562306a36Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | (ggtt->vm.total - 4096)),
27662306a36Sopenharmony_ci		INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | ggtt->vm.total),
27762306a36Sopenharmony_ci		INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | round_down(U64_MAX, PAGE_SIZE)),
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		VALID(4096, PIN_GLOBAL),
28062306a36Sopenharmony_ci		VALID(8192, PIN_GLOBAL),
28162306a36Sopenharmony_ci		VALID(ggtt->mappable_end - 4096, PIN_GLOBAL | PIN_MAPPABLE),
28262306a36Sopenharmony_ci		VALID(ggtt->mappable_end, PIN_GLOBAL | PIN_MAPPABLE),
28362306a36Sopenharmony_ci		NOSPACE(ggtt->mappable_end + 4096, PIN_GLOBAL | PIN_MAPPABLE),
28462306a36Sopenharmony_ci		VALID(ggtt->vm.total - 4096, PIN_GLOBAL),
28562306a36Sopenharmony_ci		VALID(ggtt->vm.total, PIN_GLOBAL),
28662306a36Sopenharmony_ci		NOSPACE(ggtt->vm.total + 4096, PIN_GLOBAL),
28762306a36Sopenharmony_ci		NOSPACE(round_down(U64_MAX, PAGE_SIZE), PIN_GLOBAL),
28862306a36Sopenharmony_ci		INVALID(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (ggtt->mappable_end - 4096)),
28962306a36Sopenharmony_ci		INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (ggtt->vm.total - 4096)),
29062306a36Sopenharmony_ci		INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (round_down(U64_MAX, PAGE_SIZE) - 4096)),
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci		VALID(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci#if !IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
29562306a36Sopenharmony_ci		/* Misusing BIAS is a programming error (it is not controllable
29662306a36Sopenharmony_ci		 * from userspace) so when debugging is enabled, it explodes.
29762306a36Sopenharmony_ci		 * However, the tests are still quite interesting for checking
29862306a36Sopenharmony_ci		 * variable start, end and size.
29962306a36Sopenharmony_ci		 */
30062306a36Sopenharmony_ci		NOSPACE(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | ggtt->mappable_end),
30162306a36Sopenharmony_ci		NOSPACE(0, PIN_GLOBAL | PIN_OFFSET_BIAS | ggtt->vm.total),
30262306a36Sopenharmony_ci		NOSPACE(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
30362306a36Sopenharmony_ci		NOSPACE(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->vm.total - 4096)),
30462306a36Sopenharmony_ci#endif
30562306a36Sopenharmony_ci		{ },
30662306a36Sopenharmony_ci#undef NOSPACE
30762306a36Sopenharmony_ci#undef INVALID
30862306a36Sopenharmony_ci#undef __INVALID
30962306a36Sopenharmony_ci#undef VALID
31062306a36Sopenharmony_ci	}, *m;
31162306a36Sopenharmony_ci	struct drm_i915_gem_object *obj;
31262306a36Sopenharmony_ci	struct i915_vma *vma;
31362306a36Sopenharmony_ci	int err = -EINVAL;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Exercise all the weird and wonderful i915_vma_pin requests,
31662306a36Sopenharmony_ci	 * focusing on error handling of boundary conditions.
31762306a36Sopenharmony_ci	 */
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	GEM_BUG_ON(!drm_mm_clean(&ggtt->vm.mm));
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	obj = i915_gem_object_create_internal(ggtt->vm.i915, PAGE_SIZE);
32262306a36Sopenharmony_ci	if (IS_ERR(obj))
32362306a36Sopenharmony_ci		return PTR_ERR(obj);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	vma = checked_vma_instance(obj, &ggtt->vm, NULL);
32662306a36Sopenharmony_ci	if (IS_ERR(vma))
32762306a36Sopenharmony_ci		goto out;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	for (m = modes; m->assert; m++) {
33062306a36Sopenharmony_ci		err = i915_vma_pin(vma, m->size, 0, m->flags);
33162306a36Sopenharmony_ci		if (!m->assert(vma, m, err)) {
33262306a36Sopenharmony_ci			pr_err("%s to pin single page into GGTT with mode[%d:%s]: size=%llx flags=%llx, err=%d\n",
33362306a36Sopenharmony_ci			       m->assert == assert_pin_valid ? "Failed" : "Unexpectedly succeeded",
33462306a36Sopenharmony_ci			       (int)(m - modes), m->string, m->size, m->flags,
33562306a36Sopenharmony_ci			       err);
33662306a36Sopenharmony_ci			if (!err)
33762306a36Sopenharmony_ci				i915_vma_unpin(vma);
33862306a36Sopenharmony_ci			err = -EINVAL;
33962306a36Sopenharmony_ci			goto out;
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		if (!err) {
34362306a36Sopenharmony_ci			i915_vma_unpin(vma);
34462306a36Sopenharmony_ci			err = i915_vma_unbind_unlocked(vma);
34562306a36Sopenharmony_ci			if (err) {
34662306a36Sopenharmony_ci				pr_err("Failed to unbind single page from GGTT, err=%d\n", err);
34762306a36Sopenharmony_ci				goto out;
34862306a36Sopenharmony_ci			}
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		cond_resched();
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	err = 0;
35562306a36Sopenharmony_ciout:
35662306a36Sopenharmony_ci	i915_gem_object_put(obj);
35762306a36Sopenharmony_ci	return err;
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic unsigned long rotated_index(const struct intel_rotation_info *r,
36162306a36Sopenharmony_ci				   unsigned int n,
36262306a36Sopenharmony_ci				   unsigned int x,
36362306a36Sopenharmony_ci				   unsigned int y)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	return (r->plane[n].src_stride * (r->plane[n].height - y - 1) +
36662306a36Sopenharmony_ci		r->plane[n].offset + x);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic struct scatterlist *
37062306a36Sopenharmony_ciassert_rotated(struct drm_i915_gem_object *obj,
37162306a36Sopenharmony_ci	       const struct intel_rotation_info *r, unsigned int n,
37262306a36Sopenharmony_ci	       struct scatterlist *sg)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	unsigned int x, y;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	for (x = 0; x < r->plane[n].width; x++) {
37762306a36Sopenharmony_ci		unsigned int left;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		for (y = 0; y < r->plane[n].height; y++) {
38062306a36Sopenharmony_ci			unsigned long src_idx;
38162306a36Sopenharmony_ci			dma_addr_t src;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci			if (!sg) {
38462306a36Sopenharmony_ci				pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n",
38562306a36Sopenharmony_ci				       n, x, y);
38662306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
38762306a36Sopenharmony_ci			}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci			src_idx = rotated_index(r, n, x, y);
39062306a36Sopenharmony_ci			src = i915_gem_object_get_dma_address(obj, src_idx);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci			if (sg_dma_len(sg) != PAGE_SIZE) {
39362306a36Sopenharmony_ci				pr_err("Invalid sg.length, found %d, expected %lu for rotated page (%d, %d) [src index %lu]\n",
39462306a36Sopenharmony_ci				       sg_dma_len(sg), PAGE_SIZE,
39562306a36Sopenharmony_ci				       x, y, src_idx);
39662306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
39762306a36Sopenharmony_ci			}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci			if (sg_dma_address(sg) != src) {
40062306a36Sopenharmony_ci				pr_err("Invalid address for rotated page (%d, %d) [src index %lu]\n",
40162306a36Sopenharmony_ci				       x, y, src_idx);
40262306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
40362306a36Sopenharmony_ci			}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci			sg = sg_next(sg);
40662306a36Sopenharmony_ci		}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		left = (r->plane[n].dst_stride - y) * PAGE_SIZE;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		if (!left)
41162306a36Sopenharmony_ci			continue;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		if (!sg) {
41462306a36Sopenharmony_ci			pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n",
41562306a36Sopenharmony_ci			       n, x, y);
41662306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		if (sg_dma_len(sg) != left) {
42062306a36Sopenharmony_ci			pr_err("Invalid sg.length, found %d, expected %u for rotated page (%d, %d)\n",
42162306a36Sopenharmony_ci			       sg_dma_len(sg), left, x, y);
42262306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
42362306a36Sopenharmony_ci		}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		if (sg_dma_address(sg) != 0) {
42662306a36Sopenharmony_ci			pr_err("Invalid address, found %pad, expected 0 for remapped page (%d, %d)\n",
42762306a36Sopenharmony_ci			       &sg_dma_address(sg), x, y);
42862306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
42962306a36Sopenharmony_ci		}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		sg = sg_next(sg);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return sg;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic unsigned long remapped_index(const struct intel_remapped_info *r,
43862306a36Sopenharmony_ci				    unsigned int n,
43962306a36Sopenharmony_ci				    unsigned int x,
44062306a36Sopenharmony_ci				    unsigned int y)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	return (r->plane[n].src_stride * y +
44362306a36Sopenharmony_ci		r->plane[n].offset + x);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic struct scatterlist *
44762306a36Sopenharmony_ciassert_remapped(struct drm_i915_gem_object *obj,
44862306a36Sopenharmony_ci		const struct intel_remapped_info *r, unsigned int n,
44962306a36Sopenharmony_ci		struct scatterlist *sg)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	unsigned int x, y;
45262306a36Sopenharmony_ci	unsigned int left = 0;
45362306a36Sopenharmony_ci	unsigned int offset;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	for (y = 0; y < r->plane[n].height; y++) {
45662306a36Sopenharmony_ci		for (x = 0; x < r->plane[n].width; x++) {
45762306a36Sopenharmony_ci			unsigned long src_idx;
45862306a36Sopenharmony_ci			dma_addr_t src;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci			if (!sg) {
46162306a36Sopenharmony_ci				pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n",
46262306a36Sopenharmony_ci				       n, x, y);
46362306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
46462306a36Sopenharmony_ci			}
46562306a36Sopenharmony_ci			if (!left) {
46662306a36Sopenharmony_ci				offset = 0;
46762306a36Sopenharmony_ci				left = sg_dma_len(sg);
46862306a36Sopenharmony_ci			}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci			src_idx = remapped_index(r, n, x, y);
47162306a36Sopenharmony_ci			src = i915_gem_object_get_dma_address(obj, src_idx);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci			if (left < PAGE_SIZE || left & (PAGE_SIZE-1)) {
47462306a36Sopenharmony_ci				pr_err("Invalid sg.length, found %d, expected %lu for remapped page (%d, %d) [src index %lu]\n",
47562306a36Sopenharmony_ci				       sg_dma_len(sg), PAGE_SIZE,
47662306a36Sopenharmony_ci				       x, y, src_idx);
47762306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
47862306a36Sopenharmony_ci			}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci			if (sg_dma_address(sg) + offset != src) {
48162306a36Sopenharmony_ci				pr_err("Invalid address for remapped page (%d, %d) [src index %lu]\n",
48262306a36Sopenharmony_ci				       x, y, src_idx);
48362306a36Sopenharmony_ci				return ERR_PTR(-EINVAL);
48462306a36Sopenharmony_ci			}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci			left -= PAGE_SIZE;
48762306a36Sopenharmony_ci			offset += PAGE_SIZE;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci			if (!left)
49162306a36Sopenharmony_ci				sg = sg_next(sg);
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci		if (left) {
49562306a36Sopenharmony_ci			pr_err("Unexpected sg tail with %d size for remapped page (%d, %d)\n",
49662306a36Sopenharmony_ci			       left,
49762306a36Sopenharmony_ci			       x, y);
49862306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
49962306a36Sopenharmony_ci		}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		left = (r->plane[n].dst_stride - r->plane[n].width) * PAGE_SIZE;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		if (!left)
50462306a36Sopenharmony_ci			continue;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		if (!sg) {
50762306a36Sopenharmony_ci			pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n",
50862306a36Sopenharmony_ci			       n, x, y);
50962306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
51062306a36Sopenharmony_ci		}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		if (sg_dma_len(sg) != left) {
51362306a36Sopenharmony_ci			pr_err("Invalid sg.length, found %u, expected %u for remapped page (%d, %d)\n",
51462306a36Sopenharmony_ci			       sg_dma_len(sg), left,
51562306a36Sopenharmony_ci			       x, y);
51662306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		if (sg_dma_address(sg) != 0) {
52062306a36Sopenharmony_ci			pr_err("Invalid address, found %pad, expected 0 for remapped page (%d, %d)\n",
52162306a36Sopenharmony_ci			       &sg_dma_address(sg),
52262306a36Sopenharmony_ci			       x, y);
52362306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci		sg = sg_next(sg);
52762306a36Sopenharmony_ci		left = 0;
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return sg;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic unsigned int remapped_size(enum i915_gtt_view_type view_type,
53462306a36Sopenharmony_ci				  const struct intel_remapped_plane_info *a,
53562306a36Sopenharmony_ci				  const struct intel_remapped_plane_info *b)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (view_type == I915_GTT_VIEW_ROTATED)
53962306a36Sopenharmony_ci		return a->dst_stride * a->width + b->dst_stride * b->width;
54062306a36Sopenharmony_ci	else
54162306a36Sopenharmony_ci		return a->dst_stride * a->height + b->dst_stride * b->height;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic int igt_vma_rotate_remap(void *arg)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
54762306a36Sopenharmony_ci	struct i915_address_space *vm = &ggtt->vm;
54862306a36Sopenharmony_ci	struct drm_i915_gem_object *obj;
54962306a36Sopenharmony_ci	const struct intel_remapped_plane_info planes[] = {
55062306a36Sopenharmony_ci		{ .width = 1, .height = 1, .src_stride = 1 },
55162306a36Sopenharmony_ci		{ .width = 2, .height = 2, .src_stride = 2 },
55262306a36Sopenharmony_ci		{ .width = 4, .height = 4, .src_stride = 4 },
55362306a36Sopenharmony_ci		{ .width = 8, .height = 8, .src_stride = 8 },
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		{ .width = 3, .height = 5, .src_stride = 3 },
55662306a36Sopenharmony_ci		{ .width = 3, .height = 5, .src_stride = 4 },
55762306a36Sopenharmony_ci		{ .width = 3, .height = 5, .src_stride = 5 },
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		{ .width = 5, .height = 3, .src_stride = 5 },
56062306a36Sopenharmony_ci		{ .width = 5, .height = 3, .src_stride = 7 },
56162306a36Sopenharmony_ci		{ .width = 5, .height = 3, .src_stride = 9 },
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		{ .width = 4, .height = 6, .src_stride = 6 },
56462306a36Sopenharmony_ci		{ .width = 6, .height = 4, .src_stride = 6 },
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci		{ .width = 2, .height = 2, .src_stride = 2, .dst_stride = 2 },
56762306a36Sopenharmony_ci		{ .width = 3, .height = 3, .src_stride = 3, .dst_stride = 4 },
56862306a36Sopenharmony_ci		{ .width = 5, .height = 6, .src_stride = 7, .dst_stride = 8 },
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		{ }
57162306a36Sopenharmony_ci	}, *a, *b;
57262306a36Sopenharmony_ci	enum i915_gtt_view_type types[] = {
57362306a36Sopenharmony_ci		I915_GTT_VIEW_ROTATED,
57462306a36Sopenharmony_ci		I915_GTT_VIEW_REMAPPED,
57562306a36Sopenharmony_ci		0,
57662306a36Sopenharmony_ci	}, *t;
57762306a36Sopenharmony_ci	const unsigned int max_pages = 64;
57862306a36Sopenharmony_ci	int err = -ENOMEM;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/* Create VMA for many different combinations of planes and check
58162306a36Sopenharmony_ci	 * that the page layout within the rotated VMA match our expectations.
58262306a36Sopenharmony_ci	 */
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	obj = i915_gem_object_create_internal(vm->i915, max_pages * PAGE_SIZE);
58562306a36Sopenharmony_ci	if (IS_ERR(obj))
58662306a36Sopenharmony_ci		goto out;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	for (t = types; *t; t++) {
58962306a36Sopenharmony_ci	for (a = planes; a->width; a++) {
59062306a36Sopenharmony_ci		for (b = planes + ARRAY_SIZE(planes); b-- != planes; ) {
59162306a36Sopenharmony_ci			struct i915_gtt_view view = {
59262306a36Sopenharmony_ci				.type = *t,
59362306a36Sopenharmony_ci				.remapped.plane[0] = *a,
59462306a36Sopenharmony_ci				.remapped.plane[1] = *b,
59562306a36Sopenharmony_ci			};
59662306a36Sopenharmony_ci			struct intel_remapped_plane_info *plane_info = view.remapped.plane;
59762306a36Sopenharmony_ci			unsigned int n, max_offset;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci			max_offset = max(plane_info[0].src_stride * plane_info[0].height,
60062306a36Sopenharmony_ci					 plane_info[1].src_stride * plane_info[1].height);
60162306a36Sopenharmony_ci			GEM_BUG_ON(max_offset > max_pages);
60262306a36Sopenharmony_ci			max_offset = max_pages - max_offset;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci			if (!plane_info[0].dst_stride)
60562306a36Sopenharmony_ci				plane_info[0].dst_stride = view.type == I915_GTT_VIEW_ROTATED ?
60662306a36Sopenharmony_ci									plane_info[0].height :
60762306a36Sopenharmony_ci									plane_info[0].width;
60862306a36Sopenharmony_ci			if (!plane_info[1].dst_stride)
60962306a36Sopenharmony_ci				plane_info[1].dst_stride = view.type == I915_GTT_VIEW_ROTATED ?
61062306a36Sopenharmony_ci									plane_info[1].height :
61162306a36Sopenharmony_ci									plane_info[1].width;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci			for_each_prime_number_from(plane_info[0].offset, 0, max_offset) {
61462306a36Sopenharmony_ci				for_each_prime_number_from(plane_info[1].offset, 0, max_offset) {
61562306a36Sopenharmony_ci					struct scatterlist *sg;
61662306a36Sopenharmony_ci					struct i915_vma *vma;
61762306a36Sopenharmony_ci					unsigned int expected_pages;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci					vma = checked_vma_instance(obj, vm, &view);
62062306a36Sopenharmony_ci					if (IS_ERR(vma)) {
62162306a36Sopenharmony_ci						err = PTR_ERR(vma);
62262306a36Sopenharmony_ci						goto out_object;
62362306a36Sopenharmony_ci					}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci					err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
62662306a36Sopenharmony_ci					if (err) {
62762306a36Sopenharmony_ci						pr_err("Failed to pin VMA, err=%d\n", err);
62862306a36Sopenharmony_ci						goto out_object;
62962306a36Sopenharmony_ci					}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci					expected_pages = remapped_size(view.type, &plane_info[0], &plane_info[1]);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci					if (view.type == I915_GTT_VIEW_ROTATED &&
63462306a36Sopenharmony_ci					    vma->size != expected_pages * PAGE_SIZE) {
63562306a36Sopenharmony_ci						pr_err("VMA is wrong size, expected %lu, found %llu\n",
63662306a36Sopenharmony_ci						       PAGE_SIZE * expected_pages, vma->size);
63762306a36Sopenharmony_ci						err = -EINVAL;
63862306a36Sopenharmony_ci						goto out_object;
63962306a36Sopenharmony_ci					}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci					if (view.type == I915_GTT_VIEW_REMAPPED &&
64262306a36Sopenharmony_ci					    vma->size > expected_pages * PAGE_SIZE) {
64362306a36Sopenharmony_ci						pr_err("VMA is wrong size, expected %lu, found %llu\n",
64462306a36Sopenharmony_ci						       PAGE_SIZE * expected_pages, vma->size);
64562306a36Sopenharmony_ci						err = -EINVAL;
64662306a36Sopenharmony_ci						goto out_object;
64762306a36Sopenharmony_ci					}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci					if (vma->pages->nents > expected_pages) {
65062306a36Sopenharmony_ci						pr_err("sg table is wrong sizeo, expected %u, found %u nents\n",
65162306a36Sopenharmony_ci						       expected_pages, vma->pages->nents);
65262306a36Sopenharmony_ci						err = -EINVAL;
65362306a36Sopenharmony_ci						goto out_object;
65462306a36Sopenharmony_ci					}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci					if (vma->node.size < vma->size) {
65762306a36Sopenharmony_ci						pr_err("VMA binding too small, expected %llu, found %llu\n",
65862306a36Sopenharmony_ci						       vma->size, vma->node.size);
65962306a36Sopenharmony_ci						err = -EINVAL;
66062306a36Sopenharmony_ci						goto out_object;
66162306a36Sopenharmony_ci					}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci					if (vma->pages == obj->mm.pages) {
66462306a36Sopenharmony_ci						pr_err("VMA using unrotated object pages!\n");
66562306a36Sopenharmony_ci						err = -EINVAL;
66662306a36Sopenharmony_ci						goto out_object;
66762306a36Sopenharmony_ci					}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci					sg = vma->pages->sgl;
67062306a36Sopenharmony_ci					for (n = 0; n < ARRAY_SIZE(view.rotated.plane); n++) {
67162306a36Sopenharmony_ci						if (view.type == I915_GTT_VIEW_ROTATED)
67262306a36Sopenharmony_ci							sg = assert_rotated(obj, &view.rotated, n, sg);
67362306a36Sopenharmony_ci						else
67462306a36Sopenharmony_ci							sg = assert_remapped(obj, &view.remapped, n, sg);
67562306a36Sopenharmony_ci						if (IS_ERR(sg)) {
67662306a36Sopenharmony_ci							pr_err("Inconsistent %s VMA pages for plane %d: [(%d, %d, %d, %d, %d), (%d, %d, %d, %d, %d)]\n",
67762306a36Sopenharmony_ci							       view.type == I915_GTT_VIEW_ROTATED ?
67862306a36Sopenharmony_ci							       "rotated" : "remapped", n,
67962306a36Sopenharmony_ci							       plane_info[0].width,
68062306a36Sopenharmony_ci							       plane_info[0].height,
68162306a36Sopenharmony_ci							       plane_info[0].src_stride,
68262306a36Sopenharmony_ci							       plane_info[0].dst_stride,
68362306a36Sopenharmony_ci							       plane_info[0].offset,
68462306a36Sopenharmony_ci							       plane_info[1].width,
68562306a36Sopenharmony_ci							       plane_info[1].height,
68662306a36Sopenharmony_ci							       plane_info[1].src_stride,
68762306a36Sopenharmony_ci							       plane_info[1].dst_stride,
68862306a36Sopenharmony_ci							       plane_info[1].offset);
68962306a36Sopenharmony_ci							err = -EINVAL;
69062306a36Sopenharmony_ci							goto out_object;
69162306a36Sopenharmony_ci						}
69262306a36Sopenharmony_ci					}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci					i915_vma_unpin(vma);
69562306a36Sopenharmony_ci					err = i915_vma_unbind_unlocked(vma);
69662306a36Sopenharmony_ci					if (err) {
69762306a36Sopenharmony_ci						pr_err("Unbinding returned %i\n", err);
69862306a36Sopenharmony_ci						goto out_object;
69962306a36Sopenharmony_ci					}
70062306a36Sopenharmony_ci					cond_resched();
70162306a36Sopenharmony_ci				}
70262306a36Sopenharmony_ci			}
70362306a36Sopenharmony_ci		}
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ciout_object:
70862306a36Sopenharmony_ci	i915_gem_object_put(obj);
70962306a36Sopenharmony_ciout:
71062306a36Sopenharmony_ci	return err;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistatic bool assert_partial(struct drm_i915_gem_object *obj,
71462306a36Sopenharmony_ci			   struct i915_vma *vma,
71562306a36Sopenharmony_ci			   unsigned long offset,
71662306a36Sopenharmony_ci			   unsigned long size)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct sgt_iter sgt;
71962306a36Sopenharmony_ci	dma_addr_t dma;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	for_each_sgt_daddr(dma, sgt, vma->pages) {
72262306a36Sopenharmony_ci		dma_addr_t src;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		if (!size) {
72562306a36Sopenharmony_ci			pr_err("Partial scattergather list too long\n");
72662306a36Sopenharmony_ci			return false;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		src = i915_gem_object_get_dma_address(obj, offset);
73062306a36Sopenharmony_ci		if (src != dma) {
73162306a36Sopenharmony_ci			pr_err("DMA mismatch for partial page offset %lu\n",
73262306a36Sopenharmony_ci			       offset);
73362306a36Sopenharmony_ci			return false;
73462306a36Sopenharmony_ci		}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		offset++;
73762306a36Sopenharmony_ci		size--;
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	return true;
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic bool assert_pin(struct i915_vma *vma,
74462306a36Sopenharmony_ci		       struct i915_gtt_view *view,
74562306a36Sopenharmony_ci		       u64 size,
74662306a36Sopenharmony_ci		       const char *name)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	bool ok = true;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	if (vma->size != size) {
75162306a36Sopenharmony_ci		pr_err("(%s) VMA is wrong size, expected %llu, found %llu\n",
75262306a36Sopenharmony_ci		       name, size, vma->size);
75362306a36Sopenharmony_ci		ok = false;
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (vma->node.size < vma->size) {
75762306a36Sopenharmony_ci		pr_err("(%s) VMA binding too small, expected %llu, found %llu\n",
75862306a36Sopenharmony_ci		       name, vma->size, vma->node.size);
75962306a36Sopenharmony_ci		ok = false;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (view && view->type != I915_GTT_VIEW_NORMAL) {
76362306a36Sopenharmony_ci		if (memcmp(&vma->gtt_view, view, sizeof(*view))) {
76462306a36Sopenharmony_ci			pr_err("(%s) VMA mismatch upon creation!\n",
76562306a36Sopenharmony_ci			       name);
76662306a36Sopenharmony_ci			ok = false;
76762306a36Sopenharmony_ci		}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		if (vma->pages == vma->obj->mm.pages) {
77062306a36Sopenharmony_ci			pr_err("(%s) VMA using original object pages!\n",
77162306a36Sopenharmony_ci			       name);
77262306a36Sopenharmony_ci			ok = false;
77362306a36Sopenharmony_ci		}
77462306a36Sopenharmony_ci	} else {
77562306a36Sopenharmony_ci		if (vma->gtt_view.type != I915_GTT_VIEW_NORMAL) {
77662306a36Sopenharmony_ci			pr_err("Not the normal ggtt view! Found %d\n",
77762306a36Sopenharmony_ci			       vma->gtt_view.type);
77862306a36Sopenharmony_ci			ok = false;
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci		if (vma->pages != vma->obj->mm.pages) {
78262306a36Sopenharmony_ci			pr_err("VMA not using object pages!\n");
78362306a36Sopenharmony_ci			ok = false;
78462306a36Sopenharmony_ci		}
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	return ok;
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cistatic int igt_vma_partial(void *arg)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
79362306a36Sopenharmony_ci	struct i915_address_space *vm = &ggtt->vm;
79462306a36Sopenharmony_ci	const unsigned int npages = 1021; /* prime! */
79562306a36Sopenharmony_ci	struct drm_i915_gem_object *obj;
79662306a36Sopenharmony_ci	const struct phase {
79762306a36Sopenharmony_ci		const char *name;
79862306a36Sopenharmony_ci	} phases[] = {
79962306a36Sopenharmony_ci		{ "create" },
80062306a36Sopenharmony_ci		{ "lookup" },
80162306a36Sopenharmony_ci		{ },
80262306a36Sopenharmony_ci	}, *p;
80362306a36Sopenharmony_ci	unsigned int sz, offset;
80462306a36Sopenharmony_ci	struct i915_vma *vma;
80562306a36Sopenharmony_ci	int err = -ENOMEM;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* Create lots of different VMA for the object and check that
80862306a36Sopenharmony_ci	 * we are returned the same VMA when we later request the same range.
80962306a36Sopenharmony_ci	 */
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	obj = i915_gem_object_create_internal(vm->i915, npages * PAGE_SIZE);
81262306a36Sopenharmony_ci	if (IS_ERR(obj))
81362306a36Sopenharmony_ci		goto out;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	for (p = phases; p->name; p++) { /* exercise both create/lookup */
81662306a36Sopenharmony_ci		unsigned int count, nvma;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		nvma = 0;
81962306a36Sopenharmony_ci		for_each_prime_number_from(sz, 1, npages) {
82062306a36Sopenharmony_ci			for_each_prime_number_from(offset, 0, npages - sz) {
82162306a36Sopenharmony_ci				struct i915_gtt_view view;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci				view.type = I915_GTT_VIEW_PARTIAL;
82462306a36Sopenharmony_ci				view.partial.offset = offset;
82562306a36Sopenharmony_ci				view.partial.size = sz;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci				if (sz == npages)
82862306a36Sopenharmony_ci					view.type = I915_GTT_VIEW_NORMAL;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci				vma = checked_vma_instance(obj, vm, &view);
83162306a36Sopenharmony_ci				if (IS_ERR(vma)) {
83262306a36Sopenharmony_ci					err = PTR_ERR(vma);
83362306a36Sopenharmony_ci					goto out_object;
83462306a36Sopenharmony_ci				}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci				err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
83762306a36Sopenharmony_ci				if (err)
83862306a36Sopenharmony_ci					goto out_object;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci				if (!assert_pin(vma, &view, sz*PAGE_SIZE, p->name)) {
84162306a36Sopenharmony_ci					pr_err("(%s) Inconsistent partial pinning for (offset=%d, size=%d)\n",
84262306a36Sopenharmony_ci					       p->name, offset, sz);
84362306a36Sopenharmony_ci					err = -EINVAL;
84462306a36Sopenharmony_ci					goto out_object;
84562306a36Sopenharmony_ci				}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci				if (!assert_partial(obj, vma, offset, sz)) {
84862306a36Sopenharmony_ci					pr_err("(%s) Inconsistent partial pages for (offset=%d, size=%d)\n",
84962306a36Sopenharmony_ci					       p->name, offset, sz);
85062306a36Sopenharmony_ci					err = -EINVAL;
85162306a36Sopenharmony_ci					goto out_object;
85262306a36Sopenharmony_ci				}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci				i915_vma_unpin(vma);
85562306a36Sopenharmony_ci				nvma++;
85662306a36Sopenharmony_ci				err = i915_vma_unbind_unlocked(vma);
85762306a36Sopenharmony_ci				if (err) {
85862306a36Sopenharmony_ci					pr_err("Unbinding returned %i\n", err);
85962306a36Sopenharmony_ci					goto out_object;
86062306a36Sopenharmony_ci				}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci				cond_resched();
86362306a36Sopenharmony_ci			}
86462306a36Sopenharmony_ci		}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci		count = 0;
86762306a36Sopenharmony_ci		list_for_each_entry(vma, &obj->vma.list, obj_link)
86862306a36Sopenharmony_ci			count++;
86962306a36Sopenharmony_ci		if (count != nvma) {
87062306a36Sopenharmony_ci			pr_err("(%s) All partial vma were not recorded on the obj->vma_list: found %u, expected %u\n",
87162306a36Sopenharmony_ci			       p->name, count, nvma);
87262306a36Sopenharmony_ci			err = -EINVAL;
87362306a36Sopenharmony_ci			goto out_object;
87462306a36Sopenharmony_ci		}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci		/* Check that we did create the whole object mapping */
87762306a36Sopenharmony_ci		vma = checked_vma_instance(obj, vm, NULL);
87862306a36Sopenharmony_ci		if (IS_ERR(vma)) {
87962306a36Sopenharmony_ci			err = PTR_ERR(vma);
88062306a36Sopenharmony_ci			goto out_object;
88162306a36Sopenharmony_ci		}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci		err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
88462306a36Sopenharmony_ci		if (err)
88562306a36Sopenharmony_ci			goto out_object;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci		if (!assert_pin(vma, NULL, obj->base.size, p->name)) {
88862306a36Sopenharmony_ci			pr_err("(%s) inconsistent full pin\n", p->name);
88962306a36Sopenharmony_ci			err = -EINVAL;
89062306a36Sopenharmony_ci			goto out_object;
89162306a36Sopenharmony_ci		}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci		i915_vma_unpin(vma);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci		err = i915_vma_unbind_unlocked(vma);
89662306a36Sopenharmony_ci		if (err) {
89762306a36Sopenharmony_ci			pr_err("Unbinding returned %i\n", err);
89862306a36Sopenharmony_ci			goto out_object;
89962306a36Sopenharmony_ci		}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		count = 0;
90262306a36Sopenharmony_ci		list_for_each_entry(vma, &obj->vma.list, obj_link)
90362306a36Sopenharmony_ci			count++;
90462306a36Sopenharmony_ci		if (count != nvma) {
90562306a36Sopenharmony_ci			pr_err("(%s) allocated an extra full vma!\n", p->name);
90662306a36Sopenharmony_ci			err = -EINVAL;
90762306a36Sopenharmony_ci			goto out_object;
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci	}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ciout_object:
91262306a36Sopenharmony_ci	i915_gem_object_put(obj);
91362306a36Sopenharmony_ciout:
91462306a36Sopenharmony_ci	return err;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ciint i915_vma_mock_selftests(void)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	static const struct i915_subtest tests[] = {
92062306a36Sopenharmony_ci		SUBTEST(igt_vma_create),
92162306a36Sopenharmony_ci		SUBTEST(igt_vma_pin1),
92262306a36Sopenharmony_ci		SUBTEST(igt_vma_rotate_remap),
92362306a36Sopenharmony_ci		SUBTEST(igt_vma_partial),
92462306a36Sopenharmony_ci	};
92562306a36Sopenharmony_ci	struct drm_i915_private *i915;
92662306a36Sopenharmony_ci	struct intel_gt *gt;
92762306a36Sopenharmony_ci	int err;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	i915 = mock_gem_device();
93062306a36Sopenharmony_ci	if (!i915)
93162306a36Sopenharmony_ci		return -ENOMEM;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* allocate the ggtt */
93462306a36Sopenharmony_ci	err = intel_gt_assign_ggtt(to_gt(i915));
93562306a36Sopenharmony_ci	if (err)
93662306a36Sopenharmony_ci		goto out_put;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	gt = to_gt(i915);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	mock_init_ggtt(gt);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	err = i915_subtests(tests, gt->ggtt);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	mock_device_flush(i915);
94562306a36Sopenharmony_ci	i915_gem_drain_freed_objects(i915);
94662306a36Sopenharmony_ci	mock_fini_ggtt(gt->ggtt);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ciout_put:
94962306a36Sopenharmony_ci	mock_destroy_device(i915);
95062306a36Sopenharmony_ci	return err;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic int igt_vma_remapped_gtt(void *arg)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	struct drm_i915_private *i915 = arg;
95662306a36Sopenharmony_ci	const struct intel_remapped_plane_info planes[] = {
95762306a36Sopenharmony_ci		{ .width = 1, .height = 1, .src_stride = 1 },
95862306a36Sopenharmony_ci		{ .width = 2, .height = 2, .src_stride = 2 },
95962306a36Sopenharmony_ci		{ .width = 4, .height = 4, .src_stride = 4 },
96062306a36Sopenharmony_ci		{ .width = 8, .height = 8, .src_stride = 8 },
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci		{ .width = 3, .height = 5, .src_stride = 3 },
96362306a36Sopenharmony_ci		{ .width = 3, .height = 5, .src_stride = 4 },
96462306a36Sopenharmony_ci		{ .width = 3, .height = 5, .src_stride = 5 },
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci		{ .width = 5, .height = 3, .src_stride = 5 },
96762306a36Sopenharmony_ci		{ .width = 5, .height = 3, .src_stride = 7 },
96862306a36Sopenharmony_ci		{ .width = 5, .height = 3, .src_stride = 9 },
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci		{ .width = 4, .height = 6, .src_stride = 6 },
97162306a36Sopenharmony_ci		{ .width = 6, .height = 4, .src_stride = 6 },
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci		{ .width = 2, .height = 2, .src_stride = 2, .dst_stride = 2 },
97462306a36Sopenharmony_ci		{ .width = 3, .height = 3, .src_stride = 3, .dst_stride = 4 },
97562306a36Sopenharmony_ci		{ .width = 5, .height = 6, .src_stride = 7, .dst_stride = 8 },
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		{ }
97862306a36Sopenharmony_ci	}, *p;
97962306a36Sopenharmony_ci	enum i915_gtt_view_type types[] = {
98062306a36Sopenharmony_ci		I915_GTT_VIEW_ROTATED,
98162306a36Sopenharmony_ci		I915_GTT_VIEW_REMAPPED,
98262306a36Sopenharmony_ci		0,
98362306a36Sopenharmony_ci	}, *t;
98462306a36Sopenharmony_ci	struct drm_i915_gem_object *obj;
98562306a36Sopenharmony_ci	intel_wakeref_t wakeref;
98662306a36Sopenharmony_ci	int err = 0;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if (!i915_ggtt_has_aperture(to_gt(i915)->ggtt))
98962306a36Sopenharmony_ci		return 0;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	obj = i915_gem_object_create_internal(i915, 10 * 10 * PAGE_SIZE);
99262306a36Sopenharmony_ci	if (IS_ERR(obj))
99362306a36Sopenharmony_ci		return PTR_ERR(obj);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	for (t = types; *t; t++) {
99862306a36Sopenharmony_ci		for (p = planes; p->width; p++) {
99962306a36Sopenharmony_ci			struct i915_gtt_view view = {
100062306a36Sopenharmony_ci				.type = *t,
100162306a36Sopenharmony_ci				.rotated.plane[0] = *p,
100262306a36Sopenharmony_ci			};
100362306a36Sopenharmony_ci			struct intel_remapped_plane_info *plane_info = view.rotated.plane;
100462306a36Sopenharmony_ci			struct i915_vma *vma;
100562306a36Sopenharmony_ci			u32 __iomem *map;
100662306a36Sopenharmony_ci			unsigned int x, y;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci			i915_gem_object_lock(obj, NULL);
100962306a36Sopenharmony_ci			err = i915_gem_object_set_to_gtt_domain(obj, true);
101062306a36Sopenharmony_ci			i915_gem_object_unlock(obj);
101162306a36Sopenharmony_ci			if (err)
101262306a36Sopenharmony_ci				goto out;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci			if (!plane_info[0].dst_stride)
101562306a36Sopenharmony_ci				plane_info[0].dst_stride = *t == I915_GTT_VIEW_ROTATED ?
101662306a36Sopenharmony_ci								 p->height : p->width;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci			vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
101962306a36Sopenharmony_ci			if (IS_ERR(vma)) {
102062306a36Sopenharmony_ci				err = PTR_ERR(vma);
102162306a36Sopenharmony_ci				goto out;
102262306a36Sopenharmony_ci			}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci			GEM_BUG_ON(vma->gtt_view.type != *t);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci			map = i915_vma_pin_iomap(vma);
102762306a36Sopenharmony_ci			i915_vma_unpin(vma);
102862306a36Sopenharmony_ci			if (IS_ERR(map)) {
102962306a36Sopenharmony_ci				err = PTR_ERR(map);
103062306a36Sopenharmony_ci				goto out;
103162306a36Sopenharmony_ci			}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci			for (y = 0 ; y < plane_info[0].height; y++) {
103462306a36Sopenharmony_ci				for (x = 0 ; x < plane_info[0].width; x++) {
103562306a36Sopenharmony_ci					unsigned int offset;
103662306a36Sopenharmony_ci					u32 val = y << 16 | x;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci					if (*t == I915_GTT_VIEW_ROTATED)
103962306a36Sopenharmony_ci						offset = (x * plane_info[0].dst_stride + y) * PAGE_SIZE;
104062306a36Sopenharmony_ci					else
104162306a36Sopenharmony_ci						offset = (y * plane_info[0].dst_stride + x) * PAGE_SIZE;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci					iowrite32(val, &map[offset / sizeof(*map)]);
104462306a36Sopenharmony_ci				}
104562306a36Sopenharmony_ci			}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci			i915_vma_unpin_iomap(vma);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci			vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
105062306a36Sopenharmony_ci			if (IS_ERR(vma)) {
105162306a36Sopenharmony_ci				err = PTR_ERR(vma);
105262306a36Sopenharmony_ci				goto out;
105362306a36Sopenharmony_ci			}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci			GEM_BUG_ON(vma->gtt_view.type != I915_GTT_VIEW_NORMAL);
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci			map = i915_vma_pin_iomap(vma);
105862306a36Sopenharmony_ci			i915_vma_unpin(vma);
105962306a36Sopenharmony_ci			if (IS_ERR(map)) {
106062306a36Sopenharmony_ci				err = PTR_ERR(map);
106162306a36Sopenharmony_ci				goto out;
106262306a36Sopenharmony_ci			}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci			for (y = 0 ; y < plane_info[0].height; y++) {
106562306a36Sopenharmony_ci				for (x = 0 ; x < plane_info[0].width; x++) {
106662306a36Sopenharmony_ci					unsigned int offset, src_idx;
106762306a36Sopenharmony_ci					u32 exp = y << 16 | x;
106862306a36Sopenharmony_ci					u32 val;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci					if (*t == I915_GTT_VIEW_ROTATED)
107162306a36Sopenharmony_ci						src_idx = rotated_index(&view.rotated, 0, x, y);
107262306a36Sopenharmony_ci					else
107362306a36Sopenharmony_ci						src_idx = remapped_index(&view.remapped, 0, x, y);
107462306a36Sopenharmony_ci					offset = src_idx * PAGE_SIZE;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci					val = ioread32(&map[offset / sizeof(*map)]);
107762306a36Sopenharmony_ci					if (val != exp) {
107862306a36Sopenharmony_ci						pr_err("%s VMA write test failed, expected 0x%x, found 0x%x\n",
107962306a36Sopenharmony_ci						       *t == I915_GTT_VIEW_ROTATED ? "Rotated" : "Remapped",
108062306a36Sopenharmony_ci						       exp, val);
108162306a36Sopenharmony_ci						i915_vma_unpin_iomap(vma);
108262306a36Sopenharmony_ci						err = -EINVAL;
108362306a36Sopenharmony_ci						goto out;
108462306a36Sopenharmony_ci					}
108562306a36Sopenharmony_ci				}
108662306a36Sopenharmony_ci			}
108762306a36Sopenharmony_ci			i915_vma_unpin_iomap(vma);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci			cond_resched();
109062306a36Sopenharmony_ci		}
109162306a36Sopenharmony_ci	}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ciout:
109462306a36Sopenharmony_ci	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
109562306a36Sopenharmony_ci	i915_gem_object_put(obj);
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	return err;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ciint i915_vma_live_selftests(struct drm_i915_private *i915)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	static const struct i915_subtest tests[] = {
110362306a36Sopenharmony_ci		SUBTEST(igt_vma_remapped_gtt),
110462306a36Sopenharmony_ci	};
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	return i915_live_subtests(tests, i915);
110762306a36Sopenharmony_ci}
1108