xref: /linux/drivers/gpu/drm/i915/selftests/i915_active.c (revision 1517d90cfafe0f95fd7863d04e1596f7beb7dfa8)
1 /*
2  * SPDX-License-Identifier: MIT
3  *
4  * Copyright © 2018 Intel Corporation
5  */
6 
7 #include <linux/kref.h>
8 
9 #include "gem/i915_gem_pm.h"
10 #include "gt/intel_gt.h"
11 
12 #include "i915_selftest.h"
13 
14 #include "igt_flush_test.h"
15 #include "lib_sw_fence.h"
16 
17 struct live_active {
18 	struct i915_active base;
19 	struct kref ref;
20 	bool retired;
21 };
22 
23 static void __live_get(struct live_active *active)
24 {
25 	kref_get(&active->ref);
26 }
27 
28 static void __live_free(struct live_active *active)
29 {
30 	i915_active_fini(&active->base);
31 	kfree(active);
32 }
33 
34 static void __live_release(struct kref *ref)
35 {
36 	struct live_active *active = container_of(ref, typeof(*active), ref);
37 
38 	__live_free(active);
39 }
40 
41 static void __live_put(struct live_active *active)
42 {
43 	kref_put(&active->ref, __live_release);
44 }
45 
46 static int __live_active(struct i915_active *base)
47 {
48 	struct live_active *active = container_of(base, typeof(*active), base);
49 
50 	__live_get(active);
51 	return 0;
52 }
53 
54 static void __live_retire(struct i915_active *base)
55 {
56 	struct live_active *active = container_of(base, typeof(*active), base);
57 
58 	active->retired = true;
59 	__live_put(active);
60 }
61 
62 static struct live_active *__live_alloc(struct drm_i915_private *i915)
63 {
64 	struct live_active *active;
65 
66 	active = kzalloc(sizeof(*active), GFP_KERNEL);
67 	if (!active)
68 		return NULL;
69 
70 	kref_init(&active->ref);
71 	i915_active_init(i915, &active->base, __live_active, __live_retire);
72 
73 	return active;
74 }
75 
76 static struct live_active *
77 __live_active_setup(struct drm_i915_private *i915)
78 {
79 	struct intel_engine_cs *engine;
80 	struct i915_sw_fence *submit;
81 	struct live_active *active;
82 	enum intel_engine_id id;
83 	unsigned int count = 0;
84 	int err = 0;
85 
86 	active = __live_alloc(i915);
87 	if (!active)
88 		return ERR_PTR(-ENOMEM);
89 
90 	submit = heap_fence_create(GFP_KERNEL);
91 	if (!submit) {
92 		kfree(active);
93 		return ERR_PTR(-ENOMEM);
94 	}
95 
96 	err = i915_active_acquire(&active->base);
97 	if (err)
98 		goto out;
99 
100 	for_each_engine(engine, i915, id) {
101 		struct i915_request *rq;
102 
103 		rq = i915_request_create(engine->kernel_context);
104 		if (IS_ERR(rq)) {
105 			err = PTR_ERR(rq);
106 			break;
107 		}
108 
109 		err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
110 						       submit,
111 						       GFP_KERNEL);
112 		if (err >= 0)
113 			err = i915_active_ref(&active->base, rq->timeline, rq);
114 		i915_request_add(rq);
115 		if (err) {
116 			pr_err("Failed to track active ref!\n");
117 			break;
118 		}
119 
120 		count++;
121 	}
122 
123 	i915_active_release(&active->base);
124 	if (active->retired && count) {
125 		pr_err("i915_active retired before submission!\n");
126 		err = -EINVAL;
127 	}
128 	if (atomic_read(&active->base.count) != count) {
129 		pr_err("i915_active not tracking all requests, found %d, expected %d\n",
130 		       atomic_read(&active->base.count), count);
131 		err = -EINVAL;
132 	}
133 
134 out:
135 	i915_sw_fence_commit(submit);
136 	heap_fence_put(submit);
137 	if (err) {
138 		__live_put(active);
139 		active = ERR_PTR(err);
140 	}
141 
142 	return active;
143 }
144 
145 static int live_active_wait(void *arg)
146 {
147 	struct drm_i915_private *i915 = arg;
148 	struct live_active *active;
149 	intel_wakeref_t wakeref;
150 	int err = 0;
151 
152 	/* Check that we get a callback when requests retire upon waiting */
153 
154 	mutex_lock(&i915->drm.struct_mutex);
155 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
156 
157 	active = __live_active_setup(i915);
158 	if (IS_ERR(active)) {
159 		err = PTR_ERR(active);
160 		goto err;
161 	}
162 
163 	i915_active_wait(&active->base);
164 	if (!active->retired) {
165 		pr_err("i915_active not retired after waiting!\n");
166 		err = -EINVAL;
167 	}
168 
169 	__live_put(active);
170 
171 	if (igt_flush_test(i915, I915_WAIT_LOCKED))
172 		err = -EIO;
173 
174 err:
175 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
176 	mutex_unlock(&i915->drm.struct_mutex);
177 
178 	return err;
179 }
180 
181 static int live_active_retire(void *arg)
182 {
183 	struct drm_i915_private *i915 = arg;
184 	struct live_active *active;
185 	intel_wakeref_t wakeref;
186 	int err = 0;
187 
188 	/* Check that we get a callback when requests are indirectly retired */
189 
190 	mutex_lock(&i915->drm.struct_mutex);
191 	wakeref = intel_runtime_pm_get(&i915->runtime_pm);
192 
193 	active = __live_active_setup(i915);
194 	if (IS_ERR(active)) {
195 		err = PTR_ERR(active);
196 		goto err;
197 	}
198 
199 	/* waits for & retires all requests */
200 	if (igt_flush_test(i915, I915_WAIT_LOCKED))
201 		err = -EIO;
202 
203 	if (!active->retired) {
204 		pr_err("i915_active not retired after flushing!\n");
205 		err = -EINVAL;
206 	}
207 
208 	__live_put(active);
209 
210 err:
211 	intel_runtime_pm_put(&i915->runtime_pm, wakeref);
212 	mutex_unlock(&i915->drm.struct_mutex);
213 
214 	return err;
215 }
216 
217 int i915_active_live_selftests(struct drm_i915_private *i915)
218 {
219 	static const struct i915_subtest tests[] = {
220 		SUBTEST(live_active_wait),
221 		SUBTEST(live_active_retire),
222 	};
223 
224 	if (intel_gt_is_wedged(&i915->gt))
225 		return 0;
226 
227 	return i915_subtests(tests, i915);
228 }
229