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