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