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