1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2017-2018 Intel Corporation
5  */
6 
7 #include <linux/prime_numbers.h>
8 
9 #include "intel_engine_pm.h"
10 #include "intel_gt.h"
11 #include "intel_gt_requests.h"
12 
13 #include "../selftests/i915_random.h"
14 #include "../i915_selftest.h"
15 
16 #include "../selftests/igt_flush_test.h"
17 #include "../selftests/mock_gem_device.h"
18 #include "selftests/mock_timeline.h"
19 
20 static struct page *hwsp_page(struct intel_timeline *tl)
21 {
22 	struct drm_i915_gem_object *obj = tl->hwsp_ggtt->obj;
23 
24 	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
25 	return sg_page(obj->mm.pages->sgl);
26 }
27 
28 static unsigned long hwsp_cacheline(struct intel_timeline *tl)
29 {
30 	unsigned long address = (unsigned long)page_address(hwsp_page(tl));
31 
32 	return (address + tl->hwsp_offset) / CACHELINE_BYTES;
33 }
34 
35 #define CACHELINES_PER_PAGE (PAGE_SIZE / CACHELINE_BYTES)
36 
37 struct mock_hwsp_freelist {
38 	struct drm_i915_private *i915;
39 	struct radix_tree_root cachelines;
40 	struct intel_timeline **history;
41 	unsigned long count, max;
42 	struct rnd_state prng;
43 };
44 
45 enum {
46 	SHUFFLE = BIT(0),
47 };
48 
49 static void __mock_hwsp_record(struct mock_hwsp_freelist *state,
50 			       unsigned int idx,
51 			       struct intel_timeline *tl)
52 {
53 	tl = xchg(&state->history[idx], tl);
54 	if (tl) {
55 		radix_tree_delete(&state->cachelines, hwsp_cacheline(tl));
56 		intel_timeline_put(tl);
57 	}
58 }
59 
60 static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state,
61 				unsigned int count,
62 				unsigned int flags)
63 {
64 	struct intel_timeline *tl;
65 	unsigned int idx;
66 
67 	while (count--) {
68 		unsigned long cacheline;
69 		int err;
70 
71 		tl = intel_timeline_create(&state->i915->gt, NULL);
72 		if (IS_ERR(tl))
73 			return PTR_ERR(tl);
74 
75 		cacheline = hwsp_cacheline(tl);
76 		err = radix_tree_insert(&state->cachelines, cacheline, tl);
77 		if (err) {
78 			if (err == -EEXIST) {
79 				pr_err("HWSP cacheline %lu already used; duplicate allocation!\n",
80 				       cacheline);
81 			}
82 			intel_timeline_put(tl);
83 			return err;
84 		}
85 
86 		idx = state->count++ % state->max;
87 		__mock_hwsp_record(state, idx, tl);
88 	}
89 
90 	if (flags & SHUFFLE)
91 		i915_prandom_shuffle(state->history,
92 				     sizeof(*state->history),
93 				     min(state->count, state->max),
94 				     &state->prng);
95 
96 	count = i915_prandom_u32_max_state(min(state->count, state->max),
97 					   &state->prng);
98 	while (count--) {
99 		idx = --state->count % state->max;
100 		__mock_hwsp_record(state, idx, NULL);
101 	}
102 
103 	return 0;
104 }
105 
106 static int mock_hwsp_freelist(void *arg)
107 {
108 	struct mock_hwsp_freelist state;
109 	const struct {
110 		const char *name;
111 		unsigned int flags;
112 	} phases[] = {
113 		{ "linear", 0 },
114 		{ "shuffled", SHUFFLE },
115 		{ },
116 	}, *p;
117 	unsigned int na;
118 	int err = 0;
119 
120 	INIT_RADIX_TREE(&state.cachelines, GFP_KERNEL);
121 	state.prng = I915_RND_STATE_INITIALIZER(i915_selftest.random_seed);
122 
123 	state.i915 = mock_gem_device();
124 	if (!state.i915)
125 		return -ENOMEM;
126 
127 	/*
128 	 * Create a bunch of timelines and check that their HWSP do not overlap.
129 	 * Free some, and try again.
130 	 */
131 
132 	state.max = PAGE_SIZE / sizeof(*state.history);
133 	state.count = 0;
134 	state.history = kcalloc(state.max, sizeof(*state.history), GFP_KERNEL);
135 	if (!state.history) {
136 		err = -ENOMEM;
137 		goto err_put;
138 	}
139 
140 	for (p = phases; p->name; p++) {
141 		pr_debug("%s(%s)\n", __func__, p->name);
142 		for_each_prime_number_from(na, 1, 2 * CACHELINES_PER_PAGE) {
143 			err = __mock_hwsp_timeline(&state, na, p->flags);
144 			if (err)
145 				goto out;
146 		}
147 	}
148 
149 out:
150 	for (na = 0; na < state.max; na++)
151 		__mock_hwsp_record(&state, na, NULL);
152 	kfree(state.history);
153 err_put:
154 	drm_dev_put(&state.i915->drm);
155 	return err;
156 }
157 
158 struct __igt_sync {
159 	const char *name;
160 	u32 seqno;
161 	bool expected;
162 	bool set;
163 };
164 
165 static int __igt_sync(struct intel_timeline *tl,
166 		      u64 ctx,
167 		      const struct __igt_sync *p,
168 		      const char *name)
169 {
170 	int ret;
171 
172 	if (__intel_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 = __intel_timeline_sync_set(tl, ctx, p->seqno);
180 		if (ret)
181 			return ret;
182 	}
183 
184 	return 0;
185 }
186 
187 static 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 intel_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 
238 out:
239 	mock_timeline_fini(&tl);
240 	return ret;
241 }
242 
243 static unsigned int random_engine(struct rnd_state *rnd)
244 {
245 	return i915_prandom_u32_max_state(I915_NUM_ENGINES, rnd);
246 }
247 
248 static int bench_sync(void *arg)
249 {
250 	struct rnd_state prng;
251 	struct intel_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 		__intel_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 (!__intel_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 		__intel_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 (!__intel_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 (!__intel_timeline_sync_is_later(&tl, id, seqno))
360 			__intel_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 			__intel_timeline_sync_is_later(&tl, id, 0);
389 			__intel_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 
404 int intel_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 
415 static 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 
445 static struct i915_request *
446 tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value)
447 {
448 	struct i915_request *rq;
449 	int err;
450 
451 	err = intel_timeline_pin(tl);
452 	if (err) {
453 		rq = ERR_PTR(err);
454 		goto out;
455 	}
456 
457 	rq = i915_request_create(engine->kernel_context);
458 	if (IS_ERR(rq))
459 		goto out_unpin;
460 
461 	i915_request_get(rq);
462 
463 	err = emit_ggtt_store_dw(rq, tl->hwsp_offset, value);
464 	i915_request_add(rq);
465 	if (err) {
466 		i915_request_put(rq);
467 		rq = ERR_PTR(err);
468 	}
469 
470 out_unpin:
471 	intel_timeline_unpin(tl);
472 out:
473 	if (IS_ERR(rq))
474 		pr_err("Failed to write to timeline!\n");
475 	return rq;
476 }
477 
478 static struct intel_timeline *
479 checked_intel_timeline_create(struct drm_i915_private *i915)
480 {
481 	struct intel_timeline *tl;
482 
483 	tl = intel_timeline_create(&i915->gt, NULL);
484 	if (IS_ERR(tl))
485 		return tl;
486 
487 	if (*tl->hwsp_seqno != tl->seqno) {
488 		pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n",
489 		       *tl->hwsp_seqno, tl->seqno);
490 		intel_timeline_put(tl);
491 		return ERR_PTR(-EINVAL);
492 	}
493 
494 	return tl;
495 }
496 
497 static int live_hwsp_engine(void *arg)
498 {
499 #define NUM_TIMELINES 4096
500 	struct drm_i915_private *i915 = arg;
501 	struct intel_timeline **timelines;
502 	struct intel_engine_cs *engine;
503 	enum intel_engine_id id;
504 	unsigned long count, n;
505 	int err = 0;
506 
507 	/*
508 	 * Create a bunch of timelines and check we can write
509 	 * independently to each of their breadcrumb slots.
510 	 */
511 
512 	timelines = kvmalloc_array(NUM_TIMELINES * I915_NUM_ENGINES,
513 				   sizeof(*timelines),
514 				   GFP_KERNEL);
515 	if (!timelines)
516 		return -ENOMEM;
517 
518 	count = 0;
519 	for_each_engine(engine, i915, id) {
520 		if (!intel_engine_can_store_dword(engine))
521 			continue;
522 
523 		intel_engine_pm_get(engine);
524 
525 		for (n = 0; n < NUM_TIMELINES; n++) {
526 			struct intel_timeline *tl;
527 			struct i915_request *rq;
528 
529 			tl = checked_intel_timeline_create(i915);
530 			if (IS_ERR(tl)) {
531 				err = PTR_ERR(tl);
532 				break;
533 			}
534 
535 			rq = tl_write(tl, engine, count);
536 			if (IS_ERR(rq)) {
537 				intel_timeline_put(tl);
538 				err = PTR_ERR(rq);
539 				break;
540 			}
541 
542 			timelines[count++] = tl;
543 			i915_request_put(rq);
544 		}
545 
546 		intel_engine_pm_put(engine);
547 		if (err)
548 			break;
549 	}
550 
551 	if (igt_flush_test(i915))
552 		err = -EIO;
553 
554 	for (n = 0; n < count; n++) {
555 		struct intel_timeline *tl = timelines[n];
556 
557 		if (!err && *tl->hwsp_seqno != n) {
558 			pr_err("Invalid seqno stored in timeline %lu, found 0x%x\n",
559 			       n, *tl->hwsp_seqno);
560 			err = -EINVAL;
561 		}
562 		intel_timeline_put(tl);
563 	}
564 
565 	kvfree(timelines);
566 	return err;
567 #undef NUM_TIMELINES
568 }
569 
570 static int live_hwsp_alternate(void *arg)
571 {
572 #define NUM_TIMELINES 4096
573 	struct drm_i915_private *i915 = arg;
574 	struct intel_timeline **timelines;
575 	struct intel_engine_cs *engine;
576 	enum intel_engine_id id;
577 	unsigned long count, n;
578 	int err = 0;
579 
580 	/*
581 	 * Create a bunch of timelines and check we can write
582 	 * independently to each of their breadcrumb slots with adjacent
583 	 * engines.
584 	 */
585 
586 	timelines = kvmalloc_array(NUM_TIMELINES * I915_NUM_ENGINES,
587 				   sizeof(*timelines),
588 				   GFP_KERNEL);
589 	if (!timelines)
590 		return -ENOMEM;
591 
592 	count = 0;
593 	for (n = 0; n < NUM_TIMELINES; n++) {
594 		for_each_engine(engine, i915, id) {
595 			struct intel_timeline *tl;
596 			struct i915_request *rq;
597 
598 			if (!intel_engine_can_store_dword(engine))
599 				continue;
600 
601 			tl = checked_intel_timeline_create(i915);
602 			if (IS_ERR(tl)) {
603 				intel_engine_pm_put(engine);
604 				err = PTR_ERR(tl);
605 				goto out;
606 			}
607 
608 			intel_engine_pm_get(engine);
609 			rq = tl_write(tl, engine, count);
610 			intel_engine_pm_put(engine);
611 			if (IS_ERR(rq)) {
612 				intel_timeline_put(tl);
613 				err = PTR_ERR(rq);
614 				goto out;
615 			}
616 
617 			timelines[count++] = tl;
618 			i915_request_put(rq);
619 		}
620 	}
621 
622 out:
623 	if (igt_flush_test(i915))
624 		err = -EIO;
625 
626 	for (n = 0; n < count; n++) {
627 		struct intel_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 		intel_timeline_put(tl);
635 	}
636 
637 	kvfree(timelines);
638 	return err;
639 #undef NUM_TIMELINES
640 }
641 
642 static int live_hwsp_wrap(void *arg)
643 {
644 	struct drm_i915_private *i915 = arg;
645 	struct intel_gt *gt = &i915->gt;
646 	struct intel_engine_cs *engine;
647 	struct intel_timeline *tl;
648 	enum intel_engine_id id;
649 	int err = 0;
650 
651 	/*
652 	 * Across a seqno wrap, we need to keep the old cacheline alive for
653 	 * foreign GPU references.
654 	 */
655 
656 	tl = intel_timeline_create(gt, NULL);
657 	if (IS_ERR(tl))
658 		return PTR_ERR(tl);
659 
660 	if (!tl->has_initial_breadcrumb || !tl->hwsp_cacheline)
661 		goto out_free;
662 
663 	err = intel_timeline_pin(tl);
664 	if (err)
665 		goto out_free;
666 
667 	for_each_engine(engine, gt->i915, id) {
668 		const u32 *hwsp_seqno[2];
669 		struct i915_request *rq;
670 		u32 seqno[2];
671 
672 		if (!intel_engine_can_store_dword(engine))
673 			continue;
674 
675 		intel_engine_pm_get(engine);
676 		rq = i915_request_create(engine->kernel_context);
677 		intel_engine_pm_put(engine);
678 		if (IS_ERR(rq)) {
679 			err = PTR_ERR(rq);
680 			goto out;
681 		}
682 
683 		tl->seqno = -4u;
684 
685 		mutex_lock_nested(&tl->mutex, SINGLE_DEPTH_NESTING);
686 		err = intel_timeline_get_seqno(tl, rq, &seqno[0]);
687 		mutex_unlock(&tl->mutex);
688 		if (err) {
689 			i915_request_add(rq);
690 			goto out;
691 		}
692 		pr_debug("seqno[0]:%08x, hwsp_offset:%08x\n",
693 			 seqno[0], tl->hwsp_offset);
694 
695 		err = emit_ggtt_store_dw(rq, tl->hwsp_offset, seqno[0]);
696 		if (err) {
697 			i915_request_add(rq);
698 			goto out;
699 		}
700 		hwsp_seqno[0] = tl->hwsp_seqno;
701 
702 		mutex_lock_nested(&tl->mutex, SINGLE_DEPTH_NESTING);
703 		err = intel_timeline_get_seqno(tl, rq, &seqno[1]);
704 		mutex_unlock(&tl->mutex);
705 		if (err) {
706 			i915_request_add(rq);
707 			goto out;
708 		}
709 		pr_debug("seqno[1]:%08x, hwsp_offset:%08x\n",
710 			 seqno[1], tl->hwsp_offset);
711 
712 		err = emit_ggtt_store_dw(rq, tl->hwsp_offset, seqno[1]);
713 		if (err) {
714 			i915_request_add(rq);
715 			goto out;
716 		}
717 		hwsp_seqno[1] = tl->hwsp_seqno;
718 
719 		/* With wrap should come a new hwsp */
720 		GEM_BUG_ON(seqno[1] >= seqno[0]);
721 		GEM_BUG_ON(hwsp_seqno[0] == hwsp_seqno[1]);
722 
723 		i915_request_add(rq);
724 
725 		if (i915_request_wait(rq, 0, HZ / 5) < 0) {
726 			pr_err("Wait for timeline writes timed out!\n");
727 			err = -EIO;
728 			goto out;
729 		}
730 
731 		if (*hwsp_seqno[0] != seqno[0] || *hwsp_seqno[1] != seqno[1]) {
732 			pr_err("Bad timeline values: found (%x, %x), expected (%x, %x)\n",
733 			       *hwsp_seqno[0], *hwsp_seqno[1],
734 			       seqno[0], seqno[1]);
735 			err = -EINVAL;
736 			goto out;
737 		}
738 
739 		intel_gt_retire_requests(gt); /* recycle HWSP */
740 	}
741 
742 out:
743 	if (igt_flush_test(i915))
744 		err = -EIO;
745 
746 	intel_timeline_unpin(tl);
747 out_free:
748 	intel_timeline_put(tl);
749 	return err;
750 }
751 
752 static int live_hwsp_recycle(void *arg)
753 {
754 	struct drm_i915_private *i915 = arg;
755 	struct intel_engine_cs *engine;
756 	enum intel_engine_id id;
757 	unsigned long count;
758 	int err = 0;
759 
760 	/*
761 	 * Check seqno writes into one timeline at a time. We expect to
762 	 * recycle the breadcrumb slot between iterations and neither
763 	 * want to confuse ourselves or the GPU.
764 	 */
765 
766 	count = 0;
767 	for_each_engine(engine, i915, id) {
768 		IGT_TIMEOUT(end_time);
769 
770 		if (!intel_engine_can_store_dword(engine))
771 			continue;
772 
773 		intel_engine_pm_get(engine);
774 
775 		do {
776 			struct intel_timeline *tl;
777 			struct i915_request *rq;
778 
779 			tl = checked_intel_timeline_create(i915);
780 			if (IS_ERR(tl)) {
781 				err = PTR_ERR(tl);
782 				break;
783 			}
784 
785 			rq = tl_write(tl, engine, count);
786 			if (IS_ERR(rq)) {
787 				intel_timeline_put(tl);
788 				err = PTR_ERR(rq);
789 				break;
790 			}
791 
792 			if (i915_request_wait(rq, 0, HZ / 5) < 0) {
793 				pr_err("Wait for timeline writes timed out!\n");
794 				i915_request_put(rq);
795 				intel_timeline_put(tl);
796 				err = -EIO;
797 				break;
798 			}
799 
800 			if (*tl->hwsp_seqno != count) {
801 				pr_err("Invalid seqno stored in timeline %lu, found 0x%x\n",
802 				       count, *tl->hwsp_seqno);
803 				err = -EINVAL;
804 			}
805 
806 			i915_request_put(rq);
807 			intel_timeline_put(tl);
808 			count++;
809 
810 			if (err)
811 				break;
812 		} while (!__igt_timeout(end_time, NULL));
813 
814 		intel_engine_pm_put(engine);
815 		if (err)
816 			break;
817 	}
818 
819 	return err;
820 }
821 
822 int intel_timeline_live_selftests(struct drm_i915_private *i915)
823 {
824 	static const struct i915_subtest tests[] = {
825 		SUBTEST(live_hwsp_recycle),
826 		SUBTEST(live_hwsp_engine),
827 		SUBTEST(live_hwsp_alternate),
828 		SUBTEST(live_hwsp_wrap),
829 	};
830 
831 	if (intel_gt_is_wedged(&i915->gt))
832 		return 0;
833 
834 	return i915_live_subtests(tests, i915);
835 }
836