linux/drivers/gpu/drm/i915/selftests/i915_timeline.c
<<
>>
Prefs
   1/*
   2 * SPDX-License-Identifier: MIT
   3 *
   4 * Copyright © 2017-2018 Intel Corporation
   5 */
   6
   7#include <linux/prime_numbers.h>
   8
   9#include "gem/i915_gem_pm.h"
  10
  11#include "i915_random.h"
  12#include "i915_selftest.h"
  13
  14#include "igt_flush_test.h"
  15#include "mock_gem_device.h"
  16#include "mock_timeline.h"
  17
  18static struct page *hwsp_page(struct i915_timeline *tl)
  19{
  20        struct drm_i915_gem_object *obj = tl->hwsp_ggtt->obj;
  21
  22        GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
  23        return sg_page(obj->mm.pages->sgl);
  24}
  25
  26static unsigned long hwsp_cacheline(struct i915_timeline *tl)
  27{
  28        unsigned long address = (unsigned long)page_address(hwsp_page(tl));
  29
  30        return (address + tl->hwsp_offset) / CACHELINE_BYTES;
  31}
  32
  33#define CACHELINES_PER_PAGE (PAGE_SIZE / CACHELINE_BYTES)
  34
  35struct mock_hwsp_freelist {
  36        struct drm_i915_private *i915;
  37        struct radix_tree_root cachelines;
  38        struct i915_timeline **history;
  39        unsigned long count, max;
  40        struct rnd_state prng;
  41};
  42
  43enum {
  44        SHUFFLE = BIT(0),
  45};
  46
  47static void __mock_hwsp_record(struct mock_hwsp_freelist *state,
  48                               unsigned int idx,
  49                               struct i915_timeline *tl)
  50{
  51        tl = xchg(&state->history[idx], tl);
  52        if (tl) {
  53                radix_tree_delete(&state->cachelines, hwsp_cacheline(tl));
  54                i915_timeline_put(tl);
  55        }
  56}
  57
  58static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state,
  59                                unsigned int count,
  60                                unsigned int flags)
  61{
  62        struct i915_timeline *tl;
  63        unsigned int idx;
  64
  65        while (count--) {
  66                unsigned long cacheline;
  67                int err;
  68
  69                tl = i915_timeline_create(state->i915, NULL);
  70                if (IS_ERR(tl))
  71                        return PTR_ERR(tl);
  72
  73                cacheline = hwsp_cacheline(tl);
  74                err = radix_tree_insert(&state->cachelines, cacheline, tl);
  75                if (err) {
  76                        if (err == -EEXIST) {
  77                                pr_err("HWSP cacheline %lu already used; duplicate allocation!\n",
  78                                       cacheline);
  79                        }
  80                        i915_timeline_put(tl);
  81                        return err;
  82                }
  83
  84                idx = state->count++ % state->max;
  85                __mock_hwsp_record(state, idx, tl);
  86        }
  87
  88        if (flags & SHUFFLE)
  89                i915_prandom_shuffle(state->history,
  90                                     sizeof(*state->history),
  91                                     min(state->count, state->max),
  92                                     &state->prng);
  93
  94        count = i915_prandom_u32_max_state(min(state->count, state->max),
  95                                           &state->prng);
  96        while (count--) {
  97                idx = --state->count % state->max;
  98                __mock_hwsp_record(state, idx, NULL);
  99        }
 100
 101        return 0;
 102}
 103
 104static int mock_hwsp_freelist(void *arg)
 105{
 106        struct mock_hwsp_freelist state;
 107        const struct {
 108                const char *name;
 109                unsigned int flags;
 110        } phases[] = {
 111                { "linear", 0 },
 112                { "shuffled", SHUFFLE },
 113                { },
 114        }, *p;
 115        unsigned int na;
 116        int err = 0;
 117
 118        INIT_RADIX_TREE(&state.cachelines, GFP_KERNEL);
 119        state.prng = I915_RND_STATE_INITIALIZER(i915_selftest.random_seed);
 120
 121        state.i915 = mock_gem_device();
 122        if (!state.i915)
 123                return -ENOMEM;
 124
 125        /*
 126         * Create a bunch of timelines and check that their HWSP do not overlap.
 127         * Free some, and try again.
 128         */
 129
 130        state.max = PAGE_SIZE / sizeof(*state.history);
 131        state.count = 0;
 132        state.history = kcalloc(state.max, sizeof(*state.history), GFP_KERNEL);
 133        if (!state.history) {
 134                err = -ENOMEM;
 135                goto err_put;
 136        }
 137
 138        mutex_lock(&state.i915->drm.struct_mutex);
 139        for (p = phases; p->name; p++) {
 140                pr_debug("%s(%s)\n", __func__, p->name);
 141                for_each_prime_number_from(na, 1, 2 * CACHELINES_PER_PAGE) {
 142                        err = __mock_hwsp_timeline(&state, na, p->flags);
 143                        if (err)
 144                                goto out;
 145                }
 146        }
 147
 148out:
 149        for (na = 0; na < state.max; na++)
 150                __mock_hwsp_record(&state, na, NULL);
 151        mutex_unlock(&state.i915->drm.struct_mutex);
 152        kfree(state.history);
 153err_put:
 154        drm_dev_put(&state.i915->drm);
 155        return err;
 156}
 157
 158struct __igt_sync {
 159        const char *name;
 160        u32 seqno;
 161        bool expected;
 162        bool set;
 163};
 164
 165static int __igt_sync(struct i915_timeline *tl,
 166                      u64 ctx,
 167                      const struct __igt_sync *p,
 168                      const char *name)
 169{
 170        int ret;
 171
 172        if (__i915_timeline_sync_is_later(tl, ctx, p->seqno) != p->expected) {
 173                pr_err("%s: %s(ctx=%llu, seqno=%u) expected passed %s but failed\n",
 174                       name, p->name, ctx, p->seqno, yesno(p->expected));
 175                return -EINVAL;
 176        }
 177
 178        if (p->set) {
 179                ret = __i915_timeline_sync_set(tl, ctx, p->seqno);
 180                if (ret)
 181                        return ret;
 182        }
 183
 184        return 0;
 185}
 186
 187static int igt_sync(void *arg)
 188{
 189        const struct __igt_sync pass[] = {
 190                { "unset", 0, false, false },
 191                { "new", 0, false, true },
 192                { "0a", 0, true, true },
 193                { "1a", 1, false, true },
 194                { "1b", 1, true, true },
 195                { "0b", 0, true, false },
 196                { "2a", 2, false, true },
 197                { "4", 4, false, true },
 198                { "INT_MAX", INT_MAX, false, true },
 199                { "INT_MAX-1", INT_MAX-1, true, false },
 200                { "INT_MAX+1", (u32)INT_MAX+1, false, true },
 201                { "INT_MAX", INT_MAX, true, false },
 202                { "UINT_MAX", UINT_MAX, false, true },
 203                { "wrap", 0, false, true },
 204                { "unwrap", UINT_MAX, true, false },
 205                {},
 206        }, *p;
 207        struct i915_timeline tl;
 208        int order, offset;
 209        int ret = -ENODEV;
 210
 211        mock_timeline_init(&tl, 0);
 212        for (p = pass; p->name; p++) {
 213                for (order = 1; order < 64; order++) {
 214                        for (offset = -1; offset <= (order > 1); offset++) {
 215                                u64 ctx = BIT_ULL(order) + offset;
 216
 217                                ret = __igt_sync(&tl, ctx, p, "1");
 218                                if (ret)
 219                                        goto out;
 220                        }
 221                }
 222        }
 223        mock_timeline_fini(&tl);
 224
 225        mock_timeline_init(&tl, 0);
 226        for (order = 1; order < 64; order++) {
 227                for (offset = -1; offset <= (order > 1); offset++) {
 228                        u64 ctx = BIT_ULL(order) + offset;
 229
 230                        for (p = pass; p->name; p++) {
 231                                ret = __igt_sync(&tl, ctx, p, "2");
 232                                if (ret)
 233                                        goto out;
 234                        }
 235                }
 236        }
 237
 238out:
 239        mock_timeline_fini(&tl);
 240        return ret;
 241}
 242
 243static unsigned int random_engine(struct rnd_state *rnd)
 244{
 245        return i915_prandom_u32_max_state(I915_NUM_ENGINES, rnd);
 246}
 247
 248static int bench_sync(void *arg)
 249{
 250        struct rnd_state prng;
 251        struct i915_timeline tl;
 252        unsigned long end_time, count;
 253        u64 prng32_1M;
 254        ktime_t kt;
 255        int order, last_order;
 256
 257        mock_timeline_init(&tl, 0);
 258
 259        /* Lookups from cache are very fast and so the random number generation
 260         * and the loop itself becomes a significant factor in the per-iteration
 261         * timings. We try to compensate the results by measuring the overhead
 262         * of the prng and subtract it from the reported results.
 263         */
 264        prandom_seed_state(&prng, i915_selftest.random_seed);
 265        count = 0;
 266        kt = ktime_get();
 267        end_time = jiffies + HZ/10;
 268        do {
 269                u32 x;
 270
 271                /* Make sure the compiler doesn't optimise away the prng call */
 272                WRITE_ONCE(x, prandom_u32_state(&prng));
 273
 274                count++;
 275        } while (!time_after(jiffies, end_time));
 276        kt = ktime_sub(ktime_get(), kt);
 277        pr_debug("%s: %lu random evaluations, %lluns/prng\n",
 278                 __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 279        prng32_1M = div64_ul(ktime_to_ns(kt) << 20, count);
 280
 281        /* Benchmark (only) setting random context ids */
 282        prandom_seed_state(&prng, i915_selftest.random_seed);
 283        count = 0;
 284        kt = ktime_get();
 285        end_time = jiffies + HZ/10;
 286        do {
 287                u64 id = i915_prandom_u64_state(&prng);
 288
 289                __i915_timeline_sync_set(&tl, id, 0);
 290                count++;
 291        } while (!time_after(jiffies, end_time));
 292        kt = ktime_sub(ktime_get(), kt);
 293        kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
 294        pr_info("%s: %lu random insertions, %lluns/insert\n",
 295                __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 296
 297        /* Benchmark looking up the exact same context ids as we just set */
 298        prandom_seed_state(&prng, i915_selftest.random_seed);
 299        end_time = count;
 300        kt = ktime_get();
 301        while (end_time--) {
 302                u64 id = i915_prandom_u64_state(&prng);
 303
 304                if (!__i915_timeline_sync_is_later(&tl, id, 0)) {
 305                        mock_timeline_fini(&tl);
 306                        pr_err("Lookup of %llu failed\n", id);
 307                        return -EINVAL;
 308                }
 309        }
 310        kt = ktime_sub(ktime_get(), kt);
 311        kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
 312        pr_info("%s: %lu random lookups, %lluns/lookup\n",
 313                __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 314
 315        mock_timeline_fini(&tl);
 316        cond_resched();
 317
 318        mock_timeline_init(&tl, 0);
 319
 320        /* Benchmark setting the first N (in order) contexts */
 321        count = 0;
 322        kt = ktime_get();
 323        end_time = jiffies + HZ/10;
 324        do {
 325                __i915_timeline_sync_set(&tl, count++, 0);
 326        } while (!time_after(jiffies, end_time));
 327        kt = ktime_sub(ktime_get(), kt);
 328        pr_info("%s: %lu in-order insertions, %lluns/insert\n",
 329                __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 330
 331        /* Benchmark looking up the exact same context ids as we just set */
 332        end_time = count;
 333        kt = ktime_get();
 334        while (end_time--) {
 335                if (!__i915_timeline_sync_is_later(&tl, end_time, 0)) {
 336                        pr_err("Lookup of %lu failed\n", end_time);
 337                        mock_timeline_fini(&tl);
 338                        return -EINVAL;
 339                }
 340        }
 341        kt = ktime_sub(ktime_get(), kt);
 342        pr_info("%s: %lu in-order lookups, %lluns/lookup\n",
 343                __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 344
 345        mock_timeline_fini(&tl);
 346        cond_resched();
 347
 348        mock_timeline_init(&tl, 0);
 349
 350        /* Benchmark searching for a random context id and maybe changing it */
 351        prandom_seed_state(&prng, i915_selftest.random_seed);
 352        count = 0;
 353        kt = ktime_get();
 354        end_time = jiffies + HZ/10;
 355        do {
 356                u32 id = random_engine(&prng);
 357                u32 seqno = prandom_u32_state(&prng);
 358
 359                if (!__i915_timeline_sync_is_later(&tl, id, seqno))
 360                        __i915_timeline_sync_set(&tl, id, seqno);
 361
 362                count++;
 363        } while (!time_after(jiffies, end_time));
 364        kt = ktime_sub(ktime_get(), kt);
 365        kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
 366        pr_info("%s: %lu repeated insert/lookups, %lluns/op\n",
 367                __func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 368        mock_timeline_fini(&tl);
 369        cond_resched();
 370
 371        /* Benchmark searching for a known context id and changing the seqno */
 372        for (last_order = 1, order = 1; order < 32;
 373             ({ int tmp = last_order; last_order = order; order += tmp; })) {
 374                unsigned int mask = BIT(order) - 1;
 375
 376                mock_timeline_init(&tl, 0);
 377
 378                count = 0;
 379                kt = ktime_get();
 380                end_time = jiffies + HZ/10;
 381                do {
 382                        /* Without assuming too many details of the underlying
 383                         * implementation, try to identify its phase-changes
 384                         * (if any)!
 385                         */
 386                        u64 id = (u64)(count & mask) << order;
 387
 388                        __i915_timeline_sync_is_later(&tl, id, 0);
 389                        __i915_timeline_sync_set(&tl, id, 0);
 390
 391                        count++;
 392                } while (!time_after(jiffies, end_time));
 393                kt = ktime_sub(ktime_get(), kt);
 394                pr_info("%s: %lu cyclic/%d insert/lookups, %lluns/op\n",
 395                        __func__, count, order,
 396                        (long long)div64_ul(ktime_to_ns(kt), count));
 397                mock_timeline_fini(&tl);
 398                cond_resched();
 399        }
 400
 401        return 0;
 402}
 403
 404int i915_timeline_mock_selftests(void)
 405{
 406        static const struct i915_subtest tests[] = {
 407                SUBTEST(mock_hwsp_freelist),
 408                SUBTEST(igt_sync),
 409                SUBTEST(bench_sync),
 410        };
 411
 412        return i915_subtests(tests, NULL);
 413}
 414
 415static int emit_ggtt_store_dw(struct i915_request *rq, u32 addr, u32 value)
 416{
 417        u32 *cs;
 418
 419        cs = intel_ring_begin(rq, 4);
 420        if (IS_ERR(cs))
 421                return PTR_ERR(cs);
 422
 423        if (INTEL_GEN(rq->i915) >= 8) {
 424                *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
 425                *cs++ = addr;
 426                *cs++ = 0;
 427                *cs++ = value;
 428        } else if (INTEL_GEN(rq->i915) >= 4) {
 429                *cs++ = MI_STORE_DWORD_IMM_GEN4 | MI_USE_GGTT;
 430                *cs++ = 0;
 431                *cs++ = addr;
 432                *cs++ = value;
 433        } else {
 434                *cs++ = MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL;
 435                *cs++ = addr;
 436                *cs++ = value;
 437                *cs++ = MI_NOOP;
 438        }
 439
 440        intel_ring_advance(rq, cs);
 441
 442        return 0;
 443}
 444
 445static struct i915_request *
 446tl_write(struct i915_timeline *tl, struct intel_engine_cs *engine, u32 value)
 447{
 448        struct i915_request *rq;
 449        int err;
 450
 451        lockdep_assert_held(&tl->i915->drm.struct_mutex); /* lazy rq refs */
 452
 453        err = i915_timeline_pin(tl);
 454        if (err) {
 455                rq = ERR_PTR(err);
 456                goto out;
 457        }
 458
 459        rq = i915_request_create(engine->kernel_context);
 460        if (IS_ERR(rq))
 461                goto out_unpin;
 462
 463        err = emit_ggtt_store_dw(rq, tl->hwsp_offset, value);
 464        i915_request_add(rq);
 465        if (err)
 466                rq = ERR_PTR(err);
 467
 468out_unpin:
 469        i915_timeline_unpin(tl);
 470out:
 471        if (IS_ERR(rq))
 472                pr_err("Failed to write to timeline!\n");
 473        return rq;
 474}
 475
 476static struct i915_timeline *
 477checked_i915_timeline_create(struct drm_i915_private *i915)
 478{
 479        struct i915_timeline *tl;
 480
 481        tl = i915_timeline_create(i915, NULL);
 482        if (IS_ERR(tl))
 483                return tl;
 484
 485        if (*tl->hwsp_seqno != tl->seqno) {
 486                pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n",
 487                       *tl->hwsp_seqno, tl->seqno);
 488                i915_timeline_put(tl);
 489                return ERR_PTR(-EINVAL);
 490        }
 491
 492        return tl;
 493}
 494
 495static int live_hwsp_engine(void *arg)
 496{
 497#define NUM_TIMELINES 4096
 498        struct drm_i915_private *i915 = arg;
 499        struct i915_timeline **timelines;
 500        struct intel_engine_cs *engine;
 501        enum intel_engine_id id;
 502        intel_wakeref_t wakeref;
 503        unsigned long count, n;
 504        int err = 0;
 505
 506        /*
 507         * Create a bunch of timelines and check we can write
 508         * independently to each of their breadcrumb slots.
 509         */
 510
 511        timelines = kvmalloc_array(NUM_TIMELINES * I915_NUM_ENGINES,
 512                                   sizeof(*timelines),
 513                                   GFP_KERNEL);
 514        if (!timelines)
 515                return -ENOMEM;
 516
 517        mutex_lock(&i915->drm.struct_mutex);
 518        wakeref = intel_runtime_pm_get(&i915->runtime_pm);
 519
 520        count = 0;
 521        for_each_engine(engine, i915, id) {
 522                if (!intel_engine_can_store_dword(engine))
 523                        continue;
 524
 525                for (n = 0; n < NUM_TIMELINES; n++) {
 526                        struct i915_timeline *tl;
 527                        struct i915_request *rq;
 528
 529                        tl = checked_i915_timeline_create(i915);
 530                        if (IS_ERR(tl)) {
 531                                err = PTR_ERR(tl);
 532                                goto out;
 533                        }
 534
 535                        rq = tl_write(tl, engine, count);
 536                        if (IS_ERR(rq)) {
 537                                i915_timeline_put(tl);
 538                                err = PTR_ERR(rq);
 539                                goto out;
 540                        }
 541
 542                        timelines[count++] = tl;
 543                }
 544        }
 545
 546out:
 547        if (igt_flush_test(i915, I915_WAIT_LOCKED))
 548                err = -EIO;
 549
 550        for (n = 0; n < count; n++) {
 551                struct i915_timeline *tl = timelines[n];
 552
 553                if (!err && *tl->hwsp_seqno != n) {
 554                        pr_err("Invalid seqno stored in timeline %lu, found 0x%x\n",
 555                               n, *tl->hwsp_seqno);
 556                        err = -EINVAL;
 557                }
 558                i915_timeline_put(tl);
 559        }
 560
 561        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 562        mutex_unlock(&i915->drm.struct_mutex);
 563
 564        kvfree(timelines);
 565
 566        return err;
 567#undef NUM_TIMELINES
 568}
 569
 570static int live_hwsp_alternate(void *arg)
 571{
 572#define NUM_TIMELINES 4096
 573        struct drm_i915_private *i915 = arg;
 574        struct i915_timeline **timelines;
 575        struct intel_engine_cs *engine;
 576        enum intel_engine_id id;
 577        intel_wakeref_t wakeref;
 578        unsigned long count, n;
 579        int err = 0;
 580
 581        /*
 582         * Create a bunch of timelines and check we can write
 583         * independently to each of their breadcrumb slots with adjacent
 584         * engines.
 585         */
 586
 587        timelines = kvmalloc_array(NUM_TIMELINES * I915_NUM_ENGINES,
 588                                   sizeof(*timelines),
 589                                   GFP_KERNEL);
 590        if (!timelines)
 591                return -ENOMEM;
 592
 593        mutex_lock(&i915->drm.struct_mutex);
 594        wakeref = intel_runtime_pm_get(&i915->runtime_pm);
 595
 596        count = 0;
 597        for (n = 0; n < NUM_TIMELINES; n++) {
 598                for_each_engine(engine, i915, id) {
 599                        struct i915_timeline *tl;
 600                        struct i915_request *rq;
 601
 602                        if (!intel_engine_can_store_dword(engine))
 603                                continue;
 604
 605                        tl = checked_i915_timeline_create(i915);
 606                        if (IS_ERR(tl)) {
 607                                err = PTR_ERR(tl);
 608                                goto out;
 609                        }
 610
 611                        rq = tl_write(tl, engine, count);
 612                        if (IS_ERR(rq)) {
 613                                i915_timeline_put(tl);
 614                                err = PTR_ERR(rq);
 615                                goto out;
 616                        }
 617
 618                        timelines[count++] = tl;
 619                }
 620        }
 621
 622out:
 623        if (igt_flush_test(i915, I915_WAIT_LOCKED))
 624                err = -EIO;
 625
 626        for (n = 0; n < count; n++) {
 627                struct i915_timeline *tl = timelines[n];
 628
 629                if (!err && *tl->hwsp_seqno != n) {
 630                        pr_err("Invalid seqno stored in timeline %lu, found 0x%x\n",
 631                               n, *tl->hwsp_seqno);
 632                        err = -EINVAL;
 633                }
 634                i915_timeline_put(tl);
 635        }
 636
 637        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 638        mutex_unlock(&i915->drm.struct_mutex);
 639
 640        kvfree(timelines);
 641
 642        return err;
 643#undef NUM_TIMELINES
 644}
 645
 646static int live_hwsp_wrap(void *arg)
 647{
 648        struct drm_i915_private *i915 = arg;
 649        struct intel_engine_cs *engine;
 650        struct i915_timeline *tl;
 651        enum intel_engine_id id;
 652        intel_wakeref_t wakeref;
 653        int err = 0;
 654
 655        /*
 656         * Across a seqno wrap, we need to keep the old cacheline alive for
 657         * foreign GPU references.
 658         */
 659
 660        mutex_lock(&i915->drm.struct_mutex);
 661        wakeref = intel_runtime_pm_get(&i915->runtime_pm);
 662
 663        tl = i915_timeline_create(i915, NULL);
 664        if (IS_ERR(tl)) {
 665                err = PTR_ERR(tl);
 666                goto out_rpm;
 667        }
 668        if (!tl->has_initial_breadcrumb || !tl->hwsp_cacheline)
 669                goto out_free;
 670
 671        err = i915_timeline_pin(tl);
 672        if (err)
 673                goto out_free;
 674
 675        for_each_engine(engine, i915, id) {
 676                const u32 *hwsp_seqno[2];
 677                struct i915_request *rq;
 678                u32 seqno[2];
 679
 680                if (!intel_engine_can_store_dword(engine))
 681                        continue;
 682
 683                rq = i915_request_create(engine->kernel_context);
 684                if (IS_ERR(rq)) {
 685                        err = PTR_ERR(rq);
 686                        goto out;
 687                }
 688
 689                tl->seqno = -4u;
 690
 691                err = i915_timeline_get_seqno(tl, rq, &seqno[0]);
 692                if (err) {
 693                        i915_request_add(rq);
 694                        goto out;
 695                }
 696                pr_debug("seqno[0]:%08x, hwsp_offset:%08x\n",
 697                         seqno[0], tl->hwsp_offset);
 698
 699                err = emit_ggtt_store_dw(rq, tl->hwsp_offset, seqno[0]);
 700                if (err) {
 701                        i915_request_add(rq);
 702                        goto out;
 703                }
 704                hwsp_seqno[0] = tl->hwsp_seqno;
 705
 706                err = i915_timeline_get_seqno(tl, rq, &seqno[1]);
 707                if (err) {
 708                        i915_request_add(rq);
 709                        goto out;
 710                }
 711                pr_debug("seqno[1]:%08x, hwsp_offset:%08x\n",
 712                         seqno[1], tl->hwsp_offset);
 713
 714                err = emit_ggtt_store_dw(rq, tl->hwsp_offset, seqno[1]);
 715                if (err) {
 716                        i915_request_add(rq);
 717                        goto out;
 718                }
 719                hwsp_seqno[1] = tl->hwsp_seqno;
 720
 721                /* With wrap should come a new hwsp */
 722                GEM_BUG_ON(seqno[1] >= seqno[0]);
 723                GEM_BUG_ON(hwsp_seqno[0] == hwsp_seqno[1]);
 724
 725                i915_request_add(rq);
 726
 727                if (i915_request_wait(rq, 0, HZ / 5) < 0) {
 728                        pr_err("Wait for timeline writes timed out!\n");
 729                        err = -EIO;
 730                        goto out;
 731                }
 732
 733                if (*hwsp_seqno[0] != seqno[0] || *hwsp_seqno[1] != seqno[1]) {
 734                        pr_err("Bad timeline values: found (%x, %x), expected (%x, %x)\n",
 735                               *hwsp_seqno[0], *hwsp_seqno[1],
 736                               seqno[0], seqno[1]);
 737                        err = -EINVAL;
 738                        goto out;
 739                }
 740
 741                i915_retire_requests(i915); /* recycle HWSP */
 742        }
 743
 744out:
 745        if (igt_flush_test(i915, I915_WAIT_LOCKED))
 746                err = -EIO;
 747
 748        i915_timeline_unpin(tl);
 749out_free:
 750        i915_timeline_put(tl);
 751out_rpm:
 752        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 753        mutex_unlock(&i915->drm.struct_mutex);
 754
 755        return err;
 756}
 757
 758static int live_hwsp_recycle(void *arg)
 759{
 760        struct drm_i915_private *i915 = arg;
 761        struct intel_engine_cs *engine;
 762        enum intel_engine_id id;
 763        intel_wakeref_t wakeref;
 764        unsigned long count;
 765        int err = 0;
 766
 767        /*
 768         * Check seqno writes into one timeline at a time. We expect to
 769         * recycle the breadcrumb slot between iterations and neither
 770         * want to confuse ourselves or the GPU.
 771         */
 772
 773        mutex_lock(&i915->drm.struct_mutex);
 774        wakeref = intel_runtime_pm_get(&i915->runtime_pm);
 775
 776        count = 0;
 777        for_each_engine(engine, i915, id) {
 778                IGT_TIMEOUT(end_time);
 779
 780                if (!intel_engine_can_store_dword(engine))
 781                        continue;
 782
 783                do {
 784                        struct i915_timeline *tl;
 785                        struct i915_request *rq;
 786
 787                        tl = checked_i915_timeline_create(i915);
 788                        if (IS_ERR(tl)) {
 789                                err = PTR_ERR(tl);
 790                                goto out;
 791                        }
 792
 793                        rq = tl_write(tl, engine, count);
 794                        if (IS_ERR(rq)) {
 795                                i915_timeline_put(tl);
 796                                err = PTR_ERR(rq);
 797                                goto out;
 798                        }
 799
 800                        if (i915_request_wait(rq, 0, HZ / 5) < 0) {
 801                                pr_err("Wait for timeline writes timed out!\n");
 802                                i915_timeline_put(tl);
 803                                err = -EIO;
 804                                goto out;
 805                        }
 806
 807                        if (*tl->hwsp_seqno != count) {
 808                                pr_err("Invalid seqno stored in timeline %lu, found 0x%x\n",
 809                                       count, *tl->hwsp_seqno);
 810                                err = -EINVAL;
 811                        }
 812
 813                        i915_timeline_put(tl);
 814                        count++;
 815
 816                        if (err)
 817                                goto out;
 818
 819                        i915_timelines_park(i915); /* Encourage recycling! */
 820                } while (!__igt_timeout(end_time, NULL));
 821        }
 822
 823out:
 824        if (igt_flush_test(i915, I915_WAIT_LOCKED))
 825                err = -EIO;
 826        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 827        mutex_unlock(&i915->drm.struct_mutex);
 828
 829        return err;
 830}
 831
 832int i915_timeline_live_selftests(struct drm_i915_private *i915)
 833{
 834        static const struct i915_subtest tests[] = {
 835                SUBTEST(live_hwsp_recycle),
 836                SUBTEST(live_hwsp_engine),
 837                SUBTEST(live_hwsp_alternate),
 838                SUBTEST(live_hwsp_wrap),
 839        };
 840
 841        if (i915_terminally_wedged(i915))
 842                return 0;
 843
 844        return i915_subtests(tests, i915);
 845}
 846