1
2
3
4
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
127
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
260
261
262
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
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
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
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
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
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
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
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
383
384
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);
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
508
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
583
584
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
657
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
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);
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
769
770
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);
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