1 1.1 riastrad /* $NetBSD: i915_vma.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2016 Intel Corporation 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice (including the next 14 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 15 1.1 riastrad * Software. 16 1.1 riastrad * 17 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 1.1 riastrad * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 1.1 riastrad * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 1.1 riastrad * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 1.1 riastrad * IN THE SOFTWARE. 24 1.1 riastrad * 25 1.1 riastrad */ 26 1.1 riastrad 27 1.1 riastrad #include <sys/cdefs.h> 28 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: i915_vma.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $"); 29 1.1 riastrad 30 1.1 riastrad #include <linux/prime_numbers.h> 31 1.1 riastrad 32 1.1 riastrad #include "gem/i915_gem_context.h" 33 1.1 riastrad #include "gem/selftests/mock_context.h" 34 1.1 riastrad 35 1.1 riastrad #include "i915_scatterlist.h" 36 1.1 riastrad #include "i915_selftest.h" 37 1.1 riastrad 38 1.1 riastrad #include "mock_gem_device.h" 39 1.1 riastrad #include "mock_gtt.h" 40 1.1 riastrad 41 1.1 riastrad static bool assert_vma(struct i915_vma *vma, 42 1.1 riastrad struct drm_i915_gem_object *obj, 43 1.1 riastrad struct i915_gem_context *ctx) 44 1.1 riastrad { 45 1.1 riastrad bool ok = true; 46 1.1 riastrad 47 1.1 riastrad if (vma->vm != rcu_access_pointer(ctx->vm)) { 48 1.1 riastrad pr_err("VMA created with wrong VM\n"); 49 1.1 riastrad ok = false; 50 1.1 riastrad } 51 1.1 riastrad 52 1.1 riastrad if (vma->size != obj->base.size) { 53 1.1 riastrad pr_err("VMA created with wrong size, found %llu, expected %zu\n", 54 1.1 riastrad vma->size, obj->base.size); 55 1.1 riastrad ok = false; 56 1.1 riastrad } 57 1.1 riastrad 58 1.1 riastrad if (vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) { 59 1.1 riastrad pr_err("VMA created with wrong type [%d]\n", 60 1.1 riastrad vma->ggtt_view.type); 61 1.1 riastrad ok = false; 62 1.1 riastrad } 63 1.1 riastrad 64 1.1 riastrad return ok; 65 1.1 riastrad } 66 1.1 riastrad 67 1.1 riastrad static struct i915_vma * 68 1.1 riastrad checked_vma_instance(struct drm_i915_gem_object *obj, 69 1.1 riastrad struct i915_address_space *vm, 70 1.1 riastrad const struct i915_ggtt_view *view) 71 1.1 riastrad { 72 1.1 riastrad struct i915_vma *vma; 73 1.1 riastrad bool ok = true; 74 1.1 riastrad 75 1.1 riastrad vma = i915_vma_instance(obj, vm, view); 76 1.1 riastrad if (IS_ERR(vma)) 77 1.1 riastrad return vma; 78 1.1 riastrad 79 1.1 riastrad /* Manual checks, will be reinforced by i915_vma_compare! */ 80 1.1 riastrad if (vma->vm != vm) { 81 1.1 riastrad pr_err("VMA's vm [%p] does not match request [%p]\n", 82 1.1 riastrad vma->vm, vm); 83 1.1 riastrad ok = false; 84 1.1 riastrad } 85 1.1 riastrad 86 1.1 riastrad if (i915_is_ggtt(vm) != i915_vma_is_ggtt(vma)) { 87 1.1 riastrad pr_err("VMA ggtt status [%d] does not match parent [%d]\n", 88 1.1 riastrad i915_vma_is_ggtt(vma), i915_is_ggtt(vm)); 89 1.1 riastrad ok = false; 90 1.1 riastrad } 91 1.1 riastrad 92 1.1 riastrad if (i915_vma_compare(vma, vm, view)) { 93 1.1 riastrad pr_err("i915_vma_compare failed with create parameters!\n"); 94 1.1 riastrad return ERR_PTR(-EINVAL); 95 1.1 riastrad } 96 1.1 riastrad 97 1.1 riastrad if (i915_vma_compare(vma, vma->vm, 98 1.1 riastrad i915_vma_is_ggtt(vma) ? &vma->ggtt_view : NULL)) { 99 1.1 riastrad pr_err("i915_vma_compare failed with itself\n"); 100 1.1 riastrad return ERR_PTR(-EINVAL); 101 1.1 riastrad } 102 1.1 riastrad 103 1.1 riastrad if (!ok) { 104 1.1 riastrad pr_err("i915_vma_compare failed to detect the difference!\n"); 105 1.1 riastrad return ERR_PTR(-EINVAL); 106 1.1 riastrad } 107 1.1 riastrad 108 1.1 riastrad return vma; 109 1.1 riastrad } 110 1.1 riastrad 111 1.1 riastrad static int create_vmas(struct drm_i915_private *i915, 112 1.1 riastrad struct list_head *objects, 113 1.1 riastrad struct list_head *contexts) 114 1.1 riastrad { 115 1.1 riastrad struct drm_i915_gem_object *obj; 116 1.1 riastrad struct i915_gem_context *ctx; 117 1.1 riastrad int pinned; 118 1.1 riastrad 119 1.1 riastrad list_for_each_entry(obj, objects, st_link) { 120 1.1 riastrad for (pinned = 0; pinned <= 1; pinned++) { 121 1.1 riastrad list_for_each_entry(ctx, contexts, link) { 122 1.1 riastrad struct i915_address_space *vm; 123 1.1 riastrad struct i915_vma *vma; 124 1.1 riastrad int err; 125 1.1 riastrad 126 1.1 riastrad vm = i915_gem_context_get_vm_rcu(ctx); 127 1.1 riastrad vma = checked_vma_instance(obj, vm, NULL); 128 1.1 riastrad i915_vm_put(vm); 129 1.1 riastrad if (IS_ERR(vma)) 130 1.1 riastrad return PTR_ERR(vma); 131 1.1 riastrad 132 1.1 riastrad if (!assert_vma(vma, obj, ctx)) { 133 1.1 riastrad pr_err("VMA lookup/create failed\n"); 134 1.1 riastrad return -EINVAL; 135 1.1 riastrad } 136 1.1 riastrad 137 1.1 riastrad if (!pinned) { 138 1.1 riastrad err = i915_vma_pin(vma, 0, 0, PIN_USER); 139 1.1 riastrad if (err) { 140 1.1 riastrad pr_err("Failed to pin VMA\n"); 141 1.1 riastrad return err; 142 1.1 riastrad } 143 1.1 riastrad } else { 144 1.1 riastrad i915_vma_unpin(vma); 145 1.1 riastrad } 146 1.1 riastrad } 147 1.1 riastrad } 148 1.1 riastrad } 149 1.1 riastrad 150 1.1 riastrad return 0; 151 1.1 riastrad } 152 1.1 riastrad 153 1.1 riastrad static int igt_vma_create(void *arg) 154 1.1 riastrad { 155 1.1 riastrad struct i915_ggtt *ggtt = arg; 156 1.1 riastrad struct drm_i915_private *i915 = ggtt->vm.i915; 157 1.1 riastrad struct drm_i915_gem_object *obj, *on; 158 1.1 riastrad struct i915_gem_context *ctx, *cn; 159 1.1 riastrad unsigned long num_obj, num_ctx; 160 1.1 riastrad unsigned long no, nc; 161 1.1 riastrad IGT_TIMEOUT(end_time); 162 1.1 riastrad LIST_HEAD(contexts); 163 1.1 riastrad LIST_HEAD(objects); 164 1.1 riastrad int err = -ENOMEM; 165 1.1 riastrad 166 1.1 riastrad /* Exercise creating many vma amonst many objections, checking the 167 1.1 riastrad * vma creation and lookup routines. 168 1.1 riastrad */ 169 1.1 riastrad 170 1.1 riastrad no = 0; 171 1.1 riastrad for_each_prime_number(num_obj, ULONG_MAX - 1) { 172 1.1 riastrad for (; no < num_obj; no++) { 173 1.1 riastrad obj = i915_gem_object_create_internal(i915, PAGE_SIZE); 174 1.1 riastrad if (IS_ERR(obj)) 175 1.1 riastrad goto out; 176 1.1 riastrad 177 1.1 riastrad list_add(&obj->st_link, &objects); 178 1.1 riastrad } 179 1.1 riastrad 180 1.1 riastrad nc = 0; 181 1.1 riastrad for_each_prime_number(num_ctx, 2 * NUM_CONTEXT_TAG) { 182 1.1 riastrad for (; nc < num_ctx; nc++) { 183 1.1 riastrad ctx = mock_context(i915, "mock"); 184 1.1 riastrad if (!ctx) 185 1.1 riastrad goto out; 186 1.1 riastrad 187 1.1 riastrad list_move(&ctx->link, &contexts); 188 1.1 riastrad } 189 1.1 riastrad 190 1.1 riastrad err = create_vmas(i915, &objects, &contexts); 191 1.1 riastrad if (err) 192 1.1 riastrad goto out; 193 1.1 riastrad 194 1.1 riastrad if (igt_timeout(end_time, 195 1.1 riastrad "%s timed out: after %lu objects in %lu contexts\n", 196 1.1 riastrad __func__, no, nc)) 197 1.1 riastrad goto end; 198 1.1 riastrad } 199 1.1 riastrad 200 1.1 riastrad list_for_each_entry_safe(ctx, cn, &contexts, link) { 201 1.1 riastrad list_del_init(&ctx->link); 202 1.1 riastrad mock_context_close(ctx); 203 1.1 riastrad } 204 1.1 riastrad 205 1.1 riastrad cond_resched(); 206 1.1 riastrad } 207 1.1 riastrad 208 1.1 riastrad end: 209 1.1 riastrad /* Final pass to lookup all created contexts */ 210 1.1 riastrad err = create_vmas(i915, &objects, &contexts); 211 1.1 riastrad out: 212 1.1 riastrad list_for_each_entry_safe(ctx, cn, &contexts, link) { 213 1.1 riastrad list_del_init(&ctx->link); 214 1.1 riastrad mock_context_close(ctx); 215 1.1 riastrad } 216 1.1 riastrad 217 1.1 riastrad list_for_each_entry_safe(obj, on, &objects, st_link) 218 1.1 riastrad i915_gem_object_put(obj); 219 1.1 riastrad return err; 220 1.1 riastrad } 221 1.1 riastrad 222 1.1 riastrad struct pin_mode { 223 1.1 riastrad u64 size; 224 1.1 riastrad u64 flags; 225 1.1 riastrad bool (*assert)(const struct i915_vma *, 226 1.1 riastrad const struct pin_mode *mode, 227 1.1 riastrad int result); 228 1.1 riastrad const char *string; 229 1.1 riastrad }; 230 1.1 riastrad 231 1.1 riastrad static bool assert_pin_valid(const struct i915_vma *vma, 232 1.1 riastrad const struct pin_mode *mode, 233 1.1 riastrad int result) 234 1.1 riastrad { 235 1.1 riastrad if (result) 236 1.1 riastrad return false; 237 1.1 riastrad 238 1.1 riastrad if (i915_vma_misplaced(vma, mode->size, 0, mode->flags)) 239 1.1 riastrad return false; 240 1.1 riastrad 241 1.1 riastrad return true; 242 1.1 riastrad } 243 1.1 riastrad 244 1.1 riastrad __maybe_unused 245 1.1 riastrad static bool assert_pin_enospc(const struct i915_vma *vma, 246 1.1 riastrad const struct pin_mode *mode, 247 1.1 riastrad int result) 248 1.1 riastrad { 249 1.1 riastrad return result == -ENOSPC; 250 1.1 riastrad } 251 1.1 riastrad 252 1.1 riastrad __maybe_unused 253 1.1 riastrad static bool assert_pin_einval(const struct i915_vma *vma, 254 1.1 riastrad const struct pin_mode *mode, 255 1.1 riastrad int result) 256 1.1 riastrad { 257 1.1 riastrad return result == -EINVAL; 258 1.1 riastrad } 259 1.1 riastrad 260 1.1 riastrad static int igt_vma_pin1(void *arg) 261 1.1 riastrad { 262 1.1 riastrad struct i915_ggtt *ggtt = arg; 263 1.1 riastrad const struct pin_mode modes[] = { 264 1.1 riastrad #define VALID(sz, fl) { .size = (sz), .flags = (fl), .assert = assert_pin_valid, .string = #sz ", " #fl ", (valid) " } 265 1.1 riastrad #define __INVALID(sz, fl, check, eval) { .size = (sz), .flags = (fl), .assert = (check), .string = #sz ", " #fl ", (invalid " #eval ")" } 266 1.1 riastrad #define INVALID(sz, fl) __INVALID(sz, fl, assert_pin_einval, EINVAL) 267 1.1 riastrad #define NOSPACE(sz, fl) __INVALID(sz, fl, assert_pin_enospc, ENOSPC) 268 1.1 riastrad VALID(0, PIN_GLOBAL), 269 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_MAPPABLE), 270 1.1 riastrad 271 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | 4096), 272 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | 8192), 273 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)), 274 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)), 275 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->vm.total - 4096)), 276 1.1 riastrad 277 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (ggtt->mappable_end - 4096)), 278 1.1 riastrad INVALID(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | ggtt->mappable_end), 279 1.1 riastrad VALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | (ggtt->vm.total - 4096)), 280 1.1 riastrad INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | ggtt->vm.total), 281 1.1 riastrad INVALID(0, PIN_GLOBAL | PIN_OFFSET_FIXED | round_down(U64_MAX, PAGE_SIZE)), 282 1.1 riastrad 283 1.1 riastrad VALID(4096, PIN_GLOBAL), 284 1.1 riastrad VALID(8192, PIN_GLOBAL), 285 1.1 riastrad VALID(ggtt->mappable_end - 4096, PIN_GLOBAL | PIN_MAPPABLE), 286 1.1 riastrad VALID(ggtt->mappable_end, PIN_GLOBAL | PIN_MAPPABLE), 287 1.1 riastrad NOSPACE(ggtt->mappable_end + 4096, PIN_GLOBAL | PIN_MAPPABLE), 288 1.1 riastrad VALID(ggtt->vm.total - 4096, PIN_GLOBAL), 289 1.1 riastrad VALID(ggtt->vm.total, PIN_GLOBAL), 290 1.1 riastrad NOSPACE(ggtt->vm.total + 4096, PIN_GLOBAL), 291 1.1 riastrad NOSPACE(round_down(U64_MAX, PAGE_SIZE), PIN_GLOBAL), 292 1.1 riastrad INVALID(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_FIXED | (ggtt->mappable_end - 4096)), 293 1.1 riastrad INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (ggtt->vm.total - 4096)), 294 1.1 riastrad INVALID(8192, PIN_GLOBAL | PIN_OFFSET_FIXED | (round_down(U64_MAX, PAGE_SIZE) - 4096)), 295 1.1 riastrad 296 1.1 riastrad VALID(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)), 297 1.1 riastrad 298 1.1 riastrad #if !IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) 299 1.1 riastrad /* Misusing BIAS is a programming error (it is not controllable 300 1.1 riastrad * from userspace) so when debugging is enabled, it explodes. 301 1.1 riastrad * However, the tests are still quite interesting for checking 302 1.1 riastrad * variable start, end and size. 303 1.1 riastrad */ 304 1.1 riastrad NOSPACE(0, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | ggtt->mappable_end), 305 1.1 riastrad NOSPACE(0, PIN_GLOBAL | PIN_OFFSET_BIAS | ggtt->vm.total), 306 1.1 riastrad NOSPACE(8192, PIN_GLOBAL | PIN_MAPPABLE | PIN_OFFSET_BIAS | (ggtt->mappable_end - 4096)), 307 1.1 riastrad NOSPACE(8192, PIN_GLOBAL | PIN_OFFSET_BIAS | (ggtt->vm.total - 4096)), 308 1.1 riastrad #endif 309 1.1 riastrad { }, 310 1.1 riastrad #undef NOSPACE 311 1.1 riastrad #undef INVALID 312 1.1 riastrad #undef __INVALID 313 1.1 riastrad #undef VALID 314 1.1 riastrad }, *m; 315 1.1 riastrad struct drm_i915_gem_object *obj; 316 1.1 riastrad struct i915_vma *vma; 317 1.1 riastrad int err = -EINVAL; 318 1.1 riastrad 319 1.1 riastrad /* Exercise all the weird and wonderful i915_vma_pin requests, 320 1.1 riastrad * focusing on error handling of boundary conditions. 321 1.1 riastrad */ 322 1.1 riastrad 323 1.1 riastrad GEM_BUG_ON(!drm_mm_clean(&ggtt->vm.mm)); 324 1.1 riastrad 325 1.1 riastrad obj = i915_gem_object_create_internal(ggtt->vm.i915, PAGE_SIZE); 326 1.1 riastrad if (IS_ERR(obj)) 327 1.1 riastrad return PTR_ERR(obj); 328 1.1 riastrad 329 1.1 riastrad vma = checked_vma_instance(obj, &ggtt->vm, NULL); 330 1.1 riastrad if (IS_ERR(vma)) 331 1.1 riastrad goto out; 332 1.1 riastrad 333 1.1 riastrad for (m = modes; m->assert; m++) { 334 1.1 riastrad err = i915_vma_pin(vma, m->size, 0, m->flags); 335 1.1 riastrad if (!m->assert(vma, m, err)) { 336 1.1 riastrad pr_err("%s to pin single page into GGTT with mode[%d:%s]: size=%llx flags=%llx, err=%d\n", 337 1.1 riastrad m->assert == assert_pin_valid ? "Failed" : "Unexpectedly succeeded", 338 1.1 riastrad (int)(m - modes), m->string, m->size, m->flags, 339 1.1 riastrad err); 340 1.1 riastrad if (!err) 341 1.1 riastrad i915_vma_unpin(vma); 342 1.1 riastrad err = -EINVAL; 343 1.1 riastrad goto out; 344 1.1 riastrad } 345 1.1 riastrad 346 1.1 riastrad if (!err) { 347 1.1 riastrad i915_vma_unpin(vma); 348 1.1 riastrad err = i915_vma_unbind(vma); 349 1.1 riastrad if (err) { 350 1.1 riastrad pr_err("Failed to unbind single page from GGTT, err=%d\n", err); 351 1.1 riastrad goto out; 352 1.1 riastrad } 353 1.1 riastrad } 354 1.1 riastrad 355 1.1 riastrad cond_resched(); 356 1.1 riastrad } 357 1.1 riastrad 358 1.1 riastrad err = 0; 359 1.1 riastrad out: 360 1.1 riastrad i915_gem_object_put(obj); 361 1.1 riastrad return err; 362 1.1 riastrad } 363 1.1 riastrad 364 1.1 riastrad static unsigned long rotated_index(const struct intel_rotation_info *r, 365 1.1 riastrad unsigned int n, 366 1.1 riastrad unsigned int x, 367 1.1 riastrad unsigned int y) 368 1.1 riastrad { 369 1.1 riastrad return (r->plane[n].stride * (r->plane[n].height - y - 1) + 370 1.1 riastrad r->plane[n].offset + x); 371 1.1 riastrad } 372 1.1 riastrad 373 1.1 riastrad static struct scatterlist * 374 1.1 riastrad assert_rotated(struct drm_i915_gem_object *obj, 375 1.1 riastrad const struct intel_rotation_info *r, unsigned int n, 376 1.1 riastrad struct scatterlist *sg) 377 1.1 riastrad { 378 1.1 riastrad unsigned int x, y; 379 1.1 riastrad 380 1.1 riastrad for (x = 0; x < r->plane[n].width; x++) { 381 1.1 riastrad for (y = 0; y < r->plane[n].height; y++) { 382 1.1 riastrad unsigned long src_idx; 383 1.1 riastrad dma_addr_t src; 384 1.1 riastrad 385 1.1 riastrad if (!sg) { 386 1.1 riastrad pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n", 387 1.1 riastrad n, x, y); 388 1.1 riastrad return ERR_PTR(-EINVAL); 389 1.1 riastrad } 390 1.1 riastrad 391 1.1 riastrad src_idx = rotated_index(r, n, x, y); 392 1.1 riastrad src = i915_gem_object_get_dma_address(obj, src_idx); 393 1.1 riastrad 394 1.1 riastrad if (sg_dma_len(sg) != PAGE_SIZE) { 395 1.1 riastrad pr_err("Invalid sg.length, found %d, expected %lu for rotated page (%d, %d) [src index %lu]\n", 396 1.1 riastrad sg_dma_len(sg), PAGE_SIZE, 397 1.1 riastrad x, y, src_idx); 398 1.1 riastrad return ERR_PTR(-EINVAL); 399 1.1 riastrad } 400 1.1 riastrad 401 1.1 riastrad if (sg_dma_address(sg) != src) { 402 1.1 riastrad pr_err("Invalid address for rotated page (%d, %d) [src index %lu]\n", 403 1.1 riastrad x, y, src_idx); 404 1.1 riastrad return ERR_PTR(-EINVAL); 405 1.1 riastrad } 406 1.1 riastrad 407 1.1 riastrad sg = sg_next(sg); 408 1.1 riastrad } 409 1.1 riastrad } 410 1.1 riastrad 411 1.1 riastrad return sg; 412 1.1 riastrad } 413 1.1 riastrad 414 1.1 riastrad static unsigned long remapped_index(const struct intel_remapped_info *r, 415 1.1 riastrad unsigned int n, 416 1.1 riastrad unsigned int x, 417 1.1 riastrad unsigned int y) 418 1.1 riastrad { 419 1.1 riastrad return (r->plane[n].stride * y + 420 1.1 riastrad r->plane[n].offset + x); 421 1.1 riastrad } 422 1.1 riastrad 423 1.1 riastrad static struct scatterlist * 424 1.1 riastrad assert_remapped(struct drm_i915_gem_object *obj, 425 1.1 riastrad const struct intel_remapped_info *r, unsigned int n, 426 1.1 riastrad struct scatterlist *sg) 427 1.1 riastrad { 428 1.1 riastrad unsigned int x, y; 429 1.1 riastrad unsigned int left = 0; 430 1.1 riastrad unsigned int offset; 431 1.1 riastrad 432 1.1 riastrad for (y = 0; y < r->plane[n].height; y++) { 433 1.1 riastrad for (x = 0; x < r->plane[n].width; x++) { 434 1.1 riastrad unsigned long src_idx; 435 1.1 riastrad dma_addr_t src; 436 1.1 riastrad 437 1.1 riastrad if (!sg) { 438 1.1 riastrad pr_err("Invalid sg table: too short at plane %d, (%d, %d)!\n", 439 1.1 riastrad n, x, y); 440 1.1 riastrad return ERR_PTR(-EINVAL); 441 1.1 riastrad } 442 1.1 riastrad if (!left) { 443 1.1 riastrad offset = 0; 444 1.1 riastrad left = sg_dma_len(sg); 445 1.1 riastrad } 446 1.1 riastrad 447 1.1 riastrad src_idx = remapped_index(r, n, x, y); 448 1.1 riastrad src = i915_gem_object_get_dma_address(obj, src_idx); 449 1.1 riastrad 450 1.1 riastrad if (left < PAGE_SIZE || left & (PAGE_SIZE-1)) { 451 1.1 riastrad pr_err("Invalid sg.length, found %d, expected %lu for remapped page (%d, %d) [src index %lu]\n", 452 1.1 riastrad sg_dma_len(sg), PAGE_SIZE, 453 1.1 riastrad x, y, src_idx); 454 1.1 riastrad return ERR_PTR(-EINVAL); 455 1.1 riastrad } 456 1.1 riastrad 457 1.1 riastrad if (sg_dma_address(sg) + offset != src) { 458 1.1 riastrad pr_err("Invalid address for remapped page (%d, %d) [src index %lu]\n", 459 1.1 riastrad x, y, src_idx); 460 1.1 riastrad return ERR_PTR(-EINVAL); 461 1.1 riastrad } 462 1.1 riastrad 463 1.1 riastrad left -= PAGE_SIZE; 464 1.1 riastrad offset += PAGE_SIZE; 465 1.1 riastrad 466 1.1 riastrad 467 1.1 riastrad if (!left) 468 1.1 riastrad sg = sg_next(sg); 469 1.1 riastrad } 470 1.1 riastrad } 471 1.1 riastrad 472 1.1 riastrad return sg; 473 1.1 riastrad } 474 1.1 riastrad 475 1.1 riastrad static unsigned int rotated_size(const struct intel_remapped_plane_info *a, 476 1.1 riastrad const struct intel_remapped_plane_info *b) 477 1.1 riastrad { 478 1.1 riastrad return a->width * a->height + b->width * b->height; 479 1.1 riastrad } 480 1.1 riastrad 481 1.1 riastrad static int igt_vma_rotate_remap(void *arg) 482 1.1 riastrad { 483 1.1 riastrad struct i915_ggtt *ggtt = arg; 484 1.1 riastrad struct i915_address_space *vm = &ggtt->vm; 485 1.1 riastrad struct drm_i915_gem_object *obj; 486 1.1 riastrad const struct intel_remapped_plane_info planes[] = { 487 1.1 riastrad { .width = 1, .height = 1, .stride = 1 }, 488 1.1 riastrad { .width = 2, .height = 2, .stride = 2 }, 489 1.1 riastrad { .width = 4, .height = 4, .stride = 4 }, 490 1.1 riastrad { .width = 8, .height = 8, .stride = 8 }, 491 1.1 riastrad 492 1.1 riastrad { .width = 3, .height = 5, .stride = 3 }, 493 1.1 riastrad { .width = 3, .height = 5, .stride = 4 }, 494 1.1 riastrad { .width = 3, .height = 5, .stride = 5 }, 495 1.1 riastrad 496 1.1 riastrad { .width = 5, .height = 3, .stride = 5 }, 497 1.1 riastrad { .width = 5, .height = 3, .stride = 7 }, 498 1.1 riastrad { .width = 5, .height = 3, .stride = 9 }, 499 1.1 riastrad 500 1.1 riastrad { .width = 4, .height = 6, .stride = 6 }, 501 1.1 riastrad { .width = 6, .height = 4, .stride = 6 }, 502 1.1 riastrad { } 503 1.1 riastrad }, *a, *b; 504 1.1 riastrad enum i915_ggtt_view_type types[] = { 505 1.1 riastrad I915_GGTT_VIEW_ROTATED, 506 1.1 riastrad I915_GGTT_VIEW_REMAPPED, 507 1.1 riastrad 0, 508 1.1 riastrad }, *t; 509 1.1 riastrad const unsigned int max_pages = 64; 510 1.1 riastrad int err = -ENOMEM; 511 1.1 riastrad 512 1.1 riastrad /* Create VMA for many different combinations of planes and check 513 1.1 riastrad * that the page layout within the rotated VMA match our expectations. 514 1.1 riastrad */ 515 1.1 riastrad 516 1.1 riastrad obj = i915_gem_object_create_internal(vm->i915, max_pages * PAGE_SIZE); 517 1.1 riastrad if (IS_ERR(obj)) 518 1.1 riastrad goto out; 519 1.1 riastrad 520 1.1 riastrad for (t = types; *t; t++) { 521 1.1 riastrad for (a = planes; a->width; a++) { 522 1.1 riastrad for (b = planes + ARRAY_SIZE(planes); b-- != planes; ) { 523 1.1 riastrad struct i915_ggtt_view view; 524 1.1 riastrad unsigned int n, max_offset; 525 1.1 riastrad 526 1.1 riastrad max_offset = max(a->stride * a->height, 527 1.1 riastrad b->stride * b->height); 528 1.1 riastrad GEM_BUG_ON(max_offset > max_pages); 529 1.1 riastrad max_offset = max_pages - max_offset; 530 1.1 riastrad 531 1.1 riastrad view.type = *t; 532 1.1 riastrad view.rotated.plane[0] = *a; 533 1.1 riastrad view.rotated.plane[1] = *b; 534 1.1 riastrad 535 1.1 riastrad for_each_prime_number_from(view.rotated.plane[0].offset, 0, max_offset) { 536 1.1 riastrad for_each_prime_number_from(view.rotated.plane[1].offset, 0, max_offset) { 537 1.1 riastrad struct scatterlist *sg; 538 1.1 riastrad struct i915_vma *vma; 539 1.1 riastrad 540 1.1 riastrad vma = checked_vma_instance(obj, vm, &view); 541 1.1 riastrad if (IS_ERR(vma)) { 542 1.1 riastrad err = PTR_ERR(vma); 543 1.1 riastrad goto out_object; 544 1.1 riastrad } 545 1.1 riastrad 546 1.1 riastrad err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL); 547 1.1 riastrad if (err) { 548 1.1 riastrad pr_err("Failed to pin VMA, err=%d\n", err); 549 1.1 riastrad goto out_object; 550 1.1 riastrad } 551 1.1 riastrad 552 1.1 riastrad if (view.type == I915_GGTT_VIEW_ROTATED && 553 1.1 riastrad vma->size != rotated_size(a, b) * PAGE_SIZE) { 554 1.1 riastrad pr_err("VMA is wrong size, expected %lu, found %llu\n", 555 1.1 riastrad PAGE_SIZE * rotated_size(a, b), vma->size); 556 1.1 riastrad err = -EINVAL; 557 1.1 riastrad goto out_object; 558 1.1 riastrad } 559 1.1 riastrad 560 1.1 riastrad if (view.type == I915_GGTT_VIEW_REMAPPED && 561 1.1 riastrad vma->size > rotated_size(a, b) * PAGE_SIZE) { 562 1.1 riastrad pr_err("VMA is wrong size, expected %lu, found %llu\n", 563 1.1 riastrad PAGE_SIZE * rotated_size(a, b), vma->size); 564 1.1 riastrad err = -EINVAL; 565 1.1 riastrad goto out_object; 566 1.1 riastrad } 567 1.1 riastrad 568 1.1 riastrad if (vma->pages->nents > rotated_size(a, b)) { 569 1.1 riastrad pr_err("sg table is wrong sizeo, expected %u, found %u nents\n", 570 1.1 riastrad rotated_size(a, b), vma->pages->nents); 571 1.1 riastrad err = -EINVAL; 572 1.1 riastrad goto out_object; 573 1.1 riastrad } 574 1.1 riastrad 575 1.1 riastrad if (vma->node.size < vma->size) { 576 1.1 riastrad pr_err("VMA binding too small, expected %llu, found %llu\n", 577 1.1 riastrad vma->size, vma->node.size); 578 1.1 riastrad err = -EINVAL; 579 1.1 riastrad goto out_object; 580 1.1 riastrad } 581 1.1 riastrad 582 1.1 riastrad if (vma->pages == obj->mm.pages) { 583 1.1 riastrad pr_err("VMA using unrotated object pages!\n"); 584 1.1 riastrad err = -EINVAL; 585 1.1 riastrad goto out_object; 586 1.1 riastrad } 587 1.1 riastrad 588 1.1 riastrad sg = vma->pages->sgl; 589 1.1 riastrad for (n = 0; n < ARRAY_SIZE(view.rotated.plane); n++) { 590 1.1 riastrad if (view.type == I915_GGTT_VIEW_ROTATED) 591 1.1 riastrad sg = assert_rotated(obj, &view.rotated, n, sg); 592 1.1 riastrad else 593 1.1 riastrad sg = assert_remapped(obj, &view.remapped, n, sg); 594 1.1 riastrad if (IS_ERR(sg)) { 595 1.1 riastrad pr_err("Inconsistent %s VMA pages for plane %d: [(%d, %d, %d, %d), (%d, %d, %d, %d)]\n", 596 1.1 riastrad view.type == I915_GGTT_VIEW_ROTATED ? 597 1.1 riastrad "rotated" : "remapped", n, 598 1.1 riastrad view.rotated.plane[0].width, 599 1.1 riastrad view.rotated.plane[0].height, 600 1.1 riastrad view.rotated.plane[0].stride, 601 1.1 riastrad view.rotated.plane[0].offset, 602 1.1 riastrad view.rotated.plane[1].width, 603 1.1 riastrad view.rotated.plane[1].height, 604 1.1 riastrad view.rotated.plane[1].stride, 605 1.1 riastrad view.rotated.plane[1].offset); 606 1.1 riastrad err = -EINVAL; 607 1.1 riastrad goto out_object; 608 1.1 riastrad } 609 1.1 riastrad } 610 1.1 riastrad 611 1.1 riastrad i915_vma_unpin(vma); 612 1.1 riastrad 613 1.1 riastrad cond_resched(); 614 1.1 riastrad } 615 1.1 riastrad } 616 1.1 riastrad } 617 1.1 riastrad } 618 1.1 riastrad } 619 1.1 riastrad 620 1.1 riastrad out_object: 621 1.1 riastrad i915_gem_object_put(obj); 622 1.1 riastrad out: 623 1.1 riastrad return err; 624 1.1 riastrad } 625 1.1 riastrad 626 1.1 riastrad static bool assert_partial(struct drm_i915_gem_object *obj, 627 1.1 riastrad struct i915_vma *vma, 628 1.1 riastrad unsigned long offset, 629 1.1 riastrad unsigned long size) 630 1.1 riastrad { 631 1.1 riastrad struct sgt_iter sgt; 632 1.1 riastrad dma_addr_t dma; 633 1.1 riastrad 634 1.1 riastrad for_each_sgt_daddr(dma, sgt, vma->pages) { 635 1.1 riastrad dma_addr_t src; 636 1.1 riastrad 637 1.1 riastrad if (!size) { 638 1.1 riastrad pr_err("Partial scattergather list too long\n"); 639 1.1 riastrad return false; 640 1.1 riastrad } 641 1.1 riastrad 642 1.1 riastrad src = i915_gem_object_get_dma_address(obj, offset); 643 1.1 riastrad if (src != dma) { 644 1.1 riastrad pr_err("DMA mismatch for partial page offset %lu\n", 645 1.1 riastrad offset); 646 1.1 riastrad return false; 647 1.1 riastrad } 648 1.1 riastrad 649 1.1 riastrad offset++; 650 1.1 riastrad size--; 651 1.1 riastrad } 652 1.1 riastrad 653 1.1 riastrad return true; 654 1.1 riastrad } 655 1.1 riastrad 656 1.1 riastrad static bool assert_pin(struct i915_vma *vma, 657 1.1 riastrad struct i915_ggtt_view *view, 658 1.1 riastrad u64 size, 659 1.1 riastrad const char *name) 660 1.1 riastrad { 661 1.1 riastrad bool ok = true; 662 1.1 riastrad 663 1.1 riastrad if (vma->size != size) { 664 1.1 riastrad pr_err("(%s) VMA is wrong size, expected %llu, found %llu\n", 665 1.1 riastrad name, size, vma->size); 666 1.1 riastrad ok = false; 667 1.1 riastrad } 668 1.1 riastrad 669 1.1 riastrad if (vma->node.size < vma->size) { 670 1.1 riastrad pr_err("(%s) VMA binding too small, expected %llu, found %llu\n", 671 1.1 riastrad name, vma->size, vma->node.size); 672 1.1 riastrad ok = false; 673 1.1 riastrad } 674 1.1 riastrad 675 1.1 riastrad if (view && view->type != I915_GGTT_VIEW_NORMAL) { 676 1.1 riastrad if (memcmp(&vma->ggtt_view, view, sizeof(*view))) { 677 1.1 riastrad pr_err("(%s) VMA mismatch upon creation!\n", 678 1.1 riastrad name); 679 1.1 riastrad ok = false; 680 1.1 riastrad } 681 1.1 riastrad 682 1.1 riastrad if (vma->pages == vma->obj->mm.pages) { 683 1.1 riastrad pr_err("(%s) VMA using original object pages!\n", 684 1.1 riastrad name); 685 1.1 riastrad ok = false; 686 1.1 riastrad } 687 1.1 riastrad } else { 688 1.1 riastrad if (vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) { 689 1.1 riastrad pr_err("Not the normal ggtt view! Found %d\n", 690 1.1 riastrad vma->ggtt_view.type); 691 1.1 riastrad ok = false; 692 1.1 riastrad } 693 1.1 riastrad 694 1.1 riastrad if (vma->pages != vma->obj->mm.pages) { 695 1.1 riastrad pr_err("VMA not using object pages!\n"); 696 1.1 riastrad ok = false; 697 1.1 riastrad } 698 1.1 riastrad } 699 1.1 riastrad 700 1.1 riastrad return ok; 701 1.1 riastrad } 702 1.1 riastrad 703 1.1 riastrad static int igt_vma_partial(void *arg) 704 1.1 riastrad { 705 1.1 riastrad struct i915_ggtt *ggtt = arg; 706 1.1 riastrad struct i915_address_space *vm = &ggtt->vm; 707 1.1 riastrad const unsigned int npages = 1021; /* prime! */ 708 1.1 riastrad struct drm_i915_gem_object *obj; 709 1.1 riastrad const struct phase { 710 1.1 riastrad const char *name; 711 1.1 riastrad } phases[] = { 712 1.1 riastrad { "create" }, 713 1.1 riastrad { "lookup" }, 714 1.1 riastrad { }, 715 1.1 riastrad }, *p; 716 1.1 riastrad unsigned int sz, offset; 717 1.1 riastrad struct i915_vma *vma; 718 1.1 riastrad int err = -ENOMEM; 719 1.1 riastrad 720 1.1 riastrad /* Create lots of different VMA for the object and check that 721 1.1 riastrad * we are returned the same VMA when we later request the same range. 722 1.1 riastrad */ 723 1.1 riastrad 724 1.1 riastrad obj = i915_gem_object_create_internal(vm->i915, npages * PAGE_SIZE); 725 1.1 riastrad if (IS_ERR(obj)) 726 1.1 riastrad goto out; 727 1.1 riastrad 728 1.1 riastrad for (p = phases; p->name; p++) { /* exercise both create/lookup */ 729 1.1 riastrad unsigned int count, nvma; 730 1.1 riastrad 731 1.1 riastrad nvma = 0; 732 1.1 riastrad for_each_prime_number_from(sz, 1, npages) { 733 1.1 riastrad for_each_prime_number_from(offset, 0, npages - sz) { 734 1.1 riastrad struct i915_ggtt_view view; 735 1.1 riastrad 736 1.1 riastrad view.type = I915_GGTT_VIEW_PARTIAL; 737 1.1 riastrad view.partial.offset = offset; 738 1.1 riastrad view.partial.size = sz; 739 1.1 riastrad 740 1.1 riastrad if (sz == npages) 741 1.1 riastrad view.type = I915_GGTT_VIEW_NORMAL; 742 1.1 riastrad 743 1.1 riastrad vma = checked_vma_instance(obj, vm, &view); 744 1.1 riastrad if (IS_ERR(vma)) { 745 1.1 riastrad err = PTR_ERR(vma); 746 1.1 riastrad goto out_object; 747 1.1 riastrad } 748 1.1 riastrad 749 1.1 riastrad err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL); 750 1.1 riastrad if (err) 751 1.1 riastrad goto out_object; 752 1.1 riastrad 753 1.1 riastrad if (!assert_pin(vma, &view, sz*PAGE_SIZE, p->name)) { 754 1.1 riastrad pr_err("(%s) Inconsistent partial pinning for (offset=%d, size=%d)\n", 755 1.1 riastrad p->name, offset, sz); 756 1.1 riastrad err = -EINVAL; 757 1.1 riastrad goto out_object; 758 1.1 riastrad } 759 1.1 riastrad 760 1.1 riastrad if (!assert_partial(obj, vma, offset, sz)) { 761 1.1 riastrad pr_err("(%s) Inconsistent partial pages for (offset=%d, size=%d)\n", 762 1.1 riastrad p->name, offset, sz); 763 1.1 riastrad err = -EINVAL; 764 1.1 riastrad goto out_object; 765 1.1 riastrad } 766 1.1 riastrad 767 1.1 riastrad i915_vma_unpin(vma); 768 1.1 riastrad nvma++; 769 1.1 riastrad 770 1.1 riastrad cond_resched(); 771 1.1 riastrad } 772 1.1 riastrad } 773 1.1 riastrad 774 1.1 riastrad count = 0; 775 1.1 riastrad list_for_each_entry(vma, &obj->vma.list, obj_link) 776 1.1 riastrad count++; 777 1.1 riastrad if (count != nvma) { 778 1.1 riastrad pr_err("(%s) All partial vma were not recorded on the obj->vma_list: found %u, expected %u\n", 779 1.1 riastrad p->name, count, nvma); 780 1.1 riastrad err = -EINVAL; 781 1.1 riastrad goto out_object; 782 1.1 riastrad } 783 1.1 riastrad 784 1.1 riastrad /* Check that we did create the whole object mapping */ 785 1.1 riastrad vma = checked_vma_instance(obj, vm, NULL); 786 1.1 riastrad if (IS_ERR(vma)) { 787 1.1 riastrad err = PTR_ERR(vma); 788 1.1 riastrad goto out_object; 789 1.1 riastrad } 790 1.1 riastrad 791 1.1 riastrad err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL); 792 1.1 riastrad if (err) 793 1.1 riastrad goto out_object; 794 1.1 riastrad 795 1.1 riastrad if (!assert_pin(vma, NULL, obj->base.size, p->name)) { 796 1.1 riastrad pr_err("(%s) inconsistent full pin\n", p->name); 797 1.1 riastrad err = -EINVAL; 798 1.1 riastrad goto out_object; 799 1.1 riastrad } 800 1.1 riastrad 801 1.1 riastrad i915_vma_unpin(vma); 802 1.1 riastrad 803 1.1 riastrad count = 0; 804 1.1 riastrad list_for_each_entry(vma, &obj->vma.list, obj_link) 805 1.1 riastrad count++; 806 1.1 riastrad if (count != nvma) { 807 1.1 riastrad pr_err("(%s) allocated an extra full vma!\n", p->name); 808 1.1 riastrad err = -EINVAL; 809 1.1 riastrad goto out_object; 810 1.1 riastrad } 811 1.1 riastrad } 812 1.1 riastrad 813 1.1 riastrad out_object: 814 1.1 riastrad i915_gem_object_put(obj); 815 1.1 riastrad out: 816 1.1 riastrad return err; 817 1.1 riastrad } 818 1.1 riastrad 819 1.1 riastrad int i915_vma_mock_selftests(void) 820 1.1 riastrad { 821 1.1 riastrad static const struct i915_subtest tests[] = { 822 1.1 riastrad SUBTEST(igt_vma_create), 823 1.1 riastrad SUBTEST(igt_vma_pin1), 824 1.1 riastrad SUBTEST(igt_vma_rotate_remap), 825 1.1 riastrad SUBTEST(igt_vma_partial), 826 1.1 riastrad }; 827 1.1 riastrad struct drm_i915_private *i915; 828 1.1 riastrad struct i915_ggtt *ggtt; 829 1.1 riastrad int err; 830 1.1 riastrad 831 1.1 riastrad i915 = mock_gem_device(); 832 1.1 riastrad if (!i915) 833 1.1 riastrad return -ENOMEM; 834 1.1 riastrad 835 1.1 riastrad ggtt = kmalloc(sizeof(*ggtt), GFP_KERNEL); 836 1.1 riastrad if (!ggtt) { 837 1.1 riastrad err = -ENOMEM; 838 1.1 riastrad goto out_put; 839 1.1 riastrad } 840 1.1 riastrad mock_init_ggtt(i915, ggtt); 841 1.1 riastrad 842 1.1 riastrad err = i915_subtests(tests, ggtt); 843 1.1 riastrad 844 1.1 riastrad mock_device_flush(i915); 845 1.1 riastrad i915_gem_drain_freed_objects(i915); 846 1.1 riastrad mock_fini_ggtt(ggtt); 847 1.1 riastrad kfree(ggtt); 848 1.1 riastrad out_put: 849 1.1 riastrad drm_dev_put(&i915->drm); 850 1.1 riastrad return err; 851 1.1 riastrad } 852 1.1 riastrad 853 1.1 riastrad static int igt_vma_remapped_gtt(void *arg) 854 1.1 riastrad { 855 1.1 riastrad struct drm_i915_private *i915 = arg; 856 1.1 riastrad const struct intel_remapped_plane_info planes[] = { 857 1.1 riastrad { .width = 1, .height = 1, .stride = 1 }, 858 1.1 riastrad { .width = 2, .height = 2, .stride = 2 }, 859 1.1 riastrad { .width = 4, .height = 4, .stride = 4 }, 860 1.1 riastrad { .width = 8, .height = 8, .stride = 8 }, 861 1.1 riastrad 862 1.1 riastrad { .width = 3, .height = 5, .stride = 3 }, 863 1.1 riastrad { .width = 3, .height = 5, .stride = 4 }, 864 1.1 riastrad { .width = 3, .height = 5, .stride = 5 }, 865 1.1 riastrad 866 1.1 riastrad { .width = 5, .height = 3, .stride = 5 }, 867 1.1 riastrad { .width = 5, .height = 3, .stride = 7 }, 868 1.1 riastrad { .width = 5, .height = 3, .stride = 9 }, 869 1.1 riastrad 870 1.1 riastrad { .width = 4, .height = 6, .stride = 6 }, 871 1.1 riastrad { .width = 6, .height = 4, .stride = 6 }, 872 1.1 riastrad { } 873 1.1 riastrad }, *p; 874 1.1 riastrad enum i915_ggtt_view_type types[] = { 875 1.1 riastrad I915_GGTT_VIEW_ROTATED, 876 1.1 riastrad I915_GGTT_VIEW_REMAPPED, 877 1.1 riastrad 0, 878 1.1 riastrad }, *t; 879 1.1 riastrad struct drm_i915_gem_object *obj; 880 1.1 riastrad intel_wakeref_t wakeref; 881 1.1 riastrad int err = 0; 882 1.1 riastrad 883 1.1 riastrad obj = i915_gem_object_create_internal(i915, 10 * 10 * PAGE_SIZE); 884 1.1 riastrad if (IS_ERR(obj)) 885 1.1 riastrad return PTR_ERR(obj); 886 1.1 riastrad 887 1.1 riastrad wakeref = intel_runtime_pm_get(&i915->runtime_pm); 888 1.1 riastrad 889 1.1 riastrad for (t = types; *t; t++) { 890 1.1 riastrad for (p = planes; p->width; p++) { 891 1.1 riastrad struct i915_ggtt_view view = { 892 1.1 riastrad .type = *t, 893 1.1 riastrad .rotated.plane[0] = *p, 894 1.1 riastrad }; 895 1.1 riastrad struct i915_vma *vma; 896 1.1 riastrad u32 __iomem *map; 897 1.1 riastrad unsigned int x, y; 898 1.1 riastrad int err; 899 1.1 riastrad 900 1.1 riastrad i915_gem_object_lock(obj); 901 1.1 riastrad err = i915_gem_object_set_to_gtt_domain(obj, true); 902 1.1 riastrad i915_gem_object_unlock(obj); 903 1.1 riastrad if (err) 904 1.1 riastrad goto out; 905 1.1 riastrad 906 1.1 riastrad vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, PIN_MAPPABLE); 907 1.1 riastrad if (IS_ERR(vma)) { 908 1.1 riastrad err = PTR_ERR(vma); 909 1.1 riastrad goto out; 910 1.1 riastrad } 911 1.1 riastrad 912 1.1 riastrad GEM_BUG_ON(vma->ggtt_view.type != *t); 913 1.1 riastrad 914 1.1 riastrad map = i915_vma_pin_iomap(vma); 915 1.1 riastrad i915_vma_unpin(vma); 916 1.1 riastrad if (IS_ERR(map)) { 917 1.1 riastrad err = PTR_ERR(map); 918 1.1 riastrad goto out; 919 1.1 riastrad } 920 1.1 riastrad 921 1.1 riastrad for (y = 0 ; y < p->height; y++) { 922 1.1 riastrad for (x = 0 ; x < p->width; x++) { 923 1.1 riastrad unsigned int offset; 924 1.1 riastrad u32 val = y << 16 | x; 925 1.1 riastrad 926 1.1 riastrad if (*t == I915_GGTT_VIEW_ROTATED) 927 1.1 riastrad offset = (x * p->height + y) * PAGE_SIZE; 928 1.1 riastrad else 929 1.1 riastrad offset = (y * p->width + x) * PAGE_SIZE; 930 1.1 riastrad 931 1.1 riastrad iowrite32(val, &map[offset / sizeof(*map)]); 932 1.1 riastrad } 933 1.1 riastrad } 934 1.1 riastrad 935 1.1 riastrad i915_vma_unpin_iomap(vma); 936 1.1 riastrad 937 1.1 riastrad vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE); 938 1.1 riastrad if (IS_ERR(vma)) { 939 1.1 riastrad err = PTR_ERR(vma); 940 1.1 riastrad goto out; 941 1.1 riastrad } 942 1.1 riastrad 943 1.1 riastrad GEM_BUG_ON(vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL); 944 1.1 riastrad 945 1.1 riastrad map = i915_vma_pin_iomap(vma); 946 1.1 riastrad i915_vma_unpin(vma); 947 1.1 riastrad if (IS_ERR(map)) { 948 1.1 riastrad err = PTR_ERR(map); 949 1.1 riastrad goto out; 950 1.1 riastrad } 951 1.1 riastrad 952 1.1 riastrad for (y = 0 ; y < p->height; y++) { 953 1.1 riastrad for (x = 0 ; x < p->width; x++) { 954 1.1 riastrad unsigned int offset, src_idx; 955 1.1 riastrad u32 exp = y << 16 | x; 956 1.1 riastrad u32 val; 957 1.1 riastrad 958 1.1 riastrad if (*t == I915_GGTT_VIEW_ROTATED) 959 1.1 riastrad src_idx = rotated_index(&view.rotated, 0, x, y); 960 1.1 riastrad else 961 1.1 riastrad src_idx = remapped_index(&view.remapped, 0, x, y); 962 1.1 riastrad offset = src_idx * PAGE_SIZE; 963 1.1 riastrad 964 1.1 riastrad val = ioread32(&map[offset / sizeof(*map)]); 965 1.1 riastrad if (val != exp) { 966 1.1 riastrad pr_err("%s VMA write test failed, expected 0x%x, found 0x%x\n", 967 1.1 riastrad *t == I915_GGTT_VIEW_ROTATED ? "Rotated" : "Remapped", 968 1.1 riastrad val, exp); 969 1.1 riastrad i915_vma_unpin_iomap(vma); 970 1.1 riastrad goto out; 971 1.1 riastrad } 972 1.1 riastrad } 973 1.1 riastrad } 974 1.1 riastrad i915_vma_unpin_iomap(vma); 975 1.1 riastrad 976 1.1 riastrad cond_resched(); 977 1.1 riastrad } 978 1.1 riastrad } 979 1.1 riastrad 980 1.1 riastrad out: 981 1.1 riastrad intel_runtime_pm_put(&i915->runtime_pm, wakeref); 982 1.1 riastrad i915_gem_object_put(obj); 983 1.1 riastrad 984 1.1 riastrad return err; 985 1.1 riastrad } 986 1.1 riastrad 987 1.1 riastrad int i915_vma_live_selftests(struct drm_i915_private *i915) 988 1.1 riastrad { 989 1.1 riastrad static const struct i915_subtest tests[] = { 990 1.1 riastrad SUBTEST(igt_vma_remapped_gtt), 991 1.1 riastrad }; 992 1.1 riastrad 993 1.1 riastrad return i915_subtests(tests, i915); 994 1.1 riastrad } 995