drm/i915: Move context management under GEM
[linux-block.git] / drivers / gpu / drm / i915 / gt / selftest_context.c
CommitLineData
d8af05ff
CW
1/*
2 * SPDX-License-Identifier: GPL-2.0
3 *
4 * Copyright © 2019 Intel Corporation
5 */
6
7#include "i915_selftest.h"
9559c875 8#include "intel_engine_pm.h"
d8af05ff
CW
9#include "intel_gt.h"
10
11#include "gem/selftests/mock_context.h"
12#include "selftests/igt_flush_test.h"
13#include "selftests/mock_drm.h"
14
15static int request_sync(struct i915_request *rq)
16{
d19d71fc 17 struct intel_timeline *tl = i915_request_timeline(rq);
d8af05ff
CW
18 long timeout;
19 int err = 0;
20
d19d71fc 21 intel_timeline_get(tl);
d8af05ff
CW
22 i915_request_get(rq);
23
d19d71fc
CW
24 /* Opencode i915_request_add() so we can keep the timeline locked. */
25 __i915_request_commit(rq);
26 __i915_request_queue(rq, NULL);
27
d8af05ff 28 timeout = i915_request_wait(rq, 0, HZ / 10);
d19d71fc 29 if (timeout < 0)
d8af05ff 30 err = timeout;
d19d71fc 31 else
d8af05ff 32 i915_request_retire_upto(rq);
d19d71fc
CW
33
34 lockdep_unpin_lock(&tl->mutex, rq->cookie);
35 mutex_unlock(&tl->mutex);
d8af05ff
CW
36
37 i915_request_put(rq);
d19d71fc 38 intel_timeline_put(tl);
d8af05ff
CW
39
40 return err;
41}
42
43static int context_sync(struct intel_context *ce)
44{
75d0a7f3 45 struct intel_timeline *tl = ce->timeline;
d8af05ff
CW
46 int err = 0;
47
e5dadff4 48 mutex_lock(&tl->mutex);
d8af05ff 49 do {
b1e3177b 50 struct dma_fence *fence;
d8af05ff
CW
51 long timeout;
52
b1e3177b
CW
53 fence = i915_active_fence_get(&tl->last_request);
54 if (!fence)
d8af05ff
CW
55 break;
56
b1e3177b 57 timeout = dma_fence_wait_timeout(fence, false, HZ / 10);
d8af05ff
CW
58 if (timeout < 0)
59 err = timeout;
60 else
b1e3177b 61 i915_request_retire_upto(to_request(fence));
d8af05ff 62
b1e3177b 63 dma_fence_put(fence);
d8af05ff 64 } while (!err);
e5dadff4 65 mutex_unlock(&tl->mutex);
d8af05ff
CW
66
67 return err;
68}
69
9559c875
CW
70static int __live_context_size(struct intel_engine_cs *engine,
71 struct i915_gem_context *fixme)
72{
73 struct intel_context *ce;
74 struct i915_request *rq;
75 void *vaddr;
76 int err;
77
78 ce = intel_context_create(fixme, engine);
79 if (IS_ERR(ce))
80 return PTR_ERR(ce);
81
82 err = intel_context_pin(ce);
83 if (err)
84 goto err;
85
86 vaddr = i915_gem_object_pin_map(ce->state->obj,
87 i915_coherent_map_type(engine->i915));
88 if (IS_ERR(vaddr)) {
89 err = PTR_ERR(vaddr);
90 intel_context_unpin(ce);
91 goto err;
92 }
93
94 /*
95 * Note that execlists also applies a redzone which it checks on
96 * context unpin when debugging. We are using the same location
97 * and same poison value so that our checks overlap. Despite the
98 * redundancy, we want to keep this little selftest so that we
99 * get coverage of any and all submission backends, and we can
100 * always extend this test to ensure we trick the HW into a
101 * compromising position wrt to the various sections that need
102 * to be written into the context state.
103 *
104 * TLDR; this overlaps with the execlists redzone.
105 */
106 if (HAS_EXECLISTS(engine->i915))
107 vaddr += LRC_HEADER_PAGES * PAGE_SIZE;
108
109 vaddr += engine->context_size - I915_GTT_PAGE_SIZE;
110 memset(vaddr, POISON_INUSE, I915_GTT_PAGE_SIZE);
111
112 rq = intel_context_create_request(ce);
113 intel_context_unpin(ce);
114 if (IS_ERR(rq)) {
115 err = PTR_ERR(rq);
116 goto err_unpin;
117 }
118
119 err = request_sync(rq);
120 if (err)
121 goto err_unpin;
122
123 /* Force the context switch */
124 rq = i915_request_create(engine->kernel_context);
125 if (IS_ERR(rq)) {
126 err = PTR_ERR(rq);
127 goto err_unpin;
128 }
129 err = request_sync(rq);
130 if (err)
131 goto err_unpin;
132
133 if (memchr_inv(vaddr, POISON_INUSE, I915_GTT_PAGE_SIZE)) {
134 pr_err("%s context overwrote trailing red-zone!", engine->name);
135 err = -EINVAL;
136 }
137
138err_unpin:
139 i915_gem_object_unpin_map(ce->state->obj);
140err:
141 intel_context_put(ce);
142 return err;
143}
144
145static int live_context_size(void *arg)
146{
147 struct intel_gt *gt = arg;
148 struct intel_engine_cs *engine;
149 struct i915_gem_context *fixme;
150 enum intel_engine_id id;
151 int err = 0;
152
153 /*
154 * Check that our context sizes are correct by seeing if the
155 * HW tries to write past the end of one.
156 */
157
9559c875 158 fixme = kernel_context(gt->i915);
a4e7ccda
CW
159 if (IS_ERR(fixme))
160 return PTR_ERR(fixme);
9559c875
CW
161
162 for_each_engine(engine, gt->i915, id) {
163 struct {
164 struct drm_i915_gem_object *state;
165 void *pinned;
166 } saved;
167
168 if (!engine->context_size)
169 continue;
170
171 intel_engine_pm_get(engine);
172
173 /*
174 * Hide the old default state -- we lie about the context size
175 * and get confused when the default state is smaller than
176 * expected. For our do nothing request, inheriting the
177 * active state is sufficient, we are only checking that we
178 * don't use more than we planned.
179 */
180 saved.state = fetch_and_zero(&engine->default_state);
181 saved.pinned = fetch_and_zero(&engine->pinned_default_state);
182
183 /* Overlaps with the execlists redzone */
184 engine->context_size += I915_GTT_PAGE_SIZE;
185
186 err = __live_context_size(engine, fixme);
187
188 engine->context_size -= I915_GTT_PAGE_SIZE;
189
190 engine->pinned_default_state = saved.pinned;
191 engine->default_state = saved.state;
192
193 intel_engine_pm_put(engine);
194
195 if (err)
196 break;
197 }
198
199 kernel_context_close(fixme);
9559c875
CW
200 return err;
201}
202
d8af05ff
CW
203static int __live_active_context(struct intel_engine_cs *engine,
204 struct i915_gem_context *fixme)
205{
206 struct intel_context *ce;
207 int pass;
208 int err;
209
210 /*
211 * We keep active contexts alive until after a subsequent context
212 * switch as the final write from the context-save will be after
213 * we retire the final request. We track when we unpin the context,
214 * under the presumption that the final pin is from the last request,
215 * and instead of immediately unpinning the context, we add a task
216 * to unpin the context from the next idle-barrier.
217 *
218 * This test makes sure that the context is kept alive until a
219 * subsequent idle-barrier (emitted when the engine wakeref hits 0
220 * with no more outstanding requests).
221 */
222
223 if (intel_engine_pm_is_awake(engine)) {
224 pr_err("%s is awake before starting %s!\n",
225 engine->name, __func__);
226 return -EINVAL;
227 }
228
229 ce = intel_context_create(fixme, engine);
ed29da71
DC
230 if (IS_ERR(ce))
231 return PTR_ERR(ce);
d8af05ff
CW
232
233 for (pass = 0; pass <= 2; pass++) {
234 struct i915_request *rq;
235
236 rq = intel_context_create_request(ce);
237 if (IS_ERR(rq)) {
238 err = PTR_ERR(rq);
239 goto err;
240 }
241
242 err = request_sync(rq);
243 if (err)
244 goto err;
245
246 /* Context will be kept active until after an idle-barrier. */
247 if (i915_active_is_idle(&ce->active)) {
248 pr_err("context is not active; expected idle-barrier (%s pass %d)\n",
249 engine->name, pass);
250 err = -EINVAL;
251 goto err;
252 }
253
254 if (!intel_engine_pm_is_awake(engine)) {
255 pr_err("%s is asleep before idle-barrier\n",
256 engine->name);
257 err = -EINVAL;
258 goto err;
259 }
260 }
261
262 /* Now make sure our idle-barriers are flushed */
263 err = context_sync(engine->kernel_context);
264 if (err)
265 goto err;
266
267 if (!i915_active_is_idle(&ce->active)) {
268 pr_err("context is still active!");
269 err = -EINVAL;
270 }
271
272 if (intel_engine_pm_is_awake(engine)) {
273 struct drm_printer p = drm_debug_printer(__func__);
274
275 intel_engine_dump(engine, &p,
276 "%s is still awake after idle-barriers\n",
277 engine->name);
278 GEM_TRACE_DUMP();
279
280 err = -EINVAL;
281 goto err;
282 }
283
284err:
285 intel_context_put(ce);
286 return err;
287}
288
289static int live_active_context(void *arg)
290{
291 struct intel_gt *gt = arg;
292 struct intel_engine_cs *engine;
293 struct i915_gem_context *fixme;
294 enum intel_engine_id id;
295 struct drm_file *file;
296 int err = 0;
297
298 file = mock_file(gt->i915);
299 if (IS_ERR(file))
300 return PTR_ERR(file);
301
d8af05ff 302 fixme = live_context(gt->i915, file);
ed29da71
DC
303 if (IS_ERR(fixme)) {
304 err = PTR_ERR(fixme);
a4e7ccda 305 goto out_file;
d8af05ff
CW
306 }
307
308 for_each_engine(engine, gt->i915, id) {
309 err = __live_active_context(engine, fixme);
310 if (err)
311 break;
312
7e805762 313 err = igt_flush_test(gt->i915);
d8af05ff
CW
314 if (err)
315 break;
316 }
317
a4e7ccda 318out_file:
d8af05ff
CW
319 mock_file_free(gt->i915, file);
320 return err;
321}
322
323static int __remote_sync(struct intel_context *ce, struct intel_context *remote)
324{
325 struct i915_request *rq;
326 int err;
327
328 err = intel_context_pin(remote);
329 if (err)
330 return err;
331
332 rq = intel_context_create_request(ce);
333 if (IS_ERR(rq)) {
334 err = PTR_ERR(rq);
335 goto unpin;
336 }
337
338 err = intel_context_prepare_remote_request(remote, rq);
339 if (err) {
340 i915_request_add(rq);
341 goto unpin;
342 }
343
344 err = request_sync(rq);
345
346unpin:
347 intel_context_unpin(remote);
348 return err;
349}
350
351static int __live_remote_context(struct intel_engine_cs *engine,
352 struct i915_gem_context *fixme)
353{
354 struct intel_context *local, *remote;
355 int pass;
356 int err;
357
358 /*
359 * Check that our idle barriers do not interfere with normal
360 * activity tracking. In particular, check that operating
361 * on the context image remotely (intel_context_prepare_remote_request),
362 * which inserts foreign fences into intel_context.active, does not
363 * clobber the idle-barrier.
364 */
365
366 remote = intel_context_create(fixme, engine);
ed29da71
DC
367 if (IS_ERR(remote))
368 return PTR_ERR(remote);
d8af05ff
CW
369
370 local = intel_context_create(fixme, engine);
ed29da71
DC
371 if (IS_ERR(local)) {
372 err = PTR_ERR(local);
d8af05ff
CW
373 goto err_remote;
374 }
375
376 for (pass = 0; pass <= 2; pass++) {
377 err = __remote_sync(local, remote);
378 if (err)
379 break;
380
381 err = __remote_sync(engine->kernel_context, remote);
382 if (err)
383 break;
384
385 if (i915_active_is_idle(&remote->active)) {
386 pr_err("remote context is not active; expected idle-barrier (%s pass %d)\n",
387 engine->name, pass);
388 err = -EINVAL;
389 break;
390 }
391 }
392
393 intel_context_put(local);
394err_remote:
395 intel_context_put(remote);
396 return err;
397}
398
399static int live_remote_context(void *arg)
400{
401 struct intel_gt *gt = arg;
402 struct intel_engine_cs *engine;
403 struct i915_gem_context *fixme;
404 enum intel_engine_id id;
405 struct drm_file *file;
406 int err = 0;
407
408 file = mock_file(gt->i915);
409 if (IS_ERR(file))
410 return PTR_ERR(file);
411
d8af05ff 412 fixme = live_context(gt->i915, file);
ed29da71
DC
413 if (IS_ERR(fixme)) {
414 err = PTR_ERR(fixme);
a4e7ccda 415 goto out_file;
d8af05ff
CW
416 }
417
418 for_each_engine(engine, gt->i915, id) {
419 err = __live_remote_context(engine, fixme);
420 if (err)
421 break;
422
7e805762 423 err = igt_flush_test(gt->i915);
d8af05ff
CW
424 if (err)
425 break;
426 }
427
a4e7ccda 428out_file:
d8af05ff
CW
429 mock_file_free(gt->i915, file);
430 return err;
431}
432
433int intel_context_live_selftests(struct drm_i915_private *i915)
434{
435 static const struct i915_subtest tests[] = {
9559c875 436 SUBTEST(live_context_size),
d8af05ff
CW
437 SUBTEST(live_active_context),
438 SUBTEST(live_remote_context),
439 };
440 struct intel_gt *gt = &i915->gt;
441
442 if (intel_gt_is_wedged(gt))
443 return 0;
444
445 return intel_gt_live_subtests(tests, gt);
446}