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