Home | History | Annotate | Line # | Download | only in selftests
      1  1.1  riastrad /*	$NetBSD: i915_active.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $	*/
      2  1.1  riastrad 
      3  1.1  riastrad /*
      4  1.1  riastrad  * SPDX-License-Identifier: MIT
      5  1.1  riastrad  *
      6  1.1  riastrad  * Copyright  2018 Intel Corporation
      7  1.1  riastrad  */
      8  1.1  riastrad 
      9  1.1  riastrad #include <sys/cdefs.h>
     10  1.1  riastrad __KERNEL_RCSID(0, "$NetBSD: i915_active.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $");
     11  1.1  riastrad 
     12  1.1  riastrad #include <linux/kref.h>
     13  1.1  riastrad 
     14  1.1  riastrad #include "gem/i915_gem_pm.h"
     15  1.1  riastrad #include "gt/intel_gt.h"
     16  1.1  riastrad 
     17  1.1  riastrad #include "i915_selftest.h"
     18  1.1  riastrad 
     19  1.1  riastrad #include "igt_flush_test.h"
     20  1.1  riastrad #include "lib_sw_fence.h"
     21  1.1  riastrad 
     22  1.1  riastrad struct live_active {
     23  1.1  riastrad 	struct i915_active base;
     24  1.1  riastrad 	struct kref ref;
     25  1.1  riastrad 	bool retired;
     26  1.1  riastrad };
     27  1.1  riastrad 
     28  1.1  riastrad static void __live_get(struct live_active *active)
     29  1.1  riastrad {
     30  1.1  riastrad 	kref_get(&active->ref);
     31  1.1  riastrad }
     32  1.1  riastrad 
     33  1.1  riastrad static void __live_free(struct live_active *active)
     34  1.1  riastrad {
     35  1.1  riastrad 	i915_active_fini(&active->base);
     36  1.1  riastrad 	kfree(active);
     37  1.1  riastrad }
     38  1.1  riastrad 
     39  1.1  riastrad static void __live_release(struct kref *ref)
     40  1.1  riastrad {
     41  1.1  riastrad 	struct live_active *active = container_of(ref, typeof(*active), ref);
     42  1.1  riastrad 
     43  1.1  riastrad 	__live_free(active);
     44  1.1  riastrad }
     45  1.1  riastrad 
     46  1.1  riastrad static void __live_put(struct live_active *active)
     47  1.1  riastrad {
     48  1.1  riastrad 	kref_put(&active->ref, __live_release);
     49  1.1  riastrad }
     50  1.1  riastrad 
     51  1.1  riastrad static int __live_active(struct i915_active *base)
     52  1.1  riastrad {
     53  1.1  riastrad 	struct live_active *active = container_of(base, typeof(*active), base);
     54  1.1  riastrad 
     55  1.1  riastrad 	__live_get(active);
     56  1.1  riastrad 	return 0;
     57  1.1  riastrad }
     58  1.1  riastrad 
     59  1.1  riastrad static void __live_retire(struct i915_active *base)
     60  1.1  riastrad {
     61  1.1  riastrad 	struct live_active *active = container_of(base, typeof(*active), base);
     62  1.1  riastrad 
     63  1.1  riastrad 	active->retired = true;
     64  1.1  riastrad 	__live_put(active);
     65  1.1  riastrad }
     66  1.1  riastrad 
     67  1.1  riastrad static struct live_active *__live_alloc(struct drm_i915_private *i915)
     68  1.1  riastrad {
     69  1.1  riastrad 	struct live_active *active;
     70  1.1  riastrad 
     71  1.1  riastrad 	active = kzalloc(sizeof(*active), GFP_KERNEL);
     72  1.1  riastrad 	if (!active)
     73  1.1  riastrad 		return NULL;
     74  1.1  riastrad 
     75  1.1  riastrad 	kref_init(&active->ref);
     76  1.1  riastrad 	i915_active_init(&active->base, __live_active, __live_retire);
     77  1.1  riastrad 
     78  1.1  riastrad 	return active;
     79  1.1  riastrad }
     80  1.1  riastrad 
     81  1.1  riastrad static struct live_active *
     82  1.1  riastrad __live_active_setup(struct drm_i915_private *i915)
     83  1.1  riastrad {
     84  1.1  riastrad 	struct intel_engine_cs *engine;
     85  1.1  riastrad 	struct i915_sw_fence *submit;
     86  1.1  riastrad 	struct live_active *active;
     87  1.1  riastrad 	unsigned int count = 0;
     88  1.1  riastrad 	int err = 0;
     89  1.1  riastrad 
     90  1.1  riastrad 	active = __live_alloc(i915);
     91  1.1  riastrad 	if (!active)
     92  1.1  riastrad 		return ERR_PTR(-ENOMEM);
     93  1.1  riastrad 
     94  1.1  riastrad 	submit = heap_fence_create(GFP_KERNEL);
     95  1.1  riastrad 	if (!submit) {
     96  1.1  riastrad 		kfree(active);
     97  1.1  riastrad 		return ERR_PTR(-ENOMEM);
     98  1.1  riastrad 	}
     99  1.1  riastrad 
    100  1.1  riastrad 	err = i915_active_acquire(&active->base);
    101  1.1  riastrad 	if (err)
    102  1.1  riastrad 		goto out;
    103  1.1  riastrad 
    104  1.1  riastrad 	for_each_uabi_engine(engine, i915) {
    105  1.1  riastrad 		struct i915_request *rq;
    106  1.1  riastrad 
    107  1.1  riastrad 		rq = intel_engine_create_kernel_request(engine);
    108  1.1  riastrad 		if (IS_ERR(rq)) {
    109  1.1  riastrad 			err = PTR_ERR(rq);
    110  1.1  riastrad 			break;
    111  1.1  riastrad 		}
    112  1.1  riastrad 
    113  1.1  riastrad 		err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
    114  1.1  riastrad 						       submit,
    115  1.1  riastrad 						       GFP_KERNEL);
    116  1.1  riastrad 		if (err >= 0)
    117  1.1  riastrad 			err = i915_active_add_request(&active->base, rq);
    118  1.1  riastrad 		i915_request_add(rq);
    119  1.1  riastrad 		if (err) {
    120  1.1  riastrad 			pr_err("Failed to track active ref!\n");
    121  1.1  riastrad 			break;
    122  1.1  riastrad 		}
    123  1.1  riastrad 
    124  1.1  riastrad 		count++;
    125  1.1  riastrad 	}
    126  1.1  riastrad 
    127  1.1  riastrad 	i915_active_release(&active->base);
    128  1.1  riastrad 	if (READ_ONCE(active->retired) && count) {
    129  1.1  riastrad 		pr_err("i915_active retired before submission!\n");
    130  1.1  riastrad 		err = -EINVAL;
    131  1.1  riastrad 	}
    132  1.1  riastrad 	if (atomic_read(&active->base.count) != count) {
    133  1.1  riastrad 		pr_err("i915_active not tracking all requests, found %d, expected %d\n",
    134  1.1  riastrad 		       atomic_read(&active->base.count), count);
    135  1.1  riastrad 		err = -EINVAL;
    136  1.1  riastrad 	}
    137  1.1  riastrad 
    138  1.1  riastrad out:
    139  1.1  riastrad 	i915_sw_fence_commit(submit);
    140  1.1  riastrad 	heap_fence_put(submit);
    141  1.1  riastrad 	if (err) {
    142  1.1  riastrad 		__live_put(active);
    143  1.1  riastrad 		active = ERR_PTR(err);
    144  1.1  riastrad 	}
    145  1.1  riastrad 
    146  1.1  riastrad 	return active;
    147  1.1  riastrad }
    148  1.1  riastrad 
    149  1.1  riastrad static int live_active_wait(void *arg)
    150  1.1  riastrad {
    151  1.1  riastrad 	struct drm_i915_private *i915 = arg;
    152  1.1  riastrad 	struct live_active *active;
    153  1.1  riastrad 	int err = 0;
    154  1.1  riastrad 
    155  1.1  riastrad 	/* Check that we get a callback when requests retire upon waiting */
    156  1.1  riastrad 
    157  1.1  riastrad 	active = __live_active_setup(i915);
    158  1.1  riastrad 	if (IS_ERR(active))
    159  1.1  riastrad 		return PTR_ERR(active);
    160  1.1  riastrad 
    161  1.1  riastrad 	i915_active_wait(&active->base);
    162  1.1  riastrad 	if (!READ_ONCE(active->retired)) {
    163  1.1  riastrad 		struct drm_printer p = drm_err_printer(__func__);
    164  1.1  riastrad 
    165  1.1  riastrad 		pr_err("i915_active not retired after waiting!\n");
    166  1.1  riastrad 		i915_active_print(&active->base, &p);
    167  1.1  riastrad 
    168  1.1  riastrad 		err = -EINVAL;
    169  1.1  riastrad 	}
    170  1.1  riastrad 
    171  1.1  riastrad 	__live_put(active);
    172  1.1  riastrad 
    173  1.1  riastrad 	if (igt_flush_test(i915))
    174  1.1  riastrad 		err = -EIO;
    175  1.1  riastrad 
    176  1.1  riastrad 	return err;
    177  1.1  riastrad }
    178  1.1  riastrad 
    179  1.1  riastrad static int live_active_retire(void *arg)
    180  1.1  riastrad {
    181  1.1  riastrad 	struct drm_i915_private *i915 = arg;
    182  1.1  riastrad 	struct live_active *active;
    183  1.1  riastrad 	int err = 0;
    184  1.1  riastrad 
    185  1.1  riastrad 	/* Check that we get a callback when requests are indirectly retired */
    186  1.1  riastrad 
    187  1.1  riastrad 	active = __live_active_setup(i915);
    188  1.1  riastrad 	if (IS_ERR(active))
    189  1.1  riastrad 		return PTR_ERR(active);
    190  1.1  riastrad 
    191  1.1  riastrad 	/* waits for & retires all requests */
    192  1.1  riastrad 	if (igt_flush_test(i915))
    193  1.1  riastrad 		err = -EIO;
    194  1.1  riastrad 
    195  1.1  riastrad 	if (!READ_ONCE(active->retired)) {
    196  1.1  riastrad 		struct drm_printer p = drm_err_printer(__func__);
    197  1.1  riastrad 
    198  1.1  riastrad 		pr_err("i915_active not retired after flushing!\n");
    199  1.1  riastrad 		i915_active_print(&active->base, &p);
    200  1.1  riastrad 
    201  1.1  riastrad 		err = -EINVAL;
    202  1.1  riastrad 	}
    203  1.1  riastrad 
    204  1.1  riastrad 	__live_put(active);
    205  1.1  riastrad 
    206  1.1  riastrad 	return err;
    207  1.1  riastrad }
    208  1.1  riastrad 
    209  1.1  riastrad int i915_active_live_selftests(struct drm_i915_private *i915)
    210  1.1  riastrad {
    211  1.1  riastrad 	static const struct i915_subtest tests[] = {
    212  1.1  riastrad 		SUBTEST(live_active_wait),
    213  1.1  riastrad 		SUBTEST(live_active_retire),
    214  1.1  riastrad 	};
    215  1.1  riastrad 
    216  1.1  riastrad 	if (intel_gt_is_wedged(&i915->gt))
    217  1.1  riastrad 		return 0;
    218  1.1  riastrad 
    219  1.1  riastrad 	return i915_subtests(tests, i915);
    220  1.1  riastrad }
    221  1.1  riastrad 
    222  1.1  riastrad static struct intel_engine_cs *node_to_barrier(struct active_node *it)
    223  1.1  riastrad {
    224  1.1  riastrad 	struct intel_engine_cs *engine;
    225  1.1  riastrad 
    226  1.1  riastrad 	if (!is_barrier(&it->base))
    227  1.1  riastrad 		return NULL;
    228  1.1  riastrad 
    229  1.1  riastrad 	engine = __barrier_to_engine(it);
    230  1.1  riastrad 	smp_rmb(); /* serialise with add_active_barriers */
    231  1.1  riastrad 	if (!is_barrier(&it->base))
    232  1.1  riastrad 		return NULL;
    233  1.1  riastrad 
    234  1.1  riastrad 	return engine;
    235  1.1  riastrad }
    236  1.1  riastrad 
    237  1.1  riastrad void i915_active_print(struct i915_active *ref, struct drm_printer *m)
    238  1.1  riastrad {
    239  1.1  riastrad 	drm_printf(m, "active %pS:%pS\n", ref->active, ref->retire);
    240  1.1  riastrad 	drm_printf(m, "\tcount: %d\n", atomic_read(&ref->count));
    241  1.1  riastrad 	drm_printf(m, "\tpreallocated barriers? %s\n",
    242  1.1  riastrad 		   yesno(!llist_empty(&ref->preallocated_barriers)));
    243  1.1  riastrad 
    244  1.1  riastrad 	if (i915_active_acquire_if_busy(ref)) {
    245  1.1  riastrad 		struct active_node *it, *n;
    246  1.1  riastrad 
    247  1.1  riastrad 		rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) {
    248  1.1  riastrad 			struct intel_engine_cs *engine;
    249  1.1  riastrad 
    250  1.1  riastrad 			engine = node_to_barrier(it);
    251  1.1  riastrad 			if (engine) {
    252  1.1  riastrad 				drm_printf(m, "\tbarrier: %s\n", engine->name);
    253  1.1  riastrad 				continue;
    254  1.1  riastrad 			}
    255  1.1  riastrad 
    256  1.1  riastrad 			if (i915_active_fence_isset(&it->base)) {
    257  1.1  riastrad 				drm_printf(m,
    258  1.1  riastrad 					   "\ttimeline: %llx\n", it->timeline);
    259  1.1  riastrad 				continue;
    260  1.1  riastrad 			}
    261  1.1  riastrad 		}
    262  1.1  riastrad 
    263  1.1  riastrad 		i915_active_release(ref);
    264  1.1  riastrad 	}
    265  1.1  riastrad }
    266  1.1  riastrad 
    267  1.1  riastrad static void spin_unlock_wait(spinlock_t *lock)
    268  1.1  riastrad {
    269  1.1  riastrad 	spin_lock_irq(lock);
    270  1.1  riastrad 	spin_unlock_irq(lock);
    271  1.1  riastrad }
    272  1.1  riastrad 
    273  1.1  riastrad void i915_active_unlock_wait(struct i915_active *ref)
    274  1.1  riastrad {
    275  1.1  riastrad 	if (i915_active_acquire_if_busy(ref)) {
    276  1.1  riastrad 		struct active_node *it, *n;
    277  1.1  riastrad 
    278  1.1  riastrad 		rcu_read_lock();
    279  1.1  riastrad 		rbtree_postorder_for_each_entry_safe(it, n, &ref->tree, node) {
    280  1.1  riastrad 			struct dma_fence *f;
    281  1.1  riastrad 
    282  1.1  riastrad 			/* Wait for all active callbacks */
    283  1.1  riastrad 			f = rcu_dereference(it->base.fence);
    284  1.1  riastrad 			if (f)
    285  1.1  riastrad 				spin_unlock_wait(f->lock);
    286  1.1  riastrad 		}
    287  1.1  riastrad 		rcu_read_unlock();
    288  1.1  riastrad 
    289  1.1  riastrad 		i915_active_release(ref);
    290  1.1  riastrad 	}
    291  1.1  riastrad 
    292  1.1  riastrad 	/* And wait for the retire callback */
    293  1.1  riastrad 	spin_lock_irq(&ref->tree_lock);
    294  1.1  riastrad 	spin_unlock_irq(&ref->tree_lock);
    295  1.1  riastrad 
    296  1.1  riastrad 	/* ... which may have been on a thread instead */
    297  1.1  riastrad 	flush_work(&ref->work);
    298  1.1  riastrad }
    299