xref: /openbmc/linux/drivers/gpu/drm/i915/selftests/i915_active.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
164d6c500SChris Wilson /*
264d6c500SChris Wilson  * SPDX-License-Identifier: MIT
364d6c500SChris Wilson  *
464d6c500SChris Wilson  * Copyright © 2018 Intel Corporation
564d6c500SChris Wilson  */
664d6c500SChris Wilson 
712c255b5SChris Wilson #include <linux/kref.h>
8*01fabda8SLucas De Marchi #include <linux/string_helpers.h>
912c255b5SChris Wilson 
1010be98a7SChris Wilson #include "gem/i915_gem_pm.h"
11cb823ed9SChris Wilson #include "gt/intel_gt.h"
1210be98a7SChris Wilson 
1310be98a7SChris Wilson #include "i915_selftest.h"
1464d6c500SChris Wilson 
1564d6c500SChris Wilson #include "igt_flush_test.h"
1664d6c500SChris Wilson #include "lib_sw_fence.h"
1764d6c500SChris Wilson 
1864d6c500SChris Wilson struct live_active {
1964d6c500SChris Wilson 	struct i915_active base;
2012c255b5SChris Wilson 	struct kref ref;
2164d6c500SChris Wilson 	bool retired;
2264d6c500SChris Wilson };
2364d6c500SChris Wilson 
__live_get(struct live_active * active)2412c255b5SChris Wilson static void __live_get(struct live_active *active)
2512c255b5SChris Wilson {
2612c255b5SChris Wilson 	kref_get(&active->ref);
2712c255b5SChris Wilson }
2812c255b5SChris Wilson 
__live_free(struct live_active * active)295361db1aSChris Wilson static void __live_free(struct live_active *active)
305361db1aSChris Wilson {
315361db1aSChris Wilson 	i915_active_fini(&active->base);
325361db1aSChris Wilson 	kfree(active);
335361db1aSChris Wilson }
345361db1aSChris Wilson 
__live_release(struct kref * ref)3512c255b5SChris Wilson static void __live_release(struct kref *ref)
3612c255b5SChris Wilson {
3712c255b5SChris Wilson 	struct live_active *active = container_of(ref, typeof(*active), ref);
3812c255b5SChris Wilson 
3912c255b5SChris Wilson 	__live_free(active);
4012c255b5SChris Wilson }
4112c255b5SChris Wilson 
__live_put(struct live_active * active)4212c255b5SChris Wilson static void __live_put(struct live_active *active)
4312c255b5SChris Wilson {
4412c255b5SChris Wilson 	kref_put(&active->ref, __live_release);
4512c255b5SChris Wilson }
4612c255b5SChris Wilson 
__live_active(struct i915_active * base)4712c255b5SChris Wilson static int __live_active(struct i915_active *base)
4812c255b5SChris Wilson {
4912c255b5SChris Wilson 	struct live_active *active = container_of(base, typeof(*active), base);
5012c255b5SChris Wilson 
5112c255b5SChris Wilson 	__live_get(active);
5212c255b5SChris Wilson 	return 0;
5312c255b5SChris Wilson }
5412c255b5SChris Wilson 
__live_retire(struct i915_active * base)55c3b14760SMatthew Auld static void __live_retire(struct i915_active *base)
5664d6c500SChris Wilson {
5764d6c500SChris Wilson 	struct live_active *active = container_of(base, typeof(*active), base);
5864d6c500SChris Wilson 
5964d6c500SChris Wilson 	active->retired = true;
6012c255b5SChris Wilson 	__live_put(active);
6164d6c500SChris Wilson }
6264d6c500SChris Wilson 
__live_alloc(struct drm_i915_private * i915)635361db1aSChris Wilson static struct live_active *__live_alloc(struct drm_i915_private *i915)
645361db1aSChris Wilson {
655361db1aSChris Wilson 	struct live_active *active;
665361db1aSChris Wilson 
675361db1aSChris Wilson 	active = kzalloc(sizeof(*active), GFP_KERNEL);
685361db1aSChris Wilson 	if (!active)
695361db1aSChris Wilson 		return NULL;
705361db1aSChris Wilson 
7112c255b5SChris Wilson 	kref_init(&active->ref);
72c3b14760SMatthew Auld 	i915_active_init(&active->base, __live_active, __live_retire, 0);
735361db1aSChris Wilson 
745361db1aSChris Wilson 	return active;
755361db1aSChris Wilson }
765361db1aSChris Wilson 
775361db1aSChris Wilson static struct live_active *
__live_active_setup(struct drm_i915_private * i915)785361db1aSChris Wilson __live_active_setup(struct drm_i915_private *i915)
7964d6c500SChris Wilson {
8064d6c500SChris Wilson 	struct intel_engine_cs *engine;
8164d6c500SChris Wilson 	struct i915_sw_fence *submit;
825361db1aSChris Wilson 	struct live_active *active;
8364d6c500SChris Wilson 	unsigned int count = 0;
8464d6c500SChris Wilson 	int err = 0;
8564d6c500SChris Wilson 
865361db1aSChris Wilson 	active = __live_alloc(i915);
875361db1aSChris Wilson 	if (!active)
885361db1aSChris Wilson 		return ERR_PTR(-ENOMEM);
8964d6c500SChris Wilson 
905361db1aSChris Wilson 	submit = heap_fence_create(GFP_KERNEL);
915361db1aSChris Wilson 	if (!submit) {
925361db1aSChris Wilson 		kfree(active);
935361db1aSChris Wilson 		return ERR_PTR(-ENOMEM);
945361db1aSChris Wilson 	}
9564d6c500SChris Wilson 
9612c255b5SChris Wilson 	err = i915_active_acquire(&active->base);
9712c255b5SChris Wilson 	if (err)
9864d6c500SChris Wilson 		goto out;
9964d6c500SChris Wilson 
100928da10cSChris Wilson 	for_each_uabi_engine(engine, i915) {
10164d6c500SChris Wilson 		struct i915_request *rq;
10264d6c500SChris Wilson 
103de5825beSChris Wilson 		rq = intel_engine_create_kernel_request(engine);
10464d6c500SChris Wilson 		if (IS_ERR(rq)) {
10564d6c500SChris Wilson 			err = PTR_ERR(rq);
10664d6c500SChris Wilson 			break;
10764d6c500SChris Wilson 		}
10864d6c500SChris Wilson 
10964d6c500SChris Wilson 		err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
11064d6c500SChris Wilson 						       submit,
11164d6c500SChris Wilson 						       GFP_KERNEL);
11264d6c500SChris Wilson 		if (err >= 0)
113d19d71fcSChris Wilson 			err = i915_active_add_request(&active->base, rq);
11464d6c500SChris Wilson 		i915_request_add(rq);
11564d6c500SChris Wilson 		if (err) {
11664d6c500SChris Wilson 			pr_err("Failed to track active ref!\n");
11764d6c500SChris Wilson 			break;
11864d6c500SChris Wilson 		}
11964d6c500SChris Wilson 
12064d6c500SChris Wilson 		count++;
12164d6c500SChris Wilson 	}
12264d6c500SChris Wilson 
12364d6c500SChris Wilson 	i915_active_release(&active->base);
124274cbf20SChris Wilson 	if (READ_ONCE(active->retired) && count) {
12564d6c500SChris Wilson 		pr_err("i915_active retired before submission!\n");
12664d6c500SChris Wilson 		err = -EINVAL;
12764d6c500SChris Wilson 	}
12812c255b5SChris Wilson 	if (atomic_read(&active->base.count) != count) {
12964d6c500SChris Wilson 		pr_err("i915_active not tracking all requests, found %d, expected %d\n",
13012c255b5SChris Wilson 		       atomic_read(&active->base.count), count);
13164d6c500SChris Wilson 		err = -EINVAL;
13264d6c500SChris Wilson 	}
13364d6c500SChris Wilson 
13464d6c500SChris Wilson out:
13564d6c500SChris Wilson 	i915_sw_fence_commit(submit);
13664d6c500SChris Wilson 	heap_fence_put(submit);
13712c255b5SChris Wilson 	if (err) {
13812c255b5SChris Wilson 		__live_put(active);
13912c255b5SChris Wilson 		active = ERR_PTR(err);
14012c255b5SChris Wilson 	}
14164d6c500SChris Wilson 
14212c255b5SChris Wilson 	return active;
14364d6c500SChris Wilson }
14464d6c500SChris Wilson 
live_active_wait(void * arg)14564d6c500SChris Wilson static int live_active_wait(void *arg)
14664d6c500SChris Wilson {
14764d6c500SChris Wilson 	struct drm_i915_private *i915 = arg;
1485361db1aSChris Wilson 	struct live_active *active;
1495361db1aSChris Wilson 	int err = 0;
15064d6c500SChris Wilson 
15164d6c500SChris Wilson 	/* Check that we get a callback when requests retire upon waiting */
15264d6c500SChris Wilson 
1535361db1aSChris Wilson 	active = __live_active_setup(i915);
154b1e3177bSChris Wilson 	if (IS_ERR(active))
155b1e3177bSChris Wilson 		return PTR_ERR(active);
15664d6c500SChris Wilson 
157d75a92a8SChris Wilson 	__i915_active_wait(&active->base, TASK_UNINTERRUPTIBLE);
158274cbf20SChris Wilson 	if (!READ_ONCE(active->retired)) {
1595de34ed1SChris Wilson 		struct drm_printer p = drm_err_printer(__func__);
1605de34ed1SChris Wilson 
16164d6c500SChris Wilson 		pr_err("i915_active not retired after waiting!\n");
1625de34ed1SChris Wilson 		i915_active_print(&active->base, &p);
1635de34ed1SChris Wilson 
16464d6c500SChris Wilson 		err = -EINVAL;
16564d6c500SChris Wilson 	}
16664d6c500SChris Wilson 
16712c255b5SChris Wilson 	__live_put(active);
1685361db1aSChris Wilson 
1697e805762SChris Wilson 	if (igt_flush_test(i915))
17064d6c500SChris Wilson 		err = -EIO;
1715361db1aSChris Wilson 
17264d6c500SChris Wilson 	return err;
17364d6c500SChris Wilson }
17464d6c500SChris Wilson 
live_active_retire(void * arg)17564d6c500SChris Wilson static int live_active_retire(void *arg)
17664d6c500SChris Wilson {
17764d6c500SChris Wilson 	struct drm_i915_private *i915 = arg;
1785361db1aSChris Wilson 	struct live_active *active;
1795361db1aSChris Wilson 	int err = 0;
18064d6c500SChris Wilson 
18164d6c500SChris Wilson 	/* Check that we get a callback when requests are indirectly retired */
18264d6c500SChris Wilson 
1835361db1aSChris Wilson 	active = __live_active_setup(i915);
184b1e3177bSChris Wilson 	if (IS_ERR(active))
185b1e3177bSChris Wilson 		return PTR_ERR(active);
18664d6c500SChris Wilson 
18764d6c500SChris Wilson 	/* waits for & retires all requests */
1887e805762SChris Wilson 	if (igt_flush_test(i915))
18964d6c500SChris Wilson 		err = -EIO;
19064d6c500SChris Wilson 
191274cbf20SChris Wilson 	if (!READ_ONCE(active->retired)) {
1925de34ed1SChris Wilson 		struct drm_printer p = drm_err_printer(__func__);
1935de34ed1SChris Wilson 
19464d6c500SChris Wilson 		pr_err("i915_active not retired after flushing!\n");
1955de34ed1SChris Wilson 		i915_active_print(&active->base, &p);
1965de34ed1SChris Wilson 
19764d6c500SChris Wilson 		err = -EINVAL;
19864d6c500SChris Wilson 	}
19964d6c500SChris Wilson 
20012c255b5SChris Wilson 	__live_put(active);
2015361db1aSChris Wilson 
20264d6c500SChris Wilson 	return err;
20364d6c500SChris Wilson }
20464d6c500SChris Wilson 
live_active_barrier(void * arg)205d13a3177SChris Wilson static int live_active_barrier(void *arg)
206d13a3177SChris Wilson {
207d13a3177SChris Wilson 	struct drm_i915_private *i915 = arg;
208d13a3177SChris Wilson 	struct intel_engine_cs *engine;
209d13a3177SChris Wilson 	struct live_active *active;
210d13a3177SChris Wilson 	int err = 0;
211d13a3177SChris Wilson 
212d13a3177SChris Wilson 	/* Check that we get a callback when requests retire upon waiting */
213d13a3177SChris Wilson 
214d13a3177SChris Wilson 	active = __live_alloc(i915);
215d13a3177SChris Wilson 	if (!active)
216d13a3177SChris Wilson 		return -ENOMEM;
217d13a3177SChris Wilson 
218d13a3177SChris Wilson 	err = i915_active_acquire(&active->base);
219d13a3177SChris Wilson 	if (err)
220d13a3177SChris Wilson 		goto out;
221d13a3177SChris Wilson 
222d13a3177SChris Wilson 	for_each_uabi_engine(engine, i915) {
223d13a3177SChris Wilson 		err = i915_active_acquire_preallocate_barrier(&active->base,
224d13a3177SChris Wilson 							      engine);
225d13a3177SChris Wilson 		if (err)
226d13a3177SChris Wilson 			break;
227d13a3177SChris Wilson 
228d13a3177SChris Wilson 		i915_active_acquire_barrier(&active->base);
229d13a3177SChris Wilson 	}
230d13a3177SChris Wilson 
231d13a3177SChris Wilson 	i915_active_release(&active->base);
232d75a92a8SChris Wilson 	if (err)
233d75a92a8SChris Wilson 		goto out;
234d13a3177SChris Wilson 
235d75a92a8SChris Wilson 	__i915_active_wait(&active->base, TASK_UNINTERRUPTIBLE);
236d75a92a8SChris Wilson 	if (!READ_ONCE(active->retired)) {
237d13a3177SChris Wilson 		pr_err("i915_active not retired after flushing barriers!\n");
238d13a3177SChris Wilson 		err = -EINVAL;
239d13a3177SChris Wilson 	}
240d13a3177SChris Wilson 
241d13a3177SChris Wilson out:
242d13a3177SChris Wilson 	__live_put(active);
243d13a3177SChris Wilson 
244d13a3177SChris Wilson 	if (igt_flush_test(i915))
245d13a3177SChris Wilson 		err = -EIO;
246d13a3177SChris Wilson 
247d13a3177SChris Wilson 	return err;
248d13a3177SChris Wilson }
249d13a3177SChris Wilson 
i915_active_live_selftests(struct drm_i915_private * i915)25064d6c500SChris Wilson int i915_active_live_selftests(struct drm_i915_private *i915)
25164d6c500SChris Wilson {
25264d6c500SChris Wilson 	static const struct i915_subtest tests[] = {
25364d6c500SChris Wilson 		SUBTEST(live_active_wait),
25464d6c500SChris Wilson 		SUBTEST(live_active_retire),
255d13a3177SChris Wilson 		SUBTEST(live_active_barrier),
25664d6c500SChris Wilson 	};
25764d6c500SChris Wilson 
2588c2699faSAndi Shyti 	if (intel_gt_is_wedged(to_gt(i915)))
25964d6c500SChris Wilson 		return 0;
26064d6c500SChris Wilson 
26164d6c500SChris Wilson 	return i915_subtests(tests, i915);
26264d6c500SChris Wilson }
263164a4128SChris Wilson 
node_to_barrier(struct active_node * it)264164a4128SChris Wilson static struct intel_engine_cs *node_to_barrier(struct active_node *it)
265164a4128SChris Wilson {
266164a4128SChris Wilson 	struct intel_engine_cs *engine;
267164a4128SChris Wilson 
268164a4128SChris Wilson 	if (!is_barrier(&it->base))
269164a4128SChris Wilson 		return NULL;
270164a4128SChris Wilson 
271164a4128SChris Wilson 	engine = __barrier_to_engine(it);
272164a4128SChris Wilson 	smp_rmb(); /* serialise with add_active_barriers */
273164a4128SChris Wilson 	if (!is_barrier(&it->base))
274164a4128SChris Wilson 		return NULL;
275164a4128SChris Wilson 
276164a4128SChris Wilson 	return engine;
277164a4128SChris Wilson }
278164a4128SChris Wilson 
i915_active_print(struct i915_active * ref,struct drm_printer * m)279164a4128SChris Wilson void i915_active_print(struct i915_active *ref, struct drm_printer *m)
280164a4128SChris Wilson {
2812386b492SChris Wilson 	drm_printf(m, "active %ps:%ps\n", ref->active, ref->retire);
282164a4128SChris Wilson 	drm_printf(m, "\tcount: %d\n", atomic_read(&ref->count));
283164a4128SChris Wilson 	drm_printf(m, "\tpreallocated barriers? %s\n",
284*01fabda8SLucas De Marchi 		   str_yes_no(!llist_empty(&ref->preallocated_barriers)));
285164a4128SChris Wilson 
286164a4128SChris Wilson 	if (i915_active_acquire_if_busy(ref)) {
287164a4128SChris Wilson 		struct active_node *it, *n;
288164a4128SChris Wilson 
289164a4128SChris Wilson 		rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) {
290164a4128SChris Wilson 			struct intel_engine_cs *engine;
291164a4128SChris Wilson 
292164a4128SChris Wilson 			engine = node_to_barrier(it);
293164a4128SChris Wilson 			if (engine) {
294164a4128SChris Wilson 				drm_printf(m, "\tbarrier: %s\n", engine->name);
295164a4128SChris Wilson 				continue;
296164a4128SChris Wilson 			}
297164a4128SChris Wilson 
298164a4128SChris Wilson 			if (i915_active_fence_isset(&it->base)) {
299164a4128SChris Wilson 				drm_printf(m,
300164a4128SChris Wilson 					   "\ttimeline: %llx\n", it->timeline);
301164a4128SChris Wilson 				continue;
302164a4128SChris Wilson 			}
303164a4128SChris Wilson 		}
304164a4128SChris Wilson 
305164a4128SChris Wilson 		i915_active_release(ref);
306164a4128SChris Wilson 	}
307164a4128SChris Wilson }
30838813767SChris Wilson 
spin_unlock_wait(spinlock_t * lock)30938813767SChris Wilson static void spin_unlock_wait(spinlock_t *lock)
31038813767SChris Wilson {
31138813767SChris Wilson 	spin_lock_irq(lock);
31238813767SChris Wilson 	spin_unlock_irq(lock);
31338813767SChris Wilson }
31438813767SChris Wilson 
active_flush(struct i915_active * ref,struct i915_active_fence * active)315e3e7aeecSChris Wilson static void active_flush(struct i915_active *ref,
316e3e7aeecSChris Wilson 			 struct i915_active_fence *active)
317e3e7aeecSChris Wilson {
318e3e7aeecSChris Wilson 	struct dma_fence *fence;
319e3e7aeecSChris Wilson 
320e3e7aeecSChris Wilson 	fence = xchg(__active_fence_slot(active), NULL);
321e3e7aeecSChris Wilson 	if (!fence)
322e3e7aeecSChris Wilson 		return;
323e3e7aeecSChris Wilson 
324e3e7aeecSChris Wilson 	spin_lock_irq(fence->lock);
325e3e7aeecSChris Wilson 	__list_del_entry(&active->cb.node);
326e3e7aeecSChris Wilson 	spin_unlock_irq(fence->lock); /* serialise with fence->cb_list */
327e3e7aeecSChris Wilson 	atomic_dec(&ref->count);
328e3e7aeecSChris Wilson 
329e3e7aeecSChris Wilson 	GEM_BUG_ON(!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags));
330e3e7aeecSChris Wilson }
331e3e7aeecSChris Wilson 
i915_active_unlock_wait(struct i915_active * ref)33238813767SChris Wilson void i915_active_unlock_wait(struct i915_active *ref)
33338813767SChris Wilson {
33438813767SChris Wilson 	if (i915_active_acquire_if_busy(ref)) {
33538813767SChris Wilson 		struct active_node *it, *n;
33638813767SChris Wilson 
33738813767SChris Wilson 		/* Wait for all active callbacks */
338e3e7aeecSChris Wilson 		rcu_read_lock();
339e3e7aeecSChris Wilson 		active_flush(ref, &ref->excl);
340e3e7aeecSChris Wilson 		rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node)
341e3e7aeecSChris Wilson 			active_flush(ref, &it->base);
34238813767SChris Wilson 		rcu_read_unlock();
34338813767SChris Wilson 
34438813767SChris Wilson 		i915_active_release(ref);
34538813767SChris Wilson 	}
34638813767SChris Wilson 
34738813767SChris Wilson 	/* And wait for the retire callback */
348950da301SChris Wilson 	spin_unlock_wait(&ref->tree_lock);
34938813767SChris Wilson 
35038813767SChris Wilson 	/* ... which may have been on a thread instead */
35138813767SChris Wilson 	flush_work(&ref->work);
35238813767SChris Wilson }
353