18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright © 2016 Intel Corporation
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
138c2ecf20Sopenharmony_ci * Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
218c2ecf20Sopenharmony_ci * IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/prime_numbers.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "gem/i915_gem_context.h"
288c2ecf20Sopenharmony_ci#include "gem/selftests/mock_context.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include "i915_scatterlist.h"
318c2ecf20Sopenharmony_ci#include "i915_selftest.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "mock_gem_device.h"
348c2ecf20Sopenharmony_ci#include "mock_gtt.h"
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic bool assert_vma(struct i915_vma *vma,
378c2ecf20Sopenharmony_ci		       struct drm_i915_gem_object *obj,
388c2ecf20Sopenharmony_ci		       struct i915_gem_context *ctx)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	bool ok = true;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (vma->vm != rcu_access_pointer(ctx->vm)) {
438c2ecf20Sopenharmony_ci		pr_err("VMA created with wrong VM\n");
448c2ecf20Sopenharmony_ci		ok = false;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (vma->size != obj->base.size) {
488c2ecf20Sopenharmony_ci		pr_err("VMA created with wrong size, found %llu, expected %zu\n",
498c2ecf20Sopenharmony_ci		       vma->size, obj->base.size);
508c2ecf20Sopenharmony_ci		ok = false;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) {
548c2ecf20Sopenharmony_ci		pr_err("VMA created with wrong type [%d]\n",
558c2ecf20Sopenharmony_ci		       vma->ggtt_view.type);
568c2ecf20Sopenharmony_ci		ok = false;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	return ok;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic struct i915_vma *
638c2ecf20Sopenharmony_cichecked_vma_instance(struct drm_i915_gem_object *obj,
648c2ecf20Sopenharmony_ci		     struct i915_address_space *vm,
658c2ecf20Sopenharmony_ci		     const struct i915_ggtt_view *view)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	struct i915_vma *vma;
688c2ecf20Sopenharmony_ci	bool ok = true;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	vma = i915_vma_instance(obj, vm, view);
718c2ecf20Sopenharmony_ci	if (IS_ERR(vma))
728c2ecf20Sopenharmony_ci		return vma;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	/* Manual checks, will be reinforced by i915_vma_compare! */
758c2ecf20Sopenharmony_ci	if (vma->vm != vm) {
768c2ecf20Sopenharmony_ci		pr_err("VMA's vm [%p] does not match request [%p]\n",
778c2ecf20Sopenharmony_ci		       vma->vm, vm);
788c2ecf20Sopenharmony_ci		ok = false;
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (i915_is_ggtt(vm) != i915_vma_is_ggtt(vma)) {
828c2ecf20Sopenharmony_ci		pr_err("VMA ggtt status [%d] does not match parent [%d]\n",
838c2ecf20Sopenharmony_ci		       i915_vma_is_ggtt(vma), i915_is_ggtt(vm));
848c2ecf20Sopenharmony_ci		ok = false;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if (i915_vma_compare(vma, vm, view)) {
888c2ecf20Sopenharmony_ci		pr_err("i915_vma_compare failed with create parameters!\n");
898c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (i915_vma_compare(vma, vma->vm,
938c2ecf20Sopenharmony_ci			     i915_vma_is_ggtt(vma) ? &vma->ggtt_view : NULL)) {
948c2ecf20Sopenharmony_ci		pr_err("i915_vma_compare failed with itself\n");
958c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	if (!ok) {
998c2ecf20Sopenharmony_ci		pr_err("i915_vma_compare failed to detect the difference!\n");
1008c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
1018c2ecf20Sopenharmony_ci	}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return vma;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int create_vmas(struct drm_i915_private *i915,
1078c2ecf20Sopenharmony_ci		       struct list_head *objects,
1088c2ecf20Sopenharmony_ci		       struct list_head *contexts)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct drm_i915_gem_object *obj;
1118c2ecf20Sopenharmony_ci	struct i915_gem_context *ctx;
1128c2ecf20Sopenharmony_ci	int pinned;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	list_for_each_entry(obj, objects, st_link) {
1158c2ecf20Sopenharmony_ci		for (pinned = 0; pinned <= 1; pinned++) {
1168c2ecf20Sopenharmony_ci			list_for_each_entry(ctx, contexts, link) {
1178c2ecf20Sopenharmony_ci				struct i915_address_space *vm;
1188c2ecf20Sopenharmony_ci				struct i915_vma *vma;
1198c2ecf20Sopenharmony_ci				int err;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci				vm = i915_gem_context_get_vm_rcu(ctx);
1228c2ecf20Sopenharmony_ci				vma = checked_vma_instance(obj, vm, NULL);
1238c2ecf20Sopenharmony_ci				i915_vm_put(vm);
1248c2ecf20Sopenharmony_ci				if (IS_ERR(vma))
1258c2ecf20Sopenharmony_ci					return PTR_ERR(vma);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci				if (!assert_vma(vma, obj, ctx)) {
1288c2ecf20Sopenharmony_ci					pr_err("VMA lookup/create failed\n");
1298c2ecf20Sopenharmony_ci					return -EINVAL;
1308c2ecf20Sopenharmony_ci				}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci				if (!pinned) {
1338c2ecf20Sopenharmony_ci					err = i915_vma_pin(vma, 0, 0, PIN_USER);
1348c2ecf20Sopenharmony_ci					if (err) {
1358c2ecf20Sopenharmony_ci						pr_err("Failed to pin VMA\n");
1368c2ecf20Sopenharmony_ci						return err;
1378c2ecf20Sopenharmony_ci					}
1388c2ecf20Sopenharmony_ci				} else {
1398c2ecf20Sopenharmony_ci					i915_vma_unpin(vma);
1408c2ecf20Sopenharmony_ci				}
1418c2ecf20Sopenharmony_ci			}
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	return 0;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic int igt_vma_create(void *arg)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
1518c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = ggtt->vm.i915;
1528c2ecf20Sopenharmony_ci	struct drm_i915_gem_object *obj, *on;
1538c2ecf20Sopenharmony_ci	struct i915_gem_context *ctx, *cn;
1548c2ecf20Sopenharmony_ci	unsigned long num_obj, num_ctx;
1558c2ecf20Sopenharmony_ci	unsigned long no, nc;
1568c2ecf20Sopenharmony_ci	IGT_TIMEOUT(end_time);
1578c2ecf20Sopenharmony_ci	LIST_HEAD(contexts);
1588c2ecf20Sopenharmony_ci	LIST_HEAD(objects);
1598c2ecf20Sopenharmony_ci	int err = -ENOMEM;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Exercise creating many vma amonst many objections, checking the
1628c2ecf20Sopenharmony_ci	 * vma creation and lookup routines.
1638c2ecf20Sopenharmony_ci	 */
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	no = 0;
1668c2ecf20Sopenharmony_ci	for_each_prime_number(num_obj, ULONG_MAX - 1) {
1678c2ecf20Sopenharmony_ci		for (; no < num_obj; no++) {
1688c2ecf20Sopenharmony_ci			obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
1698c2ecf20Sopenharmony_ci			if (IS_ERR(obj))
1708c2ecf20Sopenharmony_ci				goto out;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci			list_add(&obj->st_link, &objects);
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		nc = 0;
1768c2ecf20Sopenharmony_ci		for_each_prime_number(num_ctx, 2 * BITS_PER_LONG) {
1778c2ecf20Sopenharmony_ci			for (; nc < num_ctx; nc++) {
1788c2ecf20Sopenharmony_ci				ctx = mock_context(i915, "mock");
1798c2ecf20Sopenharmony_ci				if (!ctx)
1808c2ecf20Sopenharmony_ci					goto out;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci				list_move(&ctx->link, &contexts);
1838c2ecf20Sopenharmony_ci			}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci			err = create_vmas(i915, &objects, &contexts);
1868c2ecf20Sopenharmony_ci			if (err)
1878c2ecf20Sopenharmony_ci				goto out;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci			if (igt_timeout(end_time,
1908c2ecf20Sopenharmony_ci					"%s timed out: after %lu objects in %lu contexts\n",
1918c2ecf20Sopenharmony_ci					__func__, no, nc))
1928c2ecf20Sopenharmony_ci				goto end;
1938c2ecf20Sopenharmony_ci		}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		list_for_each_entry_safe(ctx, cn, &contexts, link) {
1968c2ecf20Sopenharmony_ci			list_del_init(&ctx->link);
1978c2ecf20Sopenharmony_ci			mock_context_close(ctx);
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		cond_resched();
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ciend:
2048c2ecf20Sopenharmony_ci	/* Final pass to lookup all created contexts */
2058c2ecf20Sopenharmony_ci	err = create_vmas(i915, &objects, &contexts);
2068c2ecf20Sopenharmony_ciout:
2078c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ctx, cn, &contexts, link) {
2088c2ecf20Sopenharmony_ci		list_del_init(&ctx->link);
2098c2ecf20Sopenharmony_ci		mock_context_close(ctx);
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	list_for_each_entry_safe(obj, on, &objects, st_link)
2138c2ecf20Sopenharmony_ci		i915_gem_object_put(obj);
2148c2ecf20Sopenharmony_ci	return err;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistruct pin_mode {
2188c2ecf20Sopenharmony_ci	u64 size;
2198c2ecf20Sopenharmony_ci	u64 flags;
2208c2ecf20Sopenharmony_ci	bool (*assert)(const struct i915_vma *,
2218c2ecf20Sopenharmony_ci		       const struct pin_mode *mode,
2228c2ecf20Sopenharmony_ci		       int result);
2238c2ecf20Sopenharmony_ci	const char *string;
2248c2ecf20Sopenharmony_ci};
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic bool assert_pin_valid(const struct i915_vma *vma,
2278c2ecf20Sopenharmony_ci			     const struct pin_mode *mode,
2288c2ecf20Sopenharmony_ci			     int result)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	if (result)
2318c2ecf20Sopenharmony_ci		return false;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if (i915_vma_misplaced(vma, mode->size, 0, mode->flags))
2348c2ecf20Sopenharmony_ci		return false;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	return true;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci__maybe_unused
2408c2ecf20Sopenharmony_cistatic bool assert_pin_enospc(const struct i915_vma *vma,
2418c2ecf20Sopenharmony_ci			      const struct pin_mode *mode,
2428c2ecf20Sopenharmony_ci			      int result)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	return result == -ENOSPC;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci__maybe_unused
2488c2ecf20Sopenharmony_cistatic bool assert_pin_einval(const struct i915_vma *vma,
2498c2ecf20Sopenharmony_ci			      const struct pin_mode *mode,
2508c2ecf20Sopenharmony_ci			      int result)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	return result == -EINVAL;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int igt_vma_pin1(void *arg)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
2588c2ecf20Sopenharmony_ci	const struct pin_mode modes[] = {
2598c2ecf20Sopenharmony_ci#define VALID(sz, fl) { .size = (sz), .flags = (fl), .assert = assert_pin_valid, .string = #sz ", " #fl ", (valid) " }
2608c2ecf20Sopenharmony_ci#define __INVALID(sz, fl, check, eval) { .size = (sz), .flags = (fl), .assert = (check), .string = #sz ", " #fl ", (invalid " #eval ")" }
2618c2ecf20Sopenharmony_ci#define INVALID(sz, fl) __INVALID(sz, fl, assert_pin_einval, EINVAL)
2628c2ecf20Sopenharmony_ci#define NOSPACE(sz, fl) __INVALID(sz, fl, assert_pin_enospc, ENOSPC)
2638c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL),
2648c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_MAPPABLE),
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | 4096),
2678c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | 8192),
2688c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
2698c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
2708c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->vm.total - 4096)),
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (ggtt->mappable_end - 4096)),
2738c2ecf20Sopenharmony_ci		INVALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | ggtt->mappable_end),
2748c2ecf20Sopenharmony_ci		VALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | (ggtt->vm.total - 4096)),
2758c2ecf20Sopenharmony_ci		INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | ggtt->vm.total),
2768c2ecf20Sopenharmony_ci		INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | round_down(U64_MAX, PAGE_SIZE)),
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		VALID(4096, PIN_GLOBAL),
2798c2ecf20Sopenharmony_ci		VALID(8192, PIN_GLOBAL),
2808c2ecf20Sopenharmony_ci		VALID(ggtt->mappable_end - 4096, PIN_GLOBAL | PIN_MAPPABLE),
2818c2ecf20Sopenharmony_ci		VALID(ggtt->mappable_end, PIN_GLOBAL | PIN_MAPPABLE),
2828c2ecf20Sopenharmony_ci		NOSPACE(ggtt->mappable_end + 4096, PIN_GLOBAL | PIN_MAPPABLE),
2838c2ecf20Sopenharmony_ci		VALID(ggtt->vm.total - 4096, PIN_GLOBAL),
2848c2ecf20Sopenharmony_ci		VALID(ggtt->vm.total, PIN_GLOBAL),
2858c2ecf20Sopenharmony_ci		NOSPACE(ggtt->vm.total + 4096, PIN_GLOBAL),
2868c2ecf20Sopenharmony_ci		NOSPACE(round_down(U64_MAX, PAGE_SIZE), PIN_GLOBAL),
2878c2ecf20Sopenharmony_ci		INVALID(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (ggtt->mappable_end - 4096)),
2888c2ecf20Sopenharmony_ci		INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (ggtt->vm.total - 4096)),
2898c2ecf20Sopenharmony_ci		INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (round_down(U64_MAX, PAGE_SIZE) - 4096)),
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		VALID(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci#if !IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)
2948c2ecf20Sopenharmony_ci		/* Misusing BIAS is a programming error (it is not controllable
2958c2ecf20Sopenharmony_ci		 * from userspace) so when debugging is enabled, it explodes.
2968c2ecf20Sopenharmony_ci		 * However, the tests are still quite interesting for checking
2978c2ecf20Sopenharmony_ci		 * variable start, end and size.
2988c2ecf20Sopenharmony_ci		 */
2998c2ecf20Sopenharmony_ci		NOSPACE(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | ggtt->mappable_end),
3008c2ecf20Sopenharmony_ci		NOSPACE(0, PIN_GLOBAL | PIN_OFFSET_BIAS | ggtt->vm.total),
3018c2ecf20Sopenharmony_ci		NOSPACE(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)),
3028c2ecf20Sopenharmony_ci		NOSPACE(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->vm.total - 4096)),
3038c2ecf20Sopenharmony_ci#endif
3048c2ecf20Sopenharmony_ci		{ },
3058c2ecf20Sopenharmony_ci#undef NOSPACE
3068c2ecf20Sopenharmony_ci#undef INVALID
3078c2ecf20Sopenharmony_ci#undef __INVALID
3088c2ecf20Sopenharmony_ci#undef VALID
3098c2ecf20Sopenharmony_ci	}, *m;
3108c2ecf20Sopenharmony_ci	struct drm_i915_gem_object *obj;
3118c2ecf20Sopenharmony_ci	struct i915_vma *vma;
3128c2ecf20Sopenharmony_ci	int err = -EINVAL;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Exercise all the weird and wonderful i915_vma_pin requests,
3158c2ecf20Sopenharmony_ci	 * focusing on error handling of boundary conditions.
3168c2ecf20Sopenharmony_ci	 */
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	GEM_BUG_ON(!drm_mm_clean(&ggtt->vm.mm));
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	obj = i915_gem_object_create_internal(ggtt->vm.i915, PAGE_SIZE);
3218c2ecf20Sopenharmony_ci	if (IS_ERR(obj))
3228c2ecf20Sopenharmony_ci		return PTR_ERR(obj);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	vma = checked_vma_instance(obj, &ggtt->vm, NULL);
3258c2ecf20Sopenharmony_ci	if (IS_ERR(vma))
3268c2ecf20Sopenharmony_ci		goto out;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	for (m = modes; m->assert; m++) {
3298c2ecf20Sopenharmony_ci		err = i915_vma_pin(vma, m->size, 0, m->flags);
3308c2ecf20Sopenharmony_ci		if (!m->assert(vma, m, err)) {
3318c2ecf20Sopenharmony_ci			pr_err("%s to pin single page into GGTT with mode[%d:%s]: size=%llx flags=%llx, err=%d\n",
3328c2ecf20Sopenharmony_ci			       m->assert == assert_pin_valid ? "Failed" : "Unexpectedly succeeded",
3338c2ecf20Sopenharmony_ci			       (int)(m - modes), m->string, m->size, m->flags,
3348c2ecf20Sopenharmony_ci			       err);
3358c2ecf20Sopenharmony_ci			if (!err)
3368c2ecf20Sopenharmony_ci				i915_vma_unpin(vma);
3378c2ecf20Sopenharmony_ci			err = -EINVAL;
3388c2ecf20Sopenharmony_ci			goto out;
3398c2ecf20Sopenharmony_ci		}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		if (!err) {
3428c2ecf20Sopenharmony_ci			i915_vma_unpin(vma);
3438c2ecf20Sopenharmony_ci			err = i915_vma_unbind(vma);
3448c2ecf20Sopenharmony_ci			if (err) {
3458c2ecf20Sopenharmony_ci				pr_err("Failed to unbind single page from GGTT, err=%d\n", err);
3468c2ecf20Sopenharmony_ci				goto out;
3478c2ecf20Sopenharmony_ci			}
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci		cond_resched();
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	err = 0;
3548c2ecf20Sopenharmony_ciout:
3558c2ecf20Sopenharmony_ci	i915_gem_object_put(obj);
3568c2ecf20Sopenharmony_ci	return err;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic unsigned long rotated_index(const struct intel_rotation_info *r,
3608c2ecf20Sopenharmony_ci				   unsigned int n,
3618c2ecf20Sopenharmony_ci				   unsigned int x,
3628c2ecf20Sopenharmony_ci				   unsigned int y)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	return (r->plane[n].stride * (r->plane[n].height - y - 1) +
3658c2ecf20Sopenharmony_ci		r->plane[n].offset + x);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic struct scatterlist *
3698c2ecf20Sopenharmony_ciassert_rotated(struct drm_i915_gem_object *obj,
3708c2ecf20Sopenharmony_ci	       const struct intel_rotation_info *r, unsigned int n,
3718c2ecf20Sopenharmony_ci	       struct scatterlist *sg)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	unsigned int x, y;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	for (x = 0; x < r->plane[n].width; x++) {
3768c2ecf20Sopenharmony_ci		for (y = 0; y < r->plane[n].height; y++) {
3778c2ecf20Sopenharmony_ci			unsigned long src_idx;
3788c2ecf20Sopenharmony_ci			dma_addr_t src;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci			if (!sg) {
3818c2ecf20Sopenharmony_ci				pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n",
3828c2ecf20Sopenharmony_ci				       n, x, y);
3838c2ecf20Sopenharmony_ci				return ERR_PTR(-EINVAL);
3848c2ecf20Sopenharmony_ci			}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci			src_idx = rotated_index(r, n, x, y);
3878c2ecf20Sopenharmony_ci			src = i915_gem_object_get_dma_address(obj, src_idx);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci			if (sg_dma_len(sg) != PAGE_SIZE) {
3908c2ecf20Sopenharmony_ci				pr_err("Invalid sg.length, found %d, expected %lu for rotated page (%d, %d) [src index %lu]\n",
3918c2ecf20Sopenharmony_ci				       sg_dma_len(sg), PAGE_SIZE,
3928c2ecf20Sopenharmony_ci				       x, y, src_idx);
3938c2ecf20Sopenharmony_ci				return ERR_PTR(-EINVAL);
3948c2ecf20Sopenharmony_ci			}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci			if (sg_dma_address(sg) != src) {
3978c2ecf20Sopenharmony_ci				pr_err("Invalid address for rotated page (%d, %d) [src index %lu]\n",
3988c2ecf20Sopenharmony_ci				       x, y, src_idx);
3998c2ecf20Sopenharmony_ci				return ERR_PTR(-EINVAL);
4008c2ecf20Sopenharmony_ci			}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci			sg = sg_next(sg);
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	return sg;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic unsigned long remapped_index(const struct intel_remapped_info *r,
4108c2ecf20Sopenharmony_ci				    unsigned int n,
4118c2ecf20Sopenharmony_ci				    unsigned int x,
4128c2ecf20Sopenharmony_ci				    unsigned int y)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	return (r->plane[n].stride * y +
4158c2ecf20Sopenharmony_ci		r->plane[n].offset + x);
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic struct scatterlist *
4198c2ecf20Sopenharmony_ciassert_remapped(struct drm_i915_gem_object *obj,
4208c2ecf20Sopenharmony_ci		const struct intel_remapped_info *r, unsigned int n,
4218c2ecf20Sopenharmony_ci		struct scatterlist *sg)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	unsigned int x, y;
4248c2ecf20Sopenharmony_ci	unsigned int left = 0;
4258c2ecf20Sopenharmony_ci	unsigned int offset;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	for (y = 0; y < r->plane[n].height; y++) {
4288c2ecf20Sopenharmony_ci		for (x = 0; x < r->plane[n].width; x++) {
4298c2ecf20Sopenharmony_ci			unsigned long src_idx;
4308c2ecf20Sopenharmony_ci			dma_addr_t src;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci			if (!sg) {
4338c2ecf20Sopenharmony_ci				pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n",
4348c2ecf20Sopenharmony_ci				       n, x, y);
4358c2ecf20Sopenharmony_ci				return ERR_PTR(-EINVAL);
4368c2ecf20Sopenharmony_ci			}
4378c2ecf20Sopenharmony_ci			if (!left) {
4388c2ecf20Sopenharmony_ci				offset = 0;
4398c2ecf20Sopenharmony_ci				left = sg_dma_len(sg);
4408c2ecf20Sopenharmony_ci			}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci			src_idx = remapped_index(r, n, x, y);
4438c2ecf20Sopenharmony_ci			src = i915_gem_object_get_dma_address(obj, src_idx);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci			if (left < PAGE_SIZE || left & (PAGE_SIZE-1)) {
4468c2ecf20Sopenharmony_ci				pr_err("Invalid sg.length, found %d, expected %lu for remapped page (%d, %d) [src index %lu]\n",
4478c2ecf20Sopenharmony_ci				       sg_dma_len(sg), PAGE_SIZE,
4488c2ecf20Sopenharmony_ci				       x, y, src_idx);
4498c2ecf20Sopenharmony_ci				return ERR_PTR(-EINVAL);
4508c2ecf20Sopenharmony_ci			}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci			if (sg_dma_address(sg) + offset != src) {
4538c2ecf20Sopenharmony_ci				pr_err("Invalid address for remapped page (%d, %d) [src index %lu]\n",
4548c2ecf20Sopenharmony_ci				       x, y, src_idx);
4558c2ecf20Sopenharmony_ci				return ERR_PTR(-EINVAL);
4568c2ecf20Sopenharmony_ci			}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci			left -= PAGE_SIZE;
4598c2ecf20Sopenharmony_ci			offset += PAGE_SIZE;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci			if (!left)
4638c2ecf20Sopenharmony_ci				sg = sg_next(sg);
4648c2ecf20Sopenharmony_ci		}
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return sg;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic unsigned int rotated_size(const struct intel_remapped_plane_info *a,
4718c2ecf20Sopenharmony_ci				 const struct intel_remapped_plane_info *b)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	return a->width * a->height + b->width * b->height;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic int igt_vma_rotate_remap(void *arg)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
4798c2ecf20Sopenharmony_ci	struct i915_address_space *vm = &ggtt->vm;
4808c2ecf20Sopenharmony_ci	struct drm_i915_gem_object *obj;
4818c2ecf20Sopenharmony_ci	const struct intel_remapped_plane_info planes[] = {
4828c2ecf20Sopenharmony_ci		{ .width = 1, .height = 1, .stride = 1 },
4838c2ecf20Sopenharmony_ci		{ .width = 2, .height = 2, .stride = 2 },
4848c2ecf20Sopenharmony_ci		{ .width = 4, .height = 4, .stride = 4 },
4858c2ecf20Sopenharmony_ci		{ .width = 8, .height = 8, .stride = 8 },
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		{ .width = 3, .height = 5, .stride = 3 },
4888c2ecf20Sopenharmony_ci		{ .width = 3, .height = 5, .stride = 4 },
4898c2ecf20Sopenharmony_ci		{ .width = 3, .height = 5, .stride = 5 },
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci		{ .width = 5, .height = 3, .stride = 5 },
4928c2ecf20Sopenharmony_ci		{ .width = 5, .height = 3, .stride = 7 },
4938c2ecf20Sopenharmony_ci		{ .width = 5, .height = 3, .stride = 9 },
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci		{ .width = 4, .height = 6, .stride = 6 },
4968c2ecf20Sopenharmony_ci		{ .width = 6, .height = 4, .stride = 6 },
4978c2ecf20Sopenharmony_ci		{ }
4988c2ecf20Sopenharmony_ci	}, *a, *b;
4998c2ecf20Sopenharmony_ci	enum i915_ggtt_view_type types[] = {
5008c2ecf20Sopenharmony_ci		I915_GGTT_VIEW_ROTATED,
5018c2ecf20Sopenharmony_ci		I915_GGTT_VIEW_REMAPPED,
5028c2ecf20Sopenharmony_ci		0,
5038c2ecf20Sopenharmony_ci	}, *t;
5048c2ecf20Sopenharmony_ci	const unsigned int max_pages = 64;
5058c2ecf20Sopenharmony_ci	int err = -ENOMEM;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	/* Create VMA for many different combinations of planes and check
5088c2ecf20Sopenharmony_ci	 * that the page layout within the rotated VMA match our expectations.
5098c2ecf20Sopenharmony_ci	 */
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	obj = i915_gem_object_create_internal(vm->i915, max_pages * PAGE_SIZE);
5128c2ecf20Sopenharmony_ci	if (IS_ERR(obj))
5138c2ecf20Sopenharmony_ci		goto out;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	for (t = types; *t; t++) {
5168c2ecf20Sopenharmony_ci	for (a = planes; a->width; a++) {
5178c2ecf20Sopenharmony_ci		for (b = planes + ARRAY_SIZE(planes); b-- != planes; ) {
5188c2ecf20Sopenharmony_ci			struct i915_ggtt_view view;
5198c2ecf20Sopenharmony_ci			unsigned int n, max_offset;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci			max_offset = max(a->stride * a->height,
5228c2ecf20Sopenharmony_ci					 b->stride * b->height);
5238c2ecf20Sopenharmony_ci			GEM_BUG_ON(max_offset > max_pages);
5248c2ecf20Sopenharmony_ci			max_offset = max_pages - max_offset;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci			view.type = *t;
5278c2ecf20Sopenharmony_ci			view.rotated.plane[0] = *a;
5288c2ecf20Sopenharmony_ci			view.rotated.plane[1] = *b;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci			for_each_prime_number_from(view.rotated.plane[0].offset, 0, max_offset) {
5318c2ecf20Sopenharmony_ci				for_each_prime_number_from(view.rotated.plane[1].offset, 0, max_offset) {
5328c2ecf20Sopenharmony_ci					struct scatterlist *sg;
5338c2ecf20Sopenharmony_ci					struct i915_vma *vma;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci					vma = checked_vma_instance(obj, vm, &view);
5368c2ecf20Sopenharmony_ci					if (IS_ERR(vma)) {
5378c2ecf20Sopenharmony_ci						err = PTR_ERR(vma);
5388c2ecf20Sopenharmony_ci						goto out_object;
5398c2ecf20Sopenharmony_ci					}
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci					err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
5428c2ecf20Sopenharmony_ci					if (err) {
5438c2ecf20Sopenharmony_ci						pr_err("Failed to pin VMA, err=%d\n", err);
5448c2ecf20Sopenharmony_ci						goto out_object;
5458c2ecf20Sopenharmony_ci					}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci					if (view.type == I915_GGTT_VIEW_ROTATED &&
5488c2ecf20Sopenharmony_ci					    vma->size != rotated_size(a, b) * PAGE_SIZE) {
5498c2ecf20Sopenharmony_ci						pr_err("VMA is wrong size, expected %lu, found %llu\n",
5508c2ecf20Sopenharmony_ci						       PAGE_SIZE * rotated_size(a, b), vma->size);
5518c2ecf20Sopenharmony_ci						err = -EINVAL;
5528c2ecf20Sopenharmony_ci						goto out_object;
5538c2ecf20Sopenharmony_ci					}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci					if (view.type == I915_GGTT_VIEW_REMAPPED &&
5568c2ecf20Sopenharmony_ci					    vma->size > rotated_size(a, b) * PAGE_SIZE) {
5578c2ecf20Sopenharmony_ci						pr_err("VMA is wrong size, expected %lu, found %llu\n",
5588c2ecf20Sopenharmony_ci						       PAGE_SIZE * rotated_size(a, b), vma->size);
5598c2ecf20Sopenharmony_ci						err = -EINVAL;
5608c2ecf20Sopenharmony_ci						goto out_object;
5618c2ecf20Sopenharmony_ci					}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci					if (vma->pages->nents > rotated_size(a, b)) {
5648c2ecf20Sopenharmony_ci						pr_err("sg table is wrong sizeo, expected %u, found %u nents\n",
5658c2ecf20Sopenharmony_ci						       rotated_size(a, b), vma->pages->nents);
5668c2ecf20Sopenharmony_ci						err = -EINVAL;
5678c2ecf20Sopenharmony_ci						goto out_object;
5688c2ecf20Sopenharmony_ci					}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci					if (vma->node.size < vma->size) {
5718c2ecf20Sopenharmony_ci						pr_err("VMA binding too small, expected %llu, found %llu\n",
5728c2ecf20Sopenharmony_ci						       vma->size, vma->node.size);
5738c2ecf20Sopenharmony_ci						err = -EINVAL;
5748c2ecf20Sopenharmony_ci						goto out_object;
5758c2ecf20Sopenharmony_ci					}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci					if (vma->pages == obj->mm.pages) {
5788c2ecf20Sopenharmony_ci						pr_err("VMA using unrotated object pages!\n");
5798c2ecf20Sopenharmony_ci						err = -EINVAL;
5808c2ecf20Sopenharmony_ci						goto out_object;
5818c2ecf20Sopenharmony_ci					}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci					sg = vma->pages->sgl;
5848c2ecf20Sopenharmony_ci					for (n = 0; n < ARRAY_SIZE(view.rotated.plane); n++) {
5858c2ecf20Sopenharmony_ci						if (view.type == I915_GGTT_VIEW_ROTATED)
5868c2ecf20Sopenharmony_ci							sg = assert_rotated(obj, &view.rotated, n, sg);
5878c2ecf20Sopenharmony_ci						else
5888c2ecf20Sopenharmony_ci							sg = assert_remapped(obj, &view.remapped, n, sg);
5898c2ecf20Sopenharmony_ci						if (IS_ERR(sg)) {
5908c2ecf20Sopenharmony_ci							pr_err("Inconsistent %s VMA pages for plane %d: [(%d, %d, %d, %d), (%d, %d, %d, %d)]\n",
5918c2ecf20Sopenharmony_ci							       view.type == I915_GGTT_VIEW_ROTATED ?
5928c2ecf20Sopenharmony_ci							       "rotated" : "remapped", n,
5938c2ecf20Sopenharmony_ci							       view.rotated.plane[0].width,
5948c2ecf20Sopenharmony_ci							       view.rotated.plane[0].height,
5958c2ecf20Sopenharmony_ci							       view.rotated.plane[0].stride,
5968c2ecf20Sopenharmony_ci							       view.rotated.plane[0].offset,
5978c2ecf20Sopenharmony_ci							       view.rotated.plane[1].width,
5988c2ecf20Sopenharmony_ci							       view.rotated.plane[1].height,
5998c2ecf20Sopenharmony_ci							       view.rotated.plane[1].stride,
6008c2ecf20Sopenharmony_ci							       view.rotated.plane[1].offset);
6018c2ecf20Sopenharmony_ci							err = -EINVAL;
6028c2ecf20Sopenharmony_ci							goto out_object;
6038c2ecf20Sopenharmony_ci						}
6048c2ecf20Sopenharmony_ci					}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci					i915_vma_unpin(vma);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci					cond_resched();
6098c2ecf20Sopenharmony_ci				}
6108c2ecf20Sopenharmony_ci			}
6118c2ecf20Sopenharmony_ci		}
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ciout_object:
6168c2ecf20Sopenharmony_ci	i915_gem_object_put(obj);
6178c2ecf20Sopenharmony_ciout:
6188c2ecf20Sopenharmony_ci	return err;
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic bool assert_partial(struct drm_i915_gem_object *obj,
6228c2ecf20Sopenharmony_ci			   struct i915_vma *vma,
6238c2ecf20Sopenharmony_ci			   unsigned long offset,
6248c2ecf20Sopenharmony_ci			   unsigned long size)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	struct sgt_iter sgt;
6278c2ecf20Sopenharmony_ci	dma_addr_t dma;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	for_each_sgt_daddr(dma, sgt, vma->pages) {
6308c2ecf20Sopenharmony_ci		dma_addr_t src;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci		if (!size) {
6338c2ecf20Sopenharmony_ci			pr_err("Partial scattergather list too long\n");
6348c2ecf20Sopenharmony_ci			return false;
6358c2ecf20Sopenharmony_ci		}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci		src = i915_gem_object_get_dma_address(obj, offset);
6388c2ecf20Sopenharmony_ci		if (src != dma) {
6398c2ecf20Sopenharmony_ci			pr_err("DMA mismatch for partial page offset %lu\n",
6408c2ecf20Sopenharmony_ci			       offset);
6418c2ecf20Sopenharmony_ci			return false;
6428c2ecf20Sopenharmony_ci		}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci		offset++;
6458c2ecf20Sopenharmony_ci		size--;
6468c2ecf20Sopenharmony_ci	}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	return true;
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cistatic bool assert_pin(struct i915_vma *vma,
6528c2ecf20Sopenharmony_ci		       struct i915_ggtt_view *view,
6538c2ecf20Sopenharmony_ci		       u64 size,
6548c2ecf20Sopenharmony_ci		       const char *name)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	bool ok = true;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	if (vma->size != size) {
6598c2ecf20Sopenharmony_ci		pr_err("(%s) VMA is wrong size, expected %llu, found %llu\n",
6608c2ecf20Sopenharmony_ci		       name, size, vma->size);
6618c2ecf20Sopenharmony_ci		ok = false;
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	if (vma->node.size < vma->size) {
6658c2ecf20Sopenharmony_ci		pr_err("(%s) VMA binding too small, expected %llu, found %llu\n",
6668c2ecf20Sopenharmony_ci		       name, vma->size, vma->node.size);
6678c2ecf20Sopenharmony_ci		ok = false;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	if (view && view->type != I915_GGTT_VIEW_NORMAL) {
6718c2ecf20Sopenharmony_ci		if (memcmp(&vma->ggtt_view, view, sizeof(*view))) {
6728c2ecf20Sopenharmony_ci			pr_err("(%s) VMA mismatch upon creation!\n",
6738c2ecf20Sopenharmony_ci			       name);
6748c2ecf20Sopenharmony_ci			ok = false;
6758c2ecf20Sopenharmony_ci		}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		if (vma->pages == vma->obj->mm.pages) {
6788c2ecf20Sopenharmony_ci			pr_err("(%s) VMA using original object pages!\n",
6798c2ecf20Sopenharmony_ci			       name);
6808c2ecf20Sopenharmony_ci			ok = false;
6818c2ecf20Sopenharmony_ci		}
6828c2ecf20Sopenharmony_ci	} else {
6838c2ecf20Sopenharmony_ci		if (vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) {
6848c2ecf20Sopenharmony_ci			pr_err("Not the normal ggtt view! Found %d\n",
6858c2ecf20Sopenharmony_ci			       vma->ggtt_view.type);
6868c2ecf20Sopenharmony_ci			ok = false;
6878c2ecf20Sopenharmony_ci		}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci		if (vma->pages != vma->obj->mm.pages) {
6908c2ecf20Sopenharmony_ci			pr_err("VMA not using object pages!\n");
6918c2ecf20Sopenharmony_ci			ok = false;
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	return ok;
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cistatic int igt_vma_partial(void *arg)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	struct i915_ggtt *ggtt = arg;
7018c2ecf20Sopenharmony_ci	struct i915_address_space *vm = &ggtt->vm;
7028c2ecf20Sopenharmony_ci	const unsigned int npages = 1021; /* prime! */
7038c2ecf20Sopenharmony_ci	struct drm_i915_gem_object *obj;
7048c2ecf20Sopenharmony_ci	const struct phase {
7058c2ecf20Sopenharmony_ci		const char *name;
7068c2ecf20Sopenharmony_ci	} phases[] = {
7078c2ecf20Sopenharmony_ci		{ "create" },
7088c2ecf20Sopenharmony_ci		{ "lookup" },
7098c2ecf20Sopenharmony_ci		{ },
7108c2ecf20Sopenharmony_ci	}, *p;
7118c2ecf20Sopenharmony_ci	unsigned int sz, offset;
7128c2ecf20Sopenharmony_ci	struct i915_vma *vma;
7138c2ecf20Sopenharmony_ci	int err = -ENOMEM;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* Create lots of different VMA for the object and check that
7168c2ecf20Sopenharmony_ci	 * we are returned the same VMA when we later request the same range.
7178c2ecf20Sopenharmony_ci	 */
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	obj = i915_gem_object_create_internal(vm->i915, npages * PAGE_SIZE);
7208c2ecf20Sopenharmony_ci	if (IS_ERR(obj))
7218c2ecf20Sopenharmony_ci		goto out;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	for (p = phases; p->name; p++) { /* exercise both create/lookup */
7248c2ecf20Sopenharmony_ci		unsigned int count, nvma;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		nvma = 0;
7278c2ecf20Sopenharmony_ci		for_each_prime_number_from(sz, 1, npages) {
7288c2ecf20Sopenharmony_ci			for_each_prime_number_from(offset, 0, npages - sz) {
7298c2ecf20Sopenharmony_ci				struct i915_ggtt_view view;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci				view.type = I915_GGTT_VIEW_PARTIAL;
7328c2ecf20Sopenharmony_ci				view.partial.offset = offset;
7338c2ecf20Sopenharmony_ci				view.partial.size = sz;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci				if (sz == npages)
7368c2ecf20Sopenharmony_ci					view.type = I915_GGTT_VIEW_NORMAL;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci				vma = checked_vma_instance(obj, vm, &view);
7398c2ecf20Sopenharmony_ci				if (IS_ERR(vma)) {
7408c2ecf20Sopenharmony_ci					err = PTR_ERR(vma);
7418c2ecf20Sopenharmony_ci					goto out_object;
7428c2ecf20Sopenharmony_ci				}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci				err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
7458c2ecf20Sopenharmony_ci				if (err)
7468c2ecf20Sopenharmony_ci					goto out_object;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci				if (!assert_pin(vma, &view, sz*PAGE_SIZE, p->name)) {
7498c2ecf20Sopenharmony_ci					pr_err("(%s) Inconsistent partial pinning for (offset=%d, size=%d)\n",
7508c2ecf20Sopenharmony_ci					       p->name, offset, sz);
7518c2ecf20Sopenharmony_ci					err = -EINVAL;
7528c2ecf20Sopenharmony_ci					goto out_object;
7538c2ecf20Sopenharmony_ci				}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci				if (!assert_partial(obj, vma, offset, sz)) {
7568c2ecf20Sopenharmony_ci					pr_err("(%s) Inconsistent partial pages for (offset=%d, size=%d)\n",
7578c2ecf20Sopenharmony_ci					       p->name, offset, sz);
7588c2ecf20Sopenharmony_ci					err = -EINVAL;
7598c2ecf20Sopenharmony_ci					goto out_object;
7608c2ecf20Sopenharmony_ci				}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci				i915_vma_unpin(vma);
7638c2ecf20Sopenharmony_ci				nvma++;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci				cond_resched();
7668c2ecf20Sopenharmony_ci			}
7678c2ecf20Sopenharmony_ci		}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci		count = 0;
7708c2ecf20Sopenharmony_ci		list_for_each_entry(vma, &obj->vma.list, obj_link)
7718c2ecf20Sopenharmony_ci			count++;
7728c2ecf20Sopenharmony_ci		if (count != nvma) {
7738c2ecf20Sopenharmony_ci			pr_err("(%s) All partial vma were not recorded on the obj->vma_list: found %u, expected %u\n",
7748c2ecf20Sopenharmony_ci			       p->name, count, nvma);
7758c2ecf20Sopenharmony_ci			err = -EINVAL;
7768c2ecf20Sopenharmony_ci			goto out_object;
7778c2ecf20Sopenharmony_ci		}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		/* Check that we did create the whole object mapping */
7808c2ecf20Sopenharmony_ci		vma = checked_vma_instance(obj, vm, NULL);
7818c2ecf20Sopenharmony_ci		if (IS_ERR(vma)) {
7828c2ecf20Sopenharmony_ci			err = PTR_ERR(vma);
7838c2ecf20Sopenharmony_ci			goto out_object;
7848c2ecf20Sopenharmony_ci		}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci		err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL);
7878c2ecf20Sopenharmony_ci		if (err)
7888c2ecf20Sopenharmony_ci			goto out_object;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci		if (!assert_pin(vma, NULL, obj->base.size, p->name)) {
7918c2ecf20Sopenharmony_ci			pr_err("(%s) inconsistent full pin\n", p->name);
7928c2ecf20Sopenharmony_ci			err = -EINVAL;
7938c2ecf20Sopenharmony_ci			goto out_object;
7948c2ecf20Sopenharmony_ci		}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci		i915_vma_unpin(vma);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci		count = 0;
7998c2ecf20Sopenharmony_ci		list_for_each_entry(vma, &obj->vma.list, obj_link)
8008c2ecf20Sopenharmony_ci			count++;
8018c2ecf20Sopenharmony_ci		if (count != nvma) {
8028c2ecf20Sopenharmony_ci			pr_err("(%s) allocated an extra full vma!\n", p->name);
8038c2ecf20Sopenharmony_ci			err = -EINVAL;
8048c2ecf20Sopenharmony_ci			goto out_object;
8058c2ecf20Sopenharmony_ci		}
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ciout_object:
8098c2ecf20Sopenharmony_ci	i915_gem_object_put(obj);
8108c2ecf20Sopenharmony_ciout:
8118c2ecf20Sopenharmony_ci	return err;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ciint i915_vma_mock_selftests(void)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	static const struct i915_subtest tests[] = {
8178c2ecf20Sopenharmony_ci		SUBTEST(igt_vma_create),
8188c2ecf20Sopenharmony_ci		SUBTEST(igt_vma_pin1),
8198c2ecf20Sopenharmony_ci		SUBTEST(igt_vma_rotate_remap),
8208c2ecf20Sopenharmony_ci		SUBTEST(igt_vma_partial),
8218c2ecf20Sopenharmony_ci	};
8228c2ecf20Sopenharmony_ci	struct drm_i915_private *i915;
8238c2ecf20Sopenharmony_ci	struct i915_ggtt *ggtt;
8248c2ecf20Sopenharmony_ci	int err;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	i915 = mock_gem_device();
8278c2ecf20Sopenharmony_ci	if (!i915)
8288c2ecf20Sopenharmony_ci		return -ENOMEM;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	ggtt = kmalloc(sizeof(*ggtt), GFP_KERNEL);
8318c2ecf20Sopenharmony_ci	if (!ggtt) {
8328c2ecf20Sopenharmony_ci		err = -ENOMEM;
8338c2ecf20Sopenharmony_ci		goto out_put;
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci	mock_init_ggtt(i915, ggtt);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	err = i915_subtests(tests, ggtt);
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	mock_device_flush(i915);
8408c2ecf20Sopenharmony_ci	i915_gem_drain_freed_objects(i915);
8418c2ecf20Sopenharmony_ci	mock_fini_ggtt(ggtt);
8428c2ecf20Sopenharmony_ci	kfree(ggtt);
8438c2ecf20Sopenharmony_ciout_put:
8448c2ecf20Sopenharmony_ci	mock_destroy_device(i915);
8458c2ecf20Sopenharmony_ci	return err;
8468c2ecf20Sopenharmony_ci}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_cistatic int igt_vma_remapped_gtt(void *arg)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	struct drm_i915_private *i915 = arg;
8518c2ecf20Sopenharmony_ci	const struct intel_remapped_plane_info planes[] = {
8528c2ecf20Sopenharmony_ci		{ .width = 1, .height = 1, .stride = 1 },
8538c2ecf20Sopenharmony_ci		{ .width = 2, .height = 2, .stride = 2 },
8548c2ecf20Sopenharmony_ci		{ .width = 4, .height = 4, .stride = 4 },
8558c2ecf20Sopenharmony_ci		{ .width = 8, .height = 8, .stride = 8 },
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci		{ .width = 3, .height = 5, .stride = 3 },
8588c2ecf20Sopenharmony_ci		{ .width = 3, .height = 5, .stride = 4 },
8598c2ecf20Sopenharmony_ci		{ .width = 3, .height = 5, .stride = 5 },
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		{ .width = 5, .height = 3, .stride = 5 },
8628c2ecf20Sopenharmony_ci		{ .width = 5, .height = 3, .stride = 7 },
8638c2ecf20Sopenharmony_ci		{ .width = 5, .height = 3, .stride = 9 },
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci		{ .width = 4, .height = 6, .stride = 6 },
8668c2ecf20Sopenharmony_ci		{ .width = 6, .height = 4, .stride = 6 },
8678c2ecf20Sopenharmony_ci		{ }
8688c2ecf20Sopenharmony_ci	}, *p;
8698c2ecf20Sopenharmony_ci	enum i915_ggtt_view_type types[] = {
8708c2ecf20Sopenharmony_ci		I915_GGTT_VIEW_ROTATED,
8718c2ecf20Sopenharmony_ci		I915_GGTT_VIEW_REMAPPED,
8728c2ecf20Sopenharmony_ci		0,
8738c2ecf20Sopenharmony_ci	}, *t;
8748c2ecf20Sopenharmony_ci	struct drm_i915_gem_object *obj;
8758c2ecf20Sopenharmony_ci	intel_wakeref_t wakeref;
8768c2ecf20Sopenharmony_ci	int err = 0;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	obj = i915_gem_object_create_internal(i915, 10 * 10 * PAGE_SIZE);
8798c2ecf20Sopenharmony_ci	if (IS_ERR(obj))
8808c2ecf20Sopenharmony_ci		return PTR_ERR(obj);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	for (t = types; *t; t++) {
8858c2ecf20Sopenharmony_ci		for (p = planes; p->width; p++) {
8868c2ecf20Sopenharmony_ci			struct i915_ggtt_view view = {
8878c2ecf20Sopenharmony_ci				.type = *t,
8888c2ecf20Sopenharmony_ci				.rotated.plane[0] = *p,
8898c2ecf20Sopenharmony_ci			};
8908c2ecf20Sopenharmony_ci			struct i915_vma *vma;
8918c2ecf20Sopenharmony_ci			u32 __iomem *map;
8928c2ecf20Sopenharmony_ci			unsigned int x, y;
8938c2ecf20Sopenharmony_ci			int err;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci			i915_gem_object_lock(obj, NULL);
8968c2ecf20Sopenharmony_ci			err = i915_gem_object_set_to_gtt_domain(obj, true);
8978c2ecf20Sopenharmony_ci			i915_gem_object_unlock(obj);
8988c2ecf20Sopenharmony_ci			if (err)
8998c2ecf20Sopenharmony_ci				goto out;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci			vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE);
9028c2ecf20Sopenharmony_ci			if (IS_ERR(vma)) {
9038c2ecf20Sopenharmony_ci				err = PTR_ERR(vma);
9048c2ecf20Sopenharmony_ci				goto out;
9058c2ecf20Sopenharmony_ci			}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci			GEM_BUG_ON(vma->ggtt_view.type != *t);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci			map = i915_vma_pin_iomap(vma);
9108c2ecf20Sopenharmony_ci			i915_vma_unpin(vma);
9118c2ecf20Sopenharmony_ci			if (IS_ERR(map)) {
9128c2ecf20Sopenharmony_ci				err = PTR_ERR(map);
9138c2ecf20Sopenharmony_ci				goto out;
9148c2ecf20Sopenharmony_ci			}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci			for (y = 0 ; y < p->height; y++) {
9178c2ecf20Sopenharmony_ci				for (x = 0 ; x < p->width; x++) {
9188c2ecf20Sopenharmony_ci					unsigned int offset;
9198c2ecf20Sopenharmony_ci					u32 val = y << 16 | x;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci					if (*t == I915_GGTT_VIEW_ROTATED)
9228c2ecf20Sopenharmony_ci						offset = (x * p->height + y) * PAGE_SIZE;
9238c2ecf20Sopenharmony_ci					else
9248c2ecf20Sopenharmony_ci						offset = (y * p->width + x) * PAGE_SIZE;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci					iowrite32(val, &map[offset / sizeof(*map)]);
9278c2ecf20Sopenharmony_ci				}
9288c2ecf20Sopenharmony_ci			}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci			i915_vma_unpin_iomap(vma);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci			vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
9338c2ecf20Sopenharmony_ci			if (IS_ERR(vma)) {
9348c2ecf20Sopenharmony_ci				err = PTR_ERR(vma);
9358c2ecf20Sopenharmony_ci				goto out;
9368c2ecf20Sopenharmony_ci			}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci			GEM_BUG_ON(vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci			map = i915_vma_pin_iomap(vma);
9418c2ecf20Sopenharmony_ci			i915_vma_unpin(vma);
9428c2ecf20Sopenharmony_ci			if (IS_ERR(map)) {
9438c2ecf20Sopenharmony_ci				err = PTR_ERR(map);
9448c2ecf20Sopenharmony_ci				goto out;
9458c2ecf20Sopenharmony_ci			}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci			for (y = 0 ; y < p->height; y++) {
9488c2ecf20Sopenharmony_ci				for (x = 0 ; x < p->width; x++) {
9498c2ecf20Sopenharmony_ci					unsigned int offset, src_idx;
9508c2ecf20Sopenharmony_ci					u32 exp = y << 16 | x;
9518c2ecf20Sopenharmony_ci					u32 val;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci					if (*t == I915_GGTT_VIEW_ROTATED)
9548c2ecf20Sopenharmony_ci						src_idx = rotated_index(&view.rotated, 0, x, y);
9558c2ecf20Sopenharmony_ci					else
9568c2ecf20Sopenharmony_ci						src_idx = remapped_index(&view.remapped, 0, x, y);
9578c2ecf20Sopenharmony_ci					offset = src_idx * PAGE_SIZE;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci					val = ioread32(&map[offset / sizeof(*map)]);
9608c2ecf20Sopenharmony_ci					if (val != exp) {
9618c2ecf20Sopenharmony_ci						pr_err("%s VMA write test failed, expected 0x%x, found 0x%x\n",
9628c2ecf20Sopenharmony_ci						       *t == I915_GGTT_VIEW_ROTATED ? "Rotated" : "Remapped",
9638c2ecf20Sopenharmony_ci						       val, exp);
9648c2ecf20Sopenharmony_ci						i915_vma_unpin_iomap(vma);
9658c2ecf20Sopenharmony_ci						goto out;
9668c2ecf20Sopenharmony_ci					}
9678c2ecf20Sopenharmony_ci				}
9688c2ecf20Sopenharmony_ci			}
9698c2ecf20Sopenharmony_ci			i915_vma_unpin_iomap(vma);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci			cond_resched();
9728c2ecf20Sopenharmony_ci		}
9738c2ecf20Sopenharmony_ci	}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ciout:
9768c2ecf20Sopenharmony_ci	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
9778c2ecf20Sopenharmony_ci	i915_gem_object_put(obj);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	return err;
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ciint i915_vma_live_selftests(struct drm_i915_private *i915)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	static const struct i915_subtest tests[] = {
9858c2ecf20Sopenharmony_ci		SUBTEST(igt_vma_remapped_gtt),
9868c2ecf20Sopenharmony_ci	};
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	return i915_subtests(tests, i915);
9898c2ecf20Sopenharmony_ci}
990